Diferencia entre revisiones de «PDM Avanzado Captura de Vídeo / Imaxes»
| Línea 247: | Línea 247: | ||
'''Código da clase UD6_04_MultimediaFotoVideo'''<br/> | '''Código da clase UD6_04_MultimediaFotoVideo'''<br/> | ||
'''Obxectivo:''' Comprobar como capturar unha imaxe / vídeo e visualizala nun control ImageView / VideoView | '''Obxectivo:''' Comprobar como capturar unha imaxe / vídeo e visualizala nun control ImageView / VideoView | ||
| − | <syntaxhighlight lang="java" line enclose="div" highlight="38-39,42- | + | <syntaxhighlight lang="java" line enclose="div" highlight="38-39,42-46,72-73,77-78" > |
import android.app.Activity; | import android.app.Activity; | ||
import android.content.Intent; | import android.content.Intent; | ||
| Línea 290: | Línea 290: | ||
} else { // Saca vídeo | } else { // Saca vídeo | ||
VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo); | VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo); | ||
| + | MediaController mediaController = new MediaController(this); | ||
| + | vidview.setMediaController(mediaController); | ||
vidview.setVideoURI(data.getData()); | vidview.setVideoURI(data.getData()); | ||
vidview.start(); | vidview.start(); | ||
| Línea 370: | Línea 372: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | * Liñas 38-39: Nestas liñas obtemos a foto da aplicación do S.O. e a visualiza no ImageView. | + | * '''Liñas 38-39''': Nestas liñas obtemos a foto da aplicación do S.O. e a visualiza no ImageView. |
| − | * Liñas 42- | + | * '''Liñas 42-46''': Nestas liñas obtemos o vídeo do Intent e o cargamos no VideoView e comezamos a reprodución. |
| − | * Liñas | + | :* '''Liñas 43-45''': Creamos un MediaController asociado ao VideoView para que poidamos ter un control sobre o vídeo (reboninar, ir cara adiante, cara atrás,...) |
| − | * Liñas | + | * '''Liñas 72-73''': Evento click sobre o botón. Se está a opción do RadioButton de sacar unha foto lanzamos o Intent ACTION_IMAGE_CAPTURE, esperando o resultado. |
| + | * '''Liñas 77-78''': Evento click sobre o botón. Se está a opción do RadioButton de sacar un vídeo lanzamos o Intent ACTION_VIDEO_CAPTURE, esperando o resultado. | ||
==Gardando o Vídeo / Foto== | ==Gardando o Vídeo / Foto== | ||
Revisión del 22:06 30 oct 2018
Sumario
Introdución
As clases que interveñen na gravación son:
- Clase Camera: danos acceso á cámara, as súas características. Usarémola se facemos unha aplicación na que queiramos xestionar a cámara por nos mesmos.
- Clase SurfaceView: para previsualizar o que imos gravar.
- Clase MediaRecorder: permítenos gravar vídeo dende a cámara.
Para facer uso da cámara para gravar un vídeo podemos utilizar un Intent, evitándonos ter que deseñar a aplicación para xestionar a cámara.
Permisos necesarios a engadir no arquivo AndroidManifest.xml:
- Permiso de lectura sobre a tarxeta SD Externa (no caso de utilizar un dispositivo cunha API 23 ou superior).
1 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- Permiso para facer uso da cámara:
1 <uses-permission android:name="android.permission.CAMERA" />
Nota: Se usamos a opción de chamar á cámara cun Intent non necesitamos dito permiso.
- Permiso para indicar que a nosa aplicación fai uso da cámara:
1 <uses-feature android:name="android.hardware.camera" required="true"/>
Se queremos facer uso doutras ‘características’, tanto da cámara coma doutro hardware que ten o dispositivo móbil, consultar: http://developer.android.com/guide/topics/manifest/uses-feature-element.html#hw-features
Desta forma Google Play impedirá que se instale á aplicación se o dispositivo non ten o hardware necesario coas características especificadas.
Neste caso, a nosa aplicación está requirindo ó uso da cámara, pero pode ocorrer que non a necesite para que funcione (podemos limitar a funcionalidade da nosa aplicación se o dispositivo non ten cámara, por exemplo). Para indicar isto temos que poñer:
1 <uses-feature android:name="android.hardware.camera" android:required="false" />
- Permiso de almacenamento: se a aplicación vai gardar os datos nunha tarxeta SD externa:
1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Permiso para capturar audio (se é o caso):
1 <uses-permission android:name="android.permission.RECORD_AUDIO" />
IMPORTANTE: A partires da API 23 (Android 6), Android incorpora outro nivel de seguridade, de tal forma que agora, a maiores, teremos que solicitar dito permiso a nivel de programación. Máis información de como facelo neste enlace.
Captura de Vídeo / Audio
Neste manual imos aprender como facer uso das aplicacións que nos proporciona o S.O. Android para sacar unha foto ou vídeo.
Nos chamaremos a unha destas aplicacións e recolleremos o resultado de volta (que será a foto / vídeo sacado).
Nota: Facer esta parte utilizando o emulador é extremadamente lenta.
Cando prememos o botón de gravar temos que agardar ata que o rectángulo do interior da pantalla se poña vermello:
Os pasos a seguir son:
- Crear un Intent que sexa dun destes tipo:
- MediaStore.ACTION_IMAGE_CAPTURE : Captura unha imaxe.
- MediaStore.ACTION_VIDEO_CAPTURE : Captura un vídeo.
1 Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- Chamar ó método startActivityForResult().
- Neste momento o S.O. lanzará unha aplicación para recoller a imaxe ou vídeo.
- Lembrar que con esta forma de chamar a unha activity, esperamos un resultado (a foto ou vídeo sacado).
1 startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
- Obter o resultado da aplicación lanzada. Para iso temos que desenrolar o método onActivityResult() da nosa Activity.
- Cando chamamos a actitivity que lanza a aplicación de sacar foto ou gravar vídeo, podemos enviarlle como parámetros (no obxecto Bundle) unha serie de datos extras, como a calidade da foto, a calidade de vídeo, o tamaño máximo de gravación,onde queremos gardar a foto/vídeo...
- Máis información en http://developer.android.com/reference/android/provider/MediaStore.html#EXTRA_OUTPUT.
Nota: Para asinar un nome único a cada imaxe / vídeo capturado imos facer uso da clase Date. Cando importemos dita clase lembrar escoller á que se atopa no paquete util:
No caso de non enviar como información extra ó Intent onde queremos gardar o vídeo /foto, estes van vir no obxecto Intent dentro do método onActivityResult():
- No caso das imaxes, a imaxe ven no campo "data" dentro de getExtras do obxecto Bundle:
1 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 2 3 Bitmap bitMap= data.getExtras().get("data")); 4 ......... 5 }
- Unha vez temos o BitMap podemos visualizalo nun control ImageView da seguinte forma:
1 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 2 3 Bitmap bitMap= data.getExtras().get("data")); 4 imgView.setImageBitmap(bitMap); 5 }
- Sendo imgView un obxecto da clase ImageView.
- No caso do vídeo, obtemos o vídeo chamando ó método getData() do obxecto bundle. Isto devolve a URI do vídeo.
1 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 2 3 Uri uri = data.getData(); 4 ......... 5 }
- Para visualizalo necesitamos un obxecto da clase VideoView.
1 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 2 3 vidView.setVideoURI(data.getData()); 4 vidView.start(); 5 }
- Sendo vidView un obxecto da clase VideoView.
Accedendo ó Vídeo / Foto
Cando chamamos a activity que vai sacar a foto / vídeo podemos non indicar onde gardar esa foto
Neste punto imos ver como podemos acceder ó vídeo / foto que ven no Intent dentro do método onActivityResult().
Caso Práctico
O obxectivo desta práctica é visualizar nun control ImageView / VideoView a imaxe / vídeo obtida dende a aplicación do S.O. Android.
Nesta aplicación, debaixo do botón, se atopa un control ImageView e un control VideoView.
Dependendo da opción escollida no RadioButton, un deles estará invisible (propiedade visibility="gone").
Creamos a Activity
- Nome do proxecto: UD6_04_MultimediaFotoVideo
- Nome da activity: UD6_04_MultimediaFotoVideo.java
Código do layout xml
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" >
5
6 <RadioGroup
7 android:id="@+id/UD6_04_rgrpOpcions"
8 android:layout_width="match_parent"
9 android:layout_height="wrap_content"
10 android:layout_alignParentLeft="true"
11 android:layout_alignParentTop="true"
12 android:gravity="center_horizontal"
13 android:orientation="horizontal" >
14
15 <RadioButton
16 android:id="@+id/UD6_04_rbtnFoto"
17 android:layout_width="wrap_content"
18 android:layout_height="wrap_content"
19 android:text="Sacar Foto"
20 android:textSize="15sp"
21 android:checked="true" />
22
23 <RadioButton
24 android:id="@+id/UD6_04_rbtnVideo"
25 android:layout_width="wrap_content"
26 android:layout_height="wrap_content"
27 android:textSize="15sp"
28 android:text="Sacar Vídeo" />
29 </RadioGroup>
30 <Button
31 android:id="@+id/UD6_04_btnGravarVideoFoto"
32 android:layout_width="match_parent"
33 android:layout_height="wrap_content"
34 android:layout_alignParentLeft="true"
35 android:layout_below="@+id/UD6_04_rgrpOpcions"
36 android:textSize="14sp"
37 android:text="Lanzar Aplicación" />
38
39
40 <FrameLayout
41 android:layout_width="match_parent"
42 android:layout_height="match_parent"
43 android:layout_alignParentLeft="true"
44 android:layout_below="@+id/UD6_04_btnGravarVideoFoto">
45
46 <ImageView
47 android:id="@+id/UD6_04_imgvwFoto"
48 android:layout_width="match_parent"
49 android:layout_height="match_parent"
50 android:contentDescription="foto a sacar"
51 android:layout_gravity="center"
52 android:src="@drawable/ic_launcher" />
53
54 <VideoView
55 android:id="@+id/UD6_04_vidvwVideo"
56 android:layout_width="match_parent"
57 android:layout_height="match_parent"
58 android:layout_gravity="center"
59 android:visibility="gone" />
60
61 </FrameLayout>
62
63 </RelativeLayout>
Código da clase UD6_04_MultimediaFotoVideo
Obxectivo: Comprobar como capturar unha imaxe / vídeo e visualizala nun control ImageView / VideoView
1 import android.app.Activity;
2 import android.content.Intent;
3 import android.graphics.Bitmap;
4 import android.os.Bundle;
5 import android.provider.MediaStore;
6 import android.view.View;
7 import android.view.View.OnClickListener;
8 import android.widget.Button;
9 import android.widget.ImageView;
10 import android.widget.RadioButton;
11 import android.widget.RadioGroup;
12 import android.widget.RadioGroup.OnCheckedChangeListener;
13 import android.widget.Toast;
14 import android.widget.VideoView;
15
16 public class UD6_04_MultimediaFotoVideo extends Activity {
17
18 /**
19 * Código para verificar que o resultado ven do intent de gravación
20 */
21 private final int REQUEST_CODE_GRAVACION_OK = 1;
22
23
24 /**
25 * Obtemos a imaxe ou video que ven da aplicacion Android
26 */
27 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
28 if (requestCode == REQUEST_CODE_GRAVACION_OK) {
29 if (resultCode == RESULT_OK) {
30
31 if (data == null) {
32 Toast.makeText(getApplicationContext(), "NON HAI IMAXE/VIDEO A GARDAR", Toast.LENGTH_LONG).show();
33 return;
34 }
35
36 RadioButton rb = (RadioButton) findViewById(R.id.UD6_04_rbtnFoto);
37 if (rb.isChecked()) { // Saca foto
38 ImageView imgview = (ImageView) findViewById(R.id.UD6_04_imgvwFoto);
39 imgview.setImageBitmap((Bitmap) data.getExtras()
40 .get("data"));
41 } else { // Saca vídeo
42 VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo);
43 MediaController mediaController = new MediaController(this);
44 vidview.setMediaController(mediaController);
45 vidview.setVideoURI(data.getData());
46 vidview.start();
47 }
48
49 } else if (resultCode == RESULT_CANCELED) {
50 // Video ou Foto cancelada
51 } else {
52 // Fallo na captura do Video ou foto.
53 }
54 }
55 }
56
57 /**
58 * Programa o código dos click´s os botóns
59 */
60 private void xestionarEventos(){
61 Button gravar = (Button)findViewById(R.id.UD6_04_btnGravarVideoFoto);
62 gravar.setOnClickListener(new OnClickListener(){
63
64 @Override
65 public void onClick(View arg0) {
66 // TODO Auto-generated method stub
67 RadioButton rb = (RadioButton)findViewById(R.id.UD6_04_rbtnFoto);
68
69
70 if (rb.isChecked()){ // Saca foto
71
72 Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
73 startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
74
75 }
76 else { // Grava vídeo
77 Intent intento = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
78 startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
79
80 }
81
82 }
83
84 });
85
86 RadioGroup rgroup = (RadioGroup)findViewById(R.id.UD6_04_rgrpOpcions);
87 rgroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
88
89 @Override
90 public void onCheckedChanged(RadioGroup group, int checkedId) {
91 // TODO Auto-generated method stub
92 ImageView imgview;
93 VideoView videoview;
94
95 switch(checkedId){
96 case R.id.UD6_04_rbtnFoto: // OCULTAMOS O VIDEO
97 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
98 imgview.setVisibility(View.VISIBLE);
99 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
100 videoview.setVisibility(View.GONE);
101 break;
102 case R.id.UD6_04_rbtnVideo: // OCULTAMOS AS FOTOS
103 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
104 imgview.setVisibility(View.GONE);
105 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
106 videoview.setVisibility(View.VISIBLE);
107 break;
108 }
109 }
110 });
111 }
112
113
114 @Override
115 protected void onCreate(Bundle savedInstanceState) {
116 super.onCreate(savedInstanceState);
117 setContentView(R.layout.activity_ud6_04__multimedia_foto_video);
118
119 xestionarEventos();
120 }
121 }
- Liñas 38-39: Nestas liñas obtemos a foto da aplicación do S.O. e a visualiza no ImageView.
- Liñas 42-46: Nestas liñas obtemos o vídeo do Intent e o cargamos no VideoView e comezamos a reprodución.
- Liñas 43-45: Creamos un MediaController asociado ao VideoView para que poidamos ter un control sobre o vídeo (reboninar, ir cara adiante, cara atrás,...)
- Liñas 72-73: Evento click sobre o botón. Se está a opción do RadioButton de sacar unha foto lanzamos o Intent ACTION_IMAGE_CAPTURE, esperando o resultado.
- Liñas 77-78: Evento click sobre o botón. Se está a opción do RadioButton de sacar un vídeo lanzamos o Intent ACTION_VIDEO_CAPTURE, esperando o resultado.
Gardando o Vídeo / Foto
Neste punto imos facer unha modificación da práctica anterior e imos enviar ao Intent información sobre onde debe gardar a foto / vídeo.
Neste caso, o Intent do método onActivityResult NON DEVOLVERÁ NINGÚN DATO.
Caso Práctico
O obxectivo desta práctica é visualizar nun control ImageView / VideoView a imaxe / vídeo obtida dende a aplicación do S.O. Android PERO GARDANDO NA TARXETA SD O RESULTADO DE SACAR ESE VÍDEO / FOTO.
Neste caso as fotos gardadas se almacenan na tarxeta SD no cartafol PICTURES e os vídeos no cartafol MOVIES.
Creamos a Activity
- Nome do proxecto: UD6_05_MultimediaFotoVideo
- Nome da activity: UD6_05_MultimediaFotoVideo.java
- O código do layout vai ser o mesmo que na activity anterior.
Código da clase UD6_05_MultimediaFotoVideo
Obxectivo: Variación da práctica anterior no que indicamos como dato extra a enviar ó intent que obtén a foto / vídeo onde queremos que o garde.
1 import java.io.File;
2
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.graphics.Bitmap;
6 import android.graphics.BitmapFactory;
7 import android.net.Uri;
8 import android.os.Bundle;
9 import android.os.Environment;
10 import android.provider.MediaStore;
11 import android.view.View;
12 import android.view.View.OnClickListener;
13 import android.widget.Button;
14 import android.widget.ImageView;
15 import android.widget.RadioButton;
16 import android.widget.RadioGroup;
17 import android.widget.RadioGroup.OnCheckedChangeListener;
18 import android.widget.VideoView;
19
20 public class UD6_05_MultimediaFotoVideo extends Activity {
21
22 /**
23 * Código para verificar que o resultado ven do intent de gravación
24 */
25 private final int REQUEST_CODE_GRAVACION_OK = 1;
26
27 final private String nomeVideo="video.mp4";
28 final private String nomeFoto="foto.jpg";
29
30
31 /**
32 * Obtemos a imaxe ou video que ven da aplicacion Android
33 */
34 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
35 if (requestCode == REQUEST_CODE_GRAVACION_OK) {
36 if (resultCode == RESULT_OK) {
37
38 RadioButton rb = (RadioButton) findViewById(R.id.UD6_04_rbtnFoto);
39 if (rb.isChecked()) { // Saca foto
40 File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
41 File arquivo = new File(ruta,nomeFoto);
42 if (!arquivo.exists()) return; // Non hai foto
43
44 ImageView imgview = (ImageView) findViewById(R.id.UD6_04_imgvwFoto);
45 Bitmap bitmap = BitmapFactory.decodeFile(arquivo.getAbsolutePath());
46 imgview.setImageBitmap(bitmap);
47
48 } else { // Saca vídeo
49 File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
50 File arquivo = new File(ruta,nomeVideo);
51 if (!arquivo.exists()) return; // Non hai foto
52
53 VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo);
54 vidview.setVideoURI(Uri.fromFile(arquivo));
55 vidview.start();
56 }
57
58 } else if (resultCode == RESULT_CANCELED) {
59 // Video ou Foto cancelada
60 } else {
61 // Fallo na captura do Video ou foto.
62 }
63 }
64 }
65
66 /**
67 * Programa o código dos click´s os botóns
68 */
69 private void xestionarEventos(){
70 Button gravar = (Button)findViewById(R.id.UD6_04_btnGravarVideoFoto);
71 gravar.setOnClickListener(new OnClickListener(){
72
73 @Override
74 public void onClick(View arg0) {
75 // TODO Auto-generated method stub
76 RadioButton rb = (RadioButton)findViewById(R.id.UD6_04_rbtnFoto);
77
78
79 if (rb.isChecked()){ // Saca foto
80 File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
81 File arquivo = new File(ruta,nomeFoto);
82
83 Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
84 intento.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivo));
85 startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
86
87 }
88 else { // Grava vídeo
89 File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
90 File arquivo = new File(ruta,nomeVideo);
91
92 Intent intento = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
93 intento.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivo));
94
95 startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
96
97 }
98
99 }
100
101 });
102
103 RadioGroup rgroup = (RadioGroup)findViewById(R.id.UD6_04_rgrpOpcions);
104 rgroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
105
106 @Override
107 public void onCheckedChanged(RadioGroup group, int checkedId) {
108 // TODO Auto-generated method stub
109 ImageView imgview;
110 VideoView videoview;
111
112 switch(checkedId){
113 case R.id.UD6_04_rbtnFoto: // OCULTAMOS O VIDEO
114 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
115 imgview.setVisibility(View.VISIBLE);
116 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
117 videoview.setVisibility(View.GONE);
118 break;
119 case R.id.UD6_04_rbtnVideo: // OCULTAMOS AS FOTOS
120 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
121 imgview.setVisibility(View.GONE);
122 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
123 videoview.setVisibility(View.VISIBLE);
124 break;
125 }
126 }
127 });
128 }
129
130
131 @Override
132 protected void onCreate(Bundle savedInstanceState) {
133 super.onCreate(savedInstanceState);
134 setContentView(R.layout.activity_ud6_05__multimedia_foto_video);
135
136 xestionarEventos();
137 }
138 }
- Liñas 40-42: Obtemos un obxecto File que apunta ó nome da imaxe gardada. Este dato foi enviado como dato extra ó intent cando lanzamos a aplicación de obter unha foto.
- Liña 45: Obtemos un obxecto da clase BitMap a partires do obxecto File.
- Liñas 49-51: Obtemos un obxecto File que apunta ó nome do vídeo gardado. Este dato foi enviado como dato extra ó intent cando lanzamos a aplicación de obter o vídeo.
- Liña 54: Obtemos a Uri a partires do obxecto File.
- Liña 84: Enviamos como información extra no Intent a ruta onde debe gardar a foto sacada.
- Liña 93: Enviamos como información extra no Intent a ruta onde debe gardar o vídeo sacado.
Importante: Como xa comentamos antes, getData() no Intent do método onActivityResult() non trae nada.
Información Extra
Como comentamos antes podemos enviar o Intent diversa información (como a ruta onde gardar a foto / vídeo).
Outra información que podemos enviar:
- No caso de captura de fotos, podemos pasarlle o Intent (chamando o método putExtra da clase Intent):
- MediaStore.EXTRA_OUTPUT : Directorio e arquivo (URI) onde se vai gardar a foto. Se non se especifica, o Intent gardará o imaxe cun nome e directorio por defecto que ven especificado no intent de retorno Intent.getData().
- No caso do vídeo, algúns dos datos que podemos enviarlle a Intent son:
- MediaStore.EXTRA_OUTPUT : Directorio e arquivo (URI) onde se vai gardar o vídeo.
- Se non se especifica, o Intent gardará o imaxe cun nome e directorio por defecto que ven especificado no intent de retorno Intent.getData().
- MediaStore.EXTRA_VIDEO_QUALITY: Calidade da imaxe. Se valor 0 sería calidad baixa (para mms) e se vale 1 calidade alta.
- MediaStore.EXTRA_DURATION_LIMIT: Nº de segundos máximos para gravación.
- MediaStore.EXTRA_SIZE_LIMIT: Tamaño máximo do arquivo en bytes.
- MediaStore.EXTRA_OUTPUT : Directorio e arquivo (URI) onde se vai gardar o vídeo.
Control para o VideoView
- Cando creamos o layout e arrastramos o VideoView ó mesmo, podemos facer uso doutro control asociado ó mesmo que permite ter as opcións de 'Pause', 'Stop',...
- Este control denomínase MediaController.
- Para asocialo a un VideoView:
1 MediaController controller = new MediaController(this); 2 VideoView videoview = (VideoView)findViewById(R.id.vidvwVideo); 3 4 videoview.setMediaController(controller);
- Se o aplicamos á nosa práctica:
1 import android.widget.MediaController; 2 3 private void controlVideo(){ 4 MediaController controller = new MediaController(this); 5 VideoView videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo); 6 videoview.setMediaController(controller); 7 8 } 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_ud6_04__multimedia_foto_video); 14 15 controlVideo(); 16 xestionarEventos(); 17 }
Métodos útiles no manexo de Imaxes
- Bitmap.createScaledBitmap(bitmaporixinal, witdh, height, boolean filter): devolve un obxecto da clase Bitmap e vainos servir para escalar un bitmap a outro tamaño indicado por width e height.
O filter debería ser posto a true se facemos a imaxe máis grande e a false se a facemos máis pequena. Para determinar o tamaño adecuado do Bitmap en función dos puntos por polgada do dispositivo onde nos atopamos podemos facer uso da propiedade densityDpi:
1 switch (getResources().getDisplayMetrics().densityDpi) {
2 case DisplayMetrics.DENSITY_LOW:
3 break;
4 case DisplayMetrics.DENSITY_MEDIUM:
5 break;
6 case DisplayMetrics.DENSITY_HIGH:
7 break;
8 case DisplayMetrics.DENSITY_XHIGH:
9 break;
10 }
En función do valor de densidade escalaremos a imaxe a un tamaño adecuado tendo en conta a proporción:
- xhdpi: 2.0
- hdpi: 1.5
- mdpi: 1.0 (baseline)
- ldpi: 0.75
Nota: Normalmente cando facemos fotos e queremos visualizalas todas xuntas (por exemplo utilizando un horizontalScrollView) faise uso deste método para ter unha imaxe en pequeno da foto e despois cargar a imaxe orixinal cando a visualicemos a pantalla completa.
- Obxectobitmap.compress(CompressFormat.JPEG, 100,os): comprime un bitmap e o escribe a disco utilizando un FileOutputStream. O primeiro parámetro indica o tipo de compresión (se temos transparencias na imaxe orixinal deberemos usar BMP), o segundo indica o nivel de compresión (se é 50 sería o 50%, no exemplo o deixaría tal cal) e o terceiro parámetro é un obxecto da clase FileOutputStream para pasalo a disco.
Este método pode servirnos para pasar un bitmap a disco utilizando un obxecto da clase File (o veremos na unidade de Datos Persistentes) e obtendo o FileOutputStream a partires del. É importante asinarlle unha extensión ó arquivo que vai ser a imaxe gardada.
Se a foto a temos asinada a un ImageView e queremos recuperala coma un obxecto da clase Bitmap teremos que facer:
1 imgview.setDrawingCacheEnabled(true);
2 Bitmap imaxe = imgview.getDrawingCache();
Sendo imgview o obxecto que fai referencia ó ImageView.
O proceso contrario, é dicir, cargar unha foto nun ImageView será o seguinte (o veremos outra vez na unidade de datos persistentes):
1 Bitmap bitmap = BitmapFactory.decodeFile(Obxecto_file_apuntando_á_imaxe_gardada);
2 img.setImageBitmap(bitmap);
Sendo img un obxecto da clase ImageView.
Métodos útil no manexo de Vídeos
Pode resultarnos necesario a partires dun vídeo obter unha foto del.
Para facelo debemos de utilizar a clase ThumbnailUtils
Vexamos un exemplo:
1 BitMap preview_bitmap = ThumbnailUtils.createVideoThumbnail(uri_al_vídeo.toString(), Thumbnails.MICRO_KIND);
- Queda como 'exercicio' que busquedes en Internet como cargar un vídeo gardado localmente no proxecto, no cartafol /res/raw/
Visualización de múltiples imaxes
Pode darse o caso de que necesitemos visualizar múltiples imaxes na nosa activity.
Nota: Como está comentado en liñas anteriores, o lóxico será ter unha versión 'en pequeno' da foto para non encher a memoria utilizando o método compress da clase BitMap ou ben utilizando o método Bitmap.createScaledBitmap, como está feito no exemplo que ven a continuación.
Temos varias posibilidades para facer isto:
- Control Gallery: deprecated a partires da API 16.
- Control HorizontalScrollView.
- Control ViewPager.
- Actualización 2018
- A partires da API 22 aparece o Widget RecyclerView que permite facer o mesmo que o HorizontalScrollView pero de forma moito máis eficiente.
- Lembrar que dito compoñente está dentro das opción de investigación para desenvolver a práctica.
- Para cargar dito compoñente nunha API inferior á 22 (vos tedes que facer a aplicación cun API>=19) teredes que facer uso dunha biblioteca de compatibilidade, como xa vimos na Wiki.
Neste apartado imos ver como utilizar un HorizontalScrollView.
Caso Práctico
O obxectivo desta práctica é ver como podemos utilizar o HorizontalScrollView para visualizar imaxes en pequeno.
Como o seu propio nome indica, o HorizontalScrollView é un control que permite facer un scroll horizontal de View´s.
A idea é ter dentro deste control un LinearLayout coas imaxes.
Cada imaxe vai ter un layout cun tamaño (o tamaño da miniatura) e xestionaremos o evento de Click sobre a imaxe en miniatura para ver dita imaxe nun ImageView en grande.
Preparación
Será necesario copiar ó cartafol da SD onde o S.O. Android garda as imaxes por defecto, dúas imaxes calquera de nome foto1.jpg e foto2.jpg.
Utilizamos a clase EnvironMent (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)) para indicar a ruta onde se atopan as fotos.
Normalmente esta ruta se atopa en /sdcard/Pictures.
- Se utilizades o emulador podedes copiar as fotos utilizando a perspectiva DDMS.
- Se estades a utilizar un dispositivo real teredes que copiar as fotos conectando o dispositivo ó computador.
O alumno é libre de utilizar outra ruta calquera modificando o código convenientemente.
Creamos a Activity
- Nome do proxecto: UD6_06_MultimediaHorizontalScrollView
- Nome da activity: UD6_06_MultimediaHorizontalScrollView.java
Código do layout xml
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 tools:context="${relativePackage}.${activityClass}" >
6
7 <HorizontalScrollView
8 android:id="@+id/UD6_06_hsviewFotosPai"
9 android:layout_width="match_parent"
10 android:layout_height="wrap_content"
11 android:layout_alignParentTop="true"
12 android:layout_centerHorizontal="true"
13 android:layout_marginTop="26dp" >
14
15 <LinearLayout
16 android:id="@+id/UD6_06_linearLayoutFotosFillo"
17 android:layout_width="wrap_content"
18 android:layout_height="wrap_content"
19 android:orientation="horizontal" />
20
21 </HorizontalScrollView>
22
23 <ImageView
24 android:id="@+id/UD6_06_imgvwFotoAmpliada"
25 android:layout_width="500dp"
26 android:layout_height="500dp"
27 android:layout_alignParentBottom="true"
28 android:layout_centerHorizontal="true"
29 android:layout_marginBottom="26dp"
30 android:src="@drawable/ic_launcher" />
31
32 </RelativeLayout>
Como vemos temos un HorizontalScrollView e un LinearLayout dentro do mesmo.
Código da clase UD6_06_MultimediaHorizontalScrollView
Obxectivo: Carga nun HorizontalScrollView dúas fotos gardadas na tarxeta SD do dispositivo.
Nota: Vos dará un erro xa que fai uso dunha clase explicada a continuación.
1 import java.io.File;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Environment;
6 import android.widget.LinearLayout;
7
8 public class UD6_06_MultimediaHorizontalScrollView extends Activity {
9
10 @Override
11 protected void onCreate(Bundle savedInstanceState) {
12 super.onCreate(savedInstanceState);
13 setContentView(R.layout.activity_ud6_06__multimedia_horizontal_scroll_view);
14
15 LinearLayout linear = (LinearLayout)findViewById(R.id.UD6_06_linearLayoutFotosFillo);
16
17 String ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();
18
19 UD6_06_ImaxeHorizontalScrollView imaxe = new UD6_06_ImaxeHorizontalScrollView(this, ruta+File.separator+"foto1.jpg");
20 linear.addView(imaxe.getLayout());
21 imaxe = new UD6_06_ImaxeHorizontalScrollView(this, ruta+File.separator+"foto2.jpg");
22 linear.addView(imaxe.getLayout());
23
24 }
25 }
- Liña 15: Obtemos a referencia ó LinearLayout que se atopa dentro do HorizontalScrollView.
- Liña 17: Ruta onde se atopan as imaxes.
- Liña 19,21: Creamos dous obxectos da clase UD6_06_ImaxeHorizontalScrollView (explicada posteriormente).
- Liñas 20,22: Engadimos ditas imaxes ó LinearLayout.
Creamos o ImageView personalizado
Agora imos explicar a clase UD6_06_ImaxeHorizontalScrollView.
A idea é moi sinxela.
Vou engadir ó LinearLayout obxectos da clase ImageView.
A diferenza é que vou personalizar ditos obxectos para que estean (a imaxe) dentro dun Layout creado por min y cun tamaño concreto (o veremos no código).
Ademais xestionaremos o evento Click sobre a imaxe para facer que apareza en grande no ImageView da Activity principal.
O que hai que ter moi claro é que esta clase representa cada unha das imaxes en miniatura que vemos dentro do control HorizontalScrollView.
Código da clase UD6_06_ImaxeHorizontalScrollView
Obxectivo: Facemos un ImageView personalizado cun tamaño específico e xestionamos o evento Click sobre a imaxe.
1 import java.io.File;
2
3 import android.graphics.Bitmap;
4 import android.graphics.BitmapFactory;
5 import android.view.Gravity;
6 import android.view.View;
7 import android.view.View.OnClickListener;
8 import android.view.ViewGroup.LayoutParams;
9 import android.widget.ImageView;
10 import android.widget.LinearLayout;
11
12 public class UD6_06_ImaxeHorizontalScrollView extends ImageView implements OnClickListener {
13 protected UD6_06_MultimediaHorizontalScrollView context;
14 private File file;
15 private String path;
16 private LinearLayout layout;
17
18 /**
19 * Crea unha imaxe e a engade nun layout que vai ser o que visualice o HorizontalView
20 * @param context
21 * @param path: ruta a imaxe
22 */
23 public UD6_06_ImaxeHorizontalScrollView(UD6_06_MultimediaHorizontalScrollView context,String path) {
24 super(context);
25 this.context=context;
26 this.path=path;
27 file = new File(path);
28
29 setOnClickListener(this);
30 crearLayout();
31 }
32
33 private void crearLayout() {
34 LinearLayout layout = new LinearLayout(context);
35 layout.setLayoutParams(new LayoutParams(135, 135));
36 layout.setGravity(Gravity.CENTER);
37
38 this.setLayoutParams(new LayoutParams(120, 120)); // TAMAÑO DA IMAXE
39 this.setScaleType(ImageView.ScaleType.CENTER_CROP);
40 Bitmap bit = BitmapFactory.decodeFile(file.getAbsolutePath());
41 if (bit==null) { // Non a pode cargar
42 this.layout=layout;
43 return;
44 }
45 Bitmap bitmap;
46 bitmap = Bitmap.createScaledBitmap(bit, 220, 220,false);
47 this.setImageBitmap(bitmap);
48
49 layout.addView(this);
50 this.layout = layout;
51 }
52
53 public LinearLayout getLayout(){
54 return layout;
55 }
56
57 public File getFile(){
58 return file;
59 }
60 public String getPath(){
61 return path;
62 }
63 @Override
64 public void onClick(View v) {
65 // TODO Auto-generated method stub
66
67 Bitmap bp = BitmapFactory.decodeFile(getPath());
68 ImageView imgview = (ImageView)context.findViewById(R.id.UD6_06_imgvwFotoAmpliada);
69 imgview.setImageBitmap(bp);
70 }
71
72
73 }
- Liña 12: Fixarse como facemos unha clase que deriva de ImageView e implementa a interface onClickListener para xestionar o evento click sobre a imaxe
- Liña 23: No constructor recibimos unha instancia da clase que utiliza o ImageView. Isto é necesario xa que cando prememos sobre a imaxe en miniatura temos que atopar o ImageView da activiry para cargar a imaxe en grande. Como segundo parámetro enviamos a ruta ó arquivo de imaxe.
- Liñas 25-27: Gardamos os datos enviados.
- Liña 29: Facemos que o evento de click se xestione dentro da clase.
- Liña 30: Chamamos ó método que vai crea o Layout onde vai ir a imaxe.
- Liñas 33-51: Creamos o layout (LinearLayout) que vai albergar a foto.
- Liñas 34-36: Layout que alberga a imaxe.
- Liñas 38-39: Tamaño e tipo de escala da imaxe dentro do layout.
- Liña 40-47: Cargamos a imaxe dende a SD Externa e a asignamos ó ImageView.
- Liñas 48-51: Engadimos o layout creado o ImageView cargado de disco.
- Liñas 64-71: Xestionamos o evento do Click sobre a imaxe. Buscamos o control ImageView da activity principal (UD6_06_imgvwFotoAmpliada) e cargamos a partires do path a imaxe no ImageView.
-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2014).