Подтвердить что ты не робот

Ошибка Android MediaPlayer/VideoView (1, -2147483648)

У меня был непоследовательный опыт установки видео 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) MediaPlayer прерывается при вызове myVideoView.start().

Ошибка всегда бесполезна:

error (1, -2147483648)

Что мне здесь не хватает? Загрузка файла непосредственно из моих активов пакета (res/raw) или Интернета (http://something.com/myawesomeinternetvideo.mp4), но я не могу понять, как читать файлы из моего каталога кеша!

4b9b3361

Ответ 1

Как оказалось, ошибка -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 открывал файл, используя свои собственные разрешения.

Это также исправляет мою проблему и, надеюсь, ваш!

Ответ 2

У меня также была эта проблема при загрузке видеофайла из каталога cache. Проблема, казалось, возникала только на устройствах Nexus, но я не тестировал их на многих устройствах.

Я попытался написать файл с Context.MODE_WORLD_READABLE, но это исправление не сработало для меня. VideoProvider.java также не исправил его.

Итак, я нашел другое решение, которое сработало для меня. Я создал 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));
    }
}