Error Android MediaPlayer / VideoView (1, -2147483648)

He tenido una experiencia inconsistente al configurar un video de VideoView desde una ruta de archivo.

VideoView myVideoView = findViewById(R.id.videoView); ... myVideoView.setVideoPath(videoFilename); ... myVideoView.start(); 

videoFilename es la ruta absoluta de un video en mi directorio de caché:

 String videoFilename = new File(context.getCacheDir(), "myawesomevideo.mp4").getAbsolutePath(); 

En Android SDK> = 16 (Jelly Bean), esto funciona bien y se reproduce mi increíble video. En Android 4.0.4 (SDK = 15), MediaPlayer se rompe cuando se invoca myVideoView.start ().

El error es siempre inútil:

 error (1, -2147483648) 

¿Que me estoy perdiendo aqui? Cargando un archivo directamente desde los activos de mi paquete (res / raw) o internet ( http://something.com/myawesomeinternetvideo.mp4 ), ¡pero no puedo entender cómo leer archivos de mi directorio de caché!

Como resultado, el error -2147483648 indica un error desconocido. Esto podría tener algo que ver con la encoding de video, pero también vale la pena comprobar que la ruta del archivo existe y que VideoView tiene permiso para leerla .

Mi problema era que estaba escribiendo mis archivos con Context.MODE_PRIVATE (el valor predeterminado).

 openFileOutput(filename, Context.MODE_PRIVATE); 

Esto indica que solo su aplicación puede acceder al archivo. No sé específicamente cómo o por qué, pero en Jelly Bean y arriba, parece que la vista de video tiene permiso para acceder al archivo que especifique como si fuera su aplicación, pero antes de Jelly Bean, la vista de video intenta abrir el archivo en su propio contexto (no de su aplicación). Como el modo es privado, falla.

Una solución es escribir su archivo con Context.MODE_WORLD_READABLE , que ahora está en desuso. Esto indica que cualquiera puede abrir el archivo en esa ruta. Esto es obviamente inseguro y desalentado.

Terminé creando un proveedor de contenido y mi propio URI para manejar este caso. Específicamente:

AndroidManfest.xml :

 ...    

VideoProvider.java :

 package com.myexampleapp.video; import java.io.File; import java.io.FileNotFoundException; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.ParcelFileDescriptor; public class VideoProvider extends ContentProvider { public static final Uri CONTENT_URI_BASE = Uri.parse("content://com.myexampleapp.video.VideoProvider.files.files/"); private static final String VIDEO_MIME_TYPE = "video/mp4"; @Override public boolean onCreate() { return true; } @Override public String getType(final Uri uri) { return VIDEO_MIME_TYPE; } @Override public ParcelFileDescriptor openFile(final Uri uri, final String mode) throws FileNotFoundException { File f = new File(uri.getPath()); if (f.exists()) return (ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY)); throw new FileNotFoundException(uri.getPath()); } @Override public int delete(final Uri uri, final String selection, final String[] selectionArgs) { throw new UnsupportedOperationException(); } @Override public Uri insert(final Uri uri, final ContentValues values) { throw new UnsupportedOperationException(); } @Override public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) { throw new UnsupportedOperationException(); } @Override public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) { throw new UnsupportedOperationException(); } } 

Y luego, donde accedo a mis archivos de video:

 VideoView myVideoView = findViewById(R.id.videoView); ... myVideoView.setVideoURI( Uri.parse( CachedActionProvider.CONTENT_URI_BASE + Uri.encode(videoFilename))); ... myVideoView.start(); 

Esta es una manera realmente larga de decirle a VideoView que solicite a su proveedor de contenido el descriptor de archivo de los datos. Los descriptores de archivos no tienen permiso, por lo que puede abrir el archivo usando los permisos de su aplicación y entregarlo a VideoView en lugar de pedirle a VideoView que abra el archivo con sus propios permisos.

¡Esto soluciona mi problema y espero que sea tuyo también!

También tuve este problema al cargar un archivo de video desde el directorio de caché. El problema parecía ocurrir solo en los dispositivos Nexus, pero no lo pruebo en muchos dispositivos.

Traté de escribir el archivo con Context.MODE_WORLD_READABLE, pero esa corrección no funcionó para mí. El VideoProvider.java tampoco lo solucionó.

Entonces encontré otra solución que funcionó para mí. Creé un tempFile en mi actividad y le di a VideoView el camino perfecto.

Tal vez mi código puede ayudar a alguien 🙂

  private MediaController mController; private VideoView mVideoView; private File mTmpFile = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video); init(); } private void init() { mProgressDialog = new ProgressDialog(this); mVideoView = (VideoView) findViewById(R.id.surface_video); mVideoView.requestFocus(); mController = new MediaController(this); mVideoView.setMediaController(mController); mVideoView.setOnPreparedListener(this); mVideoView.setOnCompletionListener(this); mVideoView.setOnErrorListener(this); String url = getIntent().getExtras().getString(MainActivity.VIDEO_URL_EXTRA_KEY); if (VideoLoaderTask.hasVideo(this, url)) { url = getCacheDir().toString().concat("/" + VideoLoaderTask.VIDEO_DIR + "/").concat(url); copyToTmpFile(url); mVideoView.setVideoPath(mTmpFile.getAbsolutePath()); } else { mVideoView.setVideoURI(Uri.parse(url)); } mProgressDialog.show(); mVideoView.start(); } @Override public void onDestroy() { if (mTmpFile != null) { mTmpFile.delete(); } super.onDestroy(); } private void copyToTmpFile(String url) { File f = new File(url); try { mTmpFile = File.createTempFile("video", null); mTmpFile.deleteOnExit(); FileInputStream is = new FileInputStream(f); int size = is.available(); byte[] buffer = new byte[size]; is.read(buffer); is.close(); FileOutputStream fos = new FileOutputStream(mTmpFile); fos.write(buffer); fos.close(); } catch (Exception e) { mVideoView.setVideoURI(Uri.parse(url)); } }