Android MediaPlayer/VideoView错误(1,-2147483648)

spi*_*tor 23 android android-mediaplayer android-videoview

我从文件路径设置VideoView的视频时遇到了不一致的经历.

VideoView myVideoView = findViewById(R.id.videoView);
...
myVideoView.setVideoPath(videoFilename);
...
myVideoView.start();
Run Code Online (Sandbox Code Playgroud)

videoFilename是我的缓存目录中视频的绝对路径:

String videoFilename = new File(context.getCacheDir(), "myawesomevideo.mp4").getAbsolutePath();
Run Code Online (Sandbox Code Playgroud)

在Android SDK> = 16(Jelly Bean)中,这很好用,我的精彩视频播放.在Android 4.0.4(SDK = 15)中,当调用myVideoView.start()时,MediaPlayer会中断.

错误是永远无益的:

error (1, -2147483648)
Run Code Online (Sandbox Code Playgroud)

我在这里错过了什么?直接从我的包资产(res/raw)或互联网(http://something.com/myawesomeinternetvideo.mp4)加载文件,但我无法弄清楚如何从缓存目录中读取文件!

spi*_*tor 15

事实证明,错误-2147483648表示未知错误.这可能与视频编码有关,但也值得检查文件路径是否存在以及VideoView是否有权读取它.

我的问题是我用Context.MODE_PRIVATE(默认值)编写我的文件.

openFileOutput(filename, Context.MODE_PRIVATE);
Run Code Online (Sandbox Code Playgroud)

这表示只有您的应用程序才能访问该文件.我不知道具体如何或为什么,但在Jelly Bean及以上版本中,似乎允许视频视图访问您指定的文件,就像它是您的应用程序一样,但在Jelly Bean之前,视频视图试图打开文件在自己的上下文中(不是您的应用程序).由于模式是私有的,因此失败.

一种解决方案是使用Context.MODE_WORLD_READABLE编写您的文件,该文件现已弃用.这表示任何人都可以在该路径上打开该文件.这显然是不安全和沮丧的.

我最终创建了一个内容提供程序和我自己的URI来处理这种情况.特别:

AndroidManfest.xml:

...
    <provider
        android:name="com.myexampleapp.video.VideoProvider"
            android:authorities="com.myexampleapp.video.VideoProvider.files"
        android:exported="false" />
    </application>
</manifest>
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我访问我的视频文件:

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

这是一种非常冗长的方式,告诉VideoView向ContentProvider询问数据的文件描述符.文件描述符未经许可,因此您使用应用程序的权限打开文件并将其交给VideoView,而不是要求VideoView使用自己的权限打开文件.

这也解决了我的问题,希望也是你的问题!