Android: Reproducir vídeo con VideoView

Standard

 

VideoViewExample

 

Cuando se trata de que nuestra aplicación Android sea capaz de mostrar y reproducir archivos de vídeo, la opción indicada es la clase VideoView de Android. A continuación, un ejemplo práctico de cómo implementarlo.

Como la documentación lo indica, la clase VideoView se encarga de mostrar y/o reproducir un archivo de vídeo. Puede cargar vídeos desde varias fuentes (como resources o proveedores de contenido), se encarga de calcular las medidas del vídeo para que pueda ser manejado por cualquier layout en el que éste sea insertado, y provee además de varias opciones de visualización y ajuste, entre otras cosas).

Un detalle de especial importancia al implementar VideoView, es que esta clase no retiene su estado total cuando nuestro Activity se va a background. Al volver a estar visible, VideoView por default no restaura el estado actual de la reproducción, la posición en que ésta fue detenida, o cualquier archivo de subtítulos agregado por medio de addSubtitleSource(). Para resolver este problema, es necesario que nuestra aplicación guarde y restaure esos valores por sí misma mediante onSaveInstanceState(Bundle) y onRestoreInstanceState(Bundle), lo cual haremos en el presente ejemplo. Entonces no se diga más, manos a la obra.

En este ejemplo serán descritos los siguientes archivos:

  • layout/activity_video_view_example.xml
  • src/VideoViewExampleActivity.java

ATENCIÓN: Comentarios en el código.

Creación del Layout.

<!-- activity_video_view_example.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#282828"
    tools:context="com.hunabsys.myexampleapp.VideoViewExampleActivity">

    <!-- Navbar -->
    <include
        android:id="@+id/navbar"
        layout="@layout/navbar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/navbar" />

</RelativeLayout>

Creación de nuestro Activity.

/*
 * VideoViewExampleActivity.java
 */
package com.hunabsys.myexampleapp;

import android.app.Activity;
import android.media.MediaPlayer;
...
public class VideoViewExampleActivity extends Activity {

    private VideoView videoView;
    private int position = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_view_example);

        // Muestra el Activity en modo Landscape.
        this.setRequestedOrientation(
            ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        setUpVideoView();
    }

    private void setUpVideoView() {
        // Prepara la URI del vídeo que será reproducido.
        String uriPath = "android.resource://" + getPackageName() 
            + "/" + R.raw.video_example;
        Uri uri = Uri.parse(uriPath);

        // Se crean los controles multimedia.
        MediaController mediaController = new MediaController(this);

        // Inicializa la VideoView.
        videoView = (VideoView) findViewById(R.id.videoView);
        // Asigna los controles multimedia a la VideoView.
        videoView.setMediaController(mediaController);

        try {
            // Asigna la URI del vídeo que será reproducido a la vista.
            videoView.setVideoURI(uri);
            // Se asigna el foco a la VideoView.
            videoView.requestFocus();
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }

        /* 
         * Se asigna un listener que nos informa cuando el vídeo 
         * está listo para ser reproducido.
         */
        videoView.setOnPreparedListener(videoViewListener);
    }

    private MediaPlayer.OnPreparedListener videoViewListener = 
        new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            /*
             * Se indica al reproductor multimedia que el vídeo 
             * se reproducirá en un loop (on repeat).
             */
            mediaPlayer.setLooping(true);

            if (position == 0) {
                /* 
                 * Si tenemos una posición en savedInstanceState, 
                 * el vídeo debería comenzar desde aquí.
                 */
                videoView.start();
            } else {
                /* 
                 * Si venimos de un Activity "resumed", 
                 * la reproducción del vídeo será pausada.
                 */
                videoView.pause();
            }
        }
    };

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        /* Usamos onSaveInstanceState para guardar la posición de
           reproducción del vídeo en caso de un cambio de orientación. */
        savedInstanceState.putInt("Position", 
            videoView.getCurrentPosition());
        videoView.pause();
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        /*
         * Usamos onRestoreInstanceState para reproducir el vídeo 
         * desde la posición guardada.
         */
        position = savedInstanceState.getInt("Position");
        videoView.seekTo(position);
    }
}

Con lo anterior en nuestra aplicación, es posible dar click y reproducir, pausar, adelantar o atrasar nuestro vídeo, y además girar el dispositivo sin tener que pausar o reproducir de nuevo.

Espero haya sido de utilidad este ejercicio y me despido. ¡Hasta luego!

Fuentes:

8 thoughts on “Android: Reproducir vídeo con VideoView

  1. Uziel Morales Medina

    Oye, tengo un problema, ya tenia conocimientos sobre este tema, pero e visto blogs que hablan sobre que se puede reproducir un video dentro de la carpeta raw en resources, hasta ahí bien, lo que me pasa esque simplemente me dice que no se puede reproducir el video, trate de cambiarle el formato pero nunca me deja reproducirlo, estoy pensando que es la version de la api en android en la que estoy desarrollando, pero me extraña ver los blogs y ver que no les marca ese error

    • Silvia Valdez

      Qué tal, Uziel, gracias por comentar.

      ¿Intentaste seguir este tutorial completo y te ocurrió ese error? Según he visto en una investigación rápida es que es posible que el formato del vídeo o códecs no sean compatibles, la declaración del “path” a tu vídeo sea incorrecta por algún detalle o el archivo esté dañado.
      También puedes checar los logs de Android Monitor (en caso de que estés usando Android Studio) por si te proporcionan más información acerca del error.

      De cualquier manera sería muy útil que compartieras tu código o los logs de error para poder ayudarte (: Saludos.

  2. Uziel Morales Medina

    Silvia, gracias por contestar.

    Verifique esos posibles errores y lo que veo mas cercano es el tipo de archivo, ya que investigue y segun la version de android permite mas tipos de archivos que otros, porque en mi codigo no tengo errores, simplemente al correrlo y abrir la app no se reproduce el video y me avisa que no se puede reproducir este video, este es el codigo que utilizo para mi video:

    VideoView Videoview = (VideoView)findViewById(R.id.vv);
    Uri path = Uri.parse(“android.resources://”+getPackageName()+”/”+R.raw.rock2);
    Videoview.setVideoURI(path);
    Videoview.start();
    y el video esta en formato .webm, intente con .mp4 y no igualmente, estoy desarrollando la app con la api 10 de android en su version 2.3.3 y creo que tiene que ser algun tipo de archivo de video diferente, porque el video no esta dañado y no marca ningun error ni al crear el apk. Saludos.

    • Silvia Valdez

      Qué tal, Uziel.

      Lo que observo a simple vista en el snippet de código que me muestras, es que “android.resources://” debería ser “android.resource://”, sin la S al final de la palabra “resource”. Puede parecer una tontería pero en algunos casos algo tan simple puede ser difícil de ubicar al estar tan familiarizado con el propio código y terminar alterando el path a tu archivo, como un principio puedes intentar revisando eso.

      Además, buscando información con respecto al formato de vídeo que me comentas que estás utilizando, encontré este issue en StackOverflow que al parecer es muy similar a lo que te sucede, quizá pueda serte de ayuda: http://stackoverflow.com/questions/11354708/webm-not-playing-on-android

      Como último recurso, puede parecer obvio pero quizá el convertir tu archivo de vídeo a otro formato para comprobar que el problema no sea en particular el formato de vídeo que se esté utilizando o que el archivo se encuentre en buenas condiciones al hacer la conversión. En este enlace se listan los formatos multimedia soportados por Android para las diferentes versiones del OS: http://developer.android.com/intl/es/guide/appendix/media-formats.html

      ¡Saludos!

  3. Uziel Morales Medina

    Saludos Silvia

    Tenias razón tal vez si era un error simple pero si, era la S al final del resource, de igual forma te lo agradesco mucho por haberme respondido ya que nadie me sabía decir, ahora podre seguir con mi aplicación muchas gracias!!

    • Silvia Valdez

      Qué tal, René.

      Basándome en la respuesta del enlace de StackOverflow que me mostraste, hice una implementación completa del ejemplo para que, en caso de que algún detalle falte en tu proyecto, puedas verlo funcionando.
      No hay ningún problema al reproducir vídeos desde Google Drive, lo que se hace en la respuesta del enlace que me mostraste es parsear o convertir la URL de Drive a un formato con el cual es posible directamente reproducir el vídeo en la vista.

      Dejo aquí mismo las partes importantes del código, la app completa puedes encontrarla en el siguiente enlace de GitHub:
      https://github.com/silvia-valdez/AndroidProjects/tree/master/Examples/MultimediaApp

      Espero te sea de ayuda. Saludos.

      private static final String TAG = MainActivity.class.getSimpleName();
      private static final String GOOGLE_DRIVE_URL
      = “https://drive.google.com/file/d/0Bz78-shpGme_N0NXencyMkVTcjA/preview”;

      private VideoView mVideoView;
      private ProgressDialog mDialog;

      /**
      * METHODS.
      */
      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      /**
      * Generated methods and etc…
      **/

      initVariables();
      downloadUrl(GOOGLE_DRIVE_URL);
      }

      private void initVariables() {
      // ProgressDialog para mostrar el estado de la app
      mDialog = ProgressDialog.show(this, “”, “Downloading URL…”, true);

      // Este frame se usa para ocultar el VideoView hasta que esté preparado para reproducir
      final FrameLayout frame = (FrameLayout) findViewById(R.id.main_frame);
      if (frame != null) {
      frame.setVisibility(View.INVISIBLE);
      }

      mVideoView = (VideoView) findViewById(R.id.videoView);
      if (mVideoView != null) {
      mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
      // Cuando el vídeo está preparado para mostrarse, se oculta el ProgressDialog
      // y se muestra el VideoView
      if (mDialog.isShowing()) mDialog.dismiss();
      if (frame != null) {
      frame.setVisibility(View.VISIBLE);
      }
      }
      });
      }
      }

      private void initVideoView(String downloadedUrl) {
      mDialog.setMessage(“Starting video…”);
      Uri uri = Uri.parse(downloadedUrl);

      if (mVideoView != null) {
      mVideoView.setVideoURI(uri);
      mVideoView.start();
      }
      }

      public void downloadUrl(final String strUrl) {
      new Thread(new Runnable() {
      @Override
      public void run() {
      try {
      URL url = new URL(strUrl);
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setReadTimeout(10000);
      connection.setConnectTimeout(15000);
      connection.setRequestMethod(“GET”);
      connection.setDoInput(true);
      connection.connect();
      InputStream inputStream = connection.getInputStream();
      final String downloadedUrl = readIt(inputStream);
      Log.d(TAG, String.format(“New URL: %s”, downloadedUrl));

      runOnUiThread(new Runnable() {
      @Override
      public void run() {
      initVideoView(downloadedUrl);
      }
      });
      } catch (Exception e) {
      e.printStackTrace();
      runOnUiThread(new Runnable() {
      @Override
      public void run() {
      mDialog.dismiss();
      Toast.makeText(getApplicationContext(),
      “Failed to connect with the server”,
      Toast.LENGTH_LONG).show();
      }
      });
      }
      }
      }).start();
      }

      public String readIt(InputStream stream) throws IOException {
      BufferedReader reader = new BufferedReader(new InputStreamReader(stream, “UTF-8”));
      StringBuilder stringBuilder = new StringBuilder();
      String line;
      while ((line = reader.readLine()) != null) {
      if (line.contains(“fmt_stream_map”)) {
      stringBuilder.append(line).append(“\n”);
      break;
      }
      }
      reader.close();
      String result = decode(stringBuilder.toString());
      String[] url = result.split(“\\|”);
      return url[1];
      }

      public String decode(String url) {
      String working = url;
      int index;
      index = working.indexOf(“\\u”);
      while (index > -1) {
      int length = working.length();
      if (index > (length – 6)) break;
      int numStart = index + 2;
      int numFinish = numStart + 4;
      String substring = working.substring(numStart, numFinish);
      int number = Integer.parseInt(substring, 16);
      String stringStart = working.substring(0, index);
      String stringEnd = working.substring(numFinish);
      working = stringStart + ((char) number) + stringEnd;
      index = working.indexOf(“\\u”);
      }
      return working;
      }

Leave a Reply

Your email address will not be published. Required fields are marked *