我从文件路径设置VideoView的视频时遇到了不一致的经历。
VideoView myVideoView = findViewById(R.id.videoView);
...
myVideoView.setVideoPath(videoFilename);
...
myVideoView.start();
videoFilename是我的缓存目录中视频的绝对路径:
String videoFilename = new File(context.getCacheDir(), "myawesomevideo.mp4").getAbsolutePath();
在Android SDK> = 16(Jelly Bean)中,这很好用,我的精彩视频播放。在Android 4.0.4(SDK = 15)中,当调用myVideoView.start()时,MediaPlayer会中断。
错误永无止境:
error (1, -2147483648)
我在这里缺少什么?直接从我的包资产(res / raw)或互联网(http://something.com/myawesomeinternetvideo.mp4)加载文件,但我无法弄清楚如何从缓存目录中读取文件!
答案 0 :(得分:15)
事实证明,错误-2147483648表示未知错误。这可能与视频编码有关,但也值得检查文件路径是否存在并且VideoView有权阅读它。
我的问题是我用Context.MODE_PRIVATE(默认值)编写我的文件。
openFileOutput(filename, Context.MODE_PRIVATE);
这表示只有您的应用程序才能访问该文件。我不知道具体如何或为什么,但在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>
<强> 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();
}
}
然后,我访问我的视频文件:
VideoView myVideoView = findViewById(R.id.videoView);
...
myVideoView.setVideoURI(
Uri.parse(
CachedActionProvider.CONTENT_URI_BASE + Uri.encode(videoFilename)));
...
myVideoView.start();
这是一种非常冗长的方式,告诉VideoView向ContentProvider询问数据的文件描述符。文件描述符未经许可,因此您使用应用程序的权限打开文件并将其交给VideoView,而不是让VideoView使用自己的权限打开文件。
这解决了我的问题,希望也是你的问题!
答案 1 :(得分:4)
从cache-directory加载视频文件时我也遇到了这个问题。这个问题似乎只出现在Nexus设备上,但我不打算在很多设备上进行测试。
我尝试使用Context.MODE_WORLD_READABLE编写该文件,但该修复程序对我不起作用。 VideoProvider.java也没有修复它。
所以我找到了另一个对我有用的解决方案。我在我的Activity中创建了一个tempFile,并为VideoView提供了绝对路径。
也许我的代码可以帮助某人:)
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));
}
}