对于 1080p 视频,MediaCodec.configure 失败并出现 IllegalStateException

2024-06-12

我一直在使用grafika的电影播放器 https://github.com/google/grafika/blob/master/src/com/android/grafika/MoviePlayer.java和大弗莱克的提取Mpeg帧测试 http://bigflake.com/mediacodec/ExtractMpegFramesTest_egl14.java.txt在我们的应用程序中实现搜索和提取帧功能。这些对于我们的大多数用户来说工作得很好,但是他们中的一些人遇到了IllegalStateException on MediaCodec.configure设置时ExtractMpegFramesTest(这种情况发生在三星 Galaxy S4 mini、三星 Galaxy J7、三星 Galaxy A5、华为 Ascend G7 上)。相关代码如下:

MoviePlayer

public void prepareResources() throws IOException {
    // The MediaExtractor error messages aren't very useful.  Check to see if the input
    // file exists so we can throw a better one if it's not there.
    if (!mSourceFile.canRead()) {
        throw new FileNotFoundException("Unable to read " + mSourceFile);
    }

    try {
        mExtractor = new MediaExtractor();
        mExtractor.setDataSource(mSourceFile.toString());
        mTrackIndex = selectTrack(mExtractor);
        if (mTrackIndex < 0) {
            throw new RuntimeException("No video track found in " + mSourceFile);
        }
        mExtractor.selectTrack(mTrackIndex);

        MediaFormat format = mExtractor.getTrackFormat(mTrackIndex);

        // Create a MediaCodec decoder, and configure it with the MediaFormat from the
        // extractor.  It's very important to use the format from the extractor because
        // it contains a copy of the CSD-0/CSD-1 codec-specific data chunks.
        String mime = format.getString(MediaFormat.KEY_MIME);
        mDecoder = MediaCodec.createDecoderByType(mime);
        mDecoder.configure(format, mOutputSurface, null, 0);
        mDecoder.start();
        mDecoderInputBuffers = mDecoder.getInputBuffers();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

ExtractMpegFramesTest

private void extractMpegFrames() throws IOException {
    MediaCodec decoder = null;
    CodecOutputSurface outputSurface = null;
    MediaExtractor extractor = null;
    /*int saveWidth = 640;
    int saveHeight = 480;*/

    try {
        long start1 = System.currentTimeMillis();

        File inputFile = new File(mInputVideoPath);   // must be an absolute path
        // The MediaExtractor error messages aren't very useful.  Check to see if the input
        // file exists so we can throw a better one if it's not there.
        if (!inputFile.canRead()) {
            throw new FileNotFoundException("Unable to read " + inputFile);
        }

        extractor = new MediaExtractor();
        extractor.setDataSource(inputFile.toString());
        int trackIndex = selectTrack(extractor);
        if (trackIndex < 0) {
            throw new RuntimeException("No video track found in " + inputFile);
        }
        extractor.selectTrack(trackIndex);

        MediaFormat format = extractor.getTrackFormat(trackIndex);
        if (VERBOSE) {
            Log.d(TAG, "Video size is " + format.getInteger(MediaFormat.KEY_WIDTH) + "x" +
                    format.getInteger(MediaFormat.KEY_HEIGHT));
        }

        // Could use width/height from the MediaFormat to get full-size frames.
        outputSurface = new CodecOutputSurface(format.getInteger(MediaFormat.KEY_WIDTH), format.getInteger(MediaFormat.KEY_HEIGHT));

        // Create a MediaCodec decoder, and configure it with the MediaFormat from the
        // extractor.  It's very important to use the format from the extractor because
        // it contains a copy of the CSD-0/CSD-1 codec-specific data chunks.
        String mime = format.getString(MediaFormat.KEY_MIME);
        decoder = MediaCodec.createDecoderByType(mime);
        decoder.configure(format, outputSurface.getSurface(), null, 0); //fails right here
        decoder.start();

        long end1 = System.currentTimeMillis();
        Timber.d("extractMpegFrames(): FRAME_EXTRACT setup in: %d millis", (end1-start1));

        long start2 = System.currentTimeMillis();
        doExtract(extractor, trackIndex, decoder, outputSurface);
        long end2 = System.currentTimeMillis();
        Timber.d("extractMpegFrames(): FRAME_EXTRACT doExtract in: %d millis", (end2-start2));
    } finally {
        // release everything we grabbed
        if (outputSurface != null) {
            outputSurface.release();
            outputSurface = null;
        }
        if (decoder != null) {
            decoder.stop();
            decoder.release();
            decoder = null;
        }
        if (extractor != null) {
            extractor.release();
            extractor = null;
        }
    }
}

我知道这一点question https://stackoverflow.com/a/17243175/1602807,但我不明白的是为什么MediaCodec可以配置确定MoviePlayer(视频运行得很好)但失败了ExtractMpegFramesTest。起初,我认为设备的 OpenGL 设置存在一些问题,但结果是 MediaCodec 问题。

任何见解将不胜感激。

EDIT:获得 Galaxy S4 mini 测试设备后,我获得了更有用的日志:

D/MoviePlayer: Extractor selected track 0 (video/avc): {max-input-size=1572864, height=1080, csd-0=java.nio.ByteArrayBuffer[position=0,limit=20,capacity=20], width=1920, durationUs=5131211, csd-1=java.nio.ByteArrayBuffer[position=0,limit=9,capacity=9], mime=video/avc, isDMCMMExtractor=1}
D/MoviePlayer: Video size is 1920x1080
D/MoviePlayer: Extractor selected track 0 (video/avc): {max-input-size=1572864, height=1080, csd-0=java.nio.ByteArrayBuffer[position=0,limit=20,capacity=20], width=1920, durationUs=5131211, csd-1=java.nio.ByteArrayBuffer[position=0,limit=9,capacity=9], mime=video/avc, isDMCMMExtractor=1}
I/OMXClient: Using client-side OMX mux.
E/ACodec: [OMX.qcom.video.decoder.avc] storeMetaDataInBuffers failed w/ err -2147483648
E/ACodec:  configureCodec multi window instance fail  appPid : 3283
E/ACodec: [OMX.qcom.video.decoder.avc] configureCodec returning error -38
E/MediaCodec: Codec reported an error. (omx error 0x80001001, internalError -38)
W/System.err: java.lang.IllegalStateException
W/System.err:     at android.media.MediaCodec.native_configure(Native Method)
W/System.err:     at android.media.MediaCodec.configure(MediaCodec.java:262)
W/System.err:     at co.test.testing.player.MoviePlayer.prepareResources(MoviePlayer.java:237)
W/System.err:     at co.test.testing.activities.VideoActivity.surfaceCreated(VideoActivity.java:276)
W/System.err:     at android.view.SurfaceView.updateWindow(SurfaceView.java:602)
W/System.err:     at android.view.SurfaceView.access$000(SurfaceView.java:94)
W/System.err:     at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:183)
W/System.err:     at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:891)
W/System.err:     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2201)
W/System.err:     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1256)
W/System.err:     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6635)
W/System.err:     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:813)
W/System.err:     at android.view.Choreographer.doCallbacks(Choreographer.java:613)
W/System.err:     at android.view.Choreographer.doFrame(Choreographer.java:583)
W/System.err:     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:799)
W/System.err:     at android.os.Handler.handleCallback(Handler.java:733)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err:     at android.os.Looper.loop(Looper.java:146)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5593)
W/System.err:     at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err:     at java.lang.reflect.Method.invoke(Method.java:515)
W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
W/System.err:     at dalvik.system.NativeStart.main(Native Method)

这些是从有此问题的设备中检索到的编解码器信息:

  • OMX.qcom.video.encoder.avc

  • OMX.SEC.avc.enc

  • OMX.Exynos.AVC.编码器

奇怪的是 Galaxy S4 mini 可以很好地处理 720p 视频,只是处理 1080p 视频时出现问题。


好吧,在这里再次回答我自己的问题:

  • 首先,为什么我无法提取帧ExtractMpegFramesTest使用后MoviePlayer显示视频:

    某些设备似乎无法处理 2 个实例MediaCodec同时对于高分辨率视频(对于 Galaxy S4 mini,>720p),因此您必须正确释放一个实例MediaCodec在开始另一项之前,像这样:

    public void releaseResources() {
        // release everything we grabbed
        if (mDecoder != null) {
            try {
                mDecoder.stop();
                mDecoder.release();
                mDecoder = null;
            } catch (Exception e) {
                Timber.d("releaseResources(): message %s cause %s", e.getMessage(),  e.getCause());
                e.printStackTrace();
            }
        }
        if (mExtractor != null) {
            try {
                mExtractor.release();
                mExtractor = null;
            } catch (Exception e) {
                Timber.d("releaseResources(): message %s cause %s", e.getMessage(),  e.getCause());
                e.printStackTrace();
            }
        }
    }
    
  • 其次,为什么MoviePlayer无法配置 1080p 视频。就我而言,因为我从媒体选择器活动开始此活动,VideoView用于预览,其中有一个MediaPlayer.OnErrorListener()注册以检测有缺陷的视频。问题是onError()回调在 Galaxy S4 mini 上有一些非常奇怪的行为,而它在我的开发设备上工作得很好。我的疯狂猜测MediaPlayer.OnErrorListener()留下MediaCodec状态不好,以后会引起很多头痛。

    所以解决办法就是设置一个空白OnErrorListener()并正确释放VideoView在做任何其他事情之前MediaCodec。像这样的东西:

    mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                return true;
            }
    });
    .....
    mVideoView.stopPlayback();
    doOtherThingWithMediaCodec();
    

这解释了在不同设备上发生的许多奇怪的事情。我希望这可以帮助其他人调试他们的应用程序。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对于 1080p 视频,MediaCodec.configure 失败并出现 IllegalStateException 的相关文章

随机推荐

  • 检测控件是否已释放

    在我的应用程序中 我有一个使用线程池执行异步操作的用户控件 线程池方法如下 private void AsyncFunction object state do the calculation refresh the grid data o
  • 在 Access 表单上将控件分组在一起

    我有一个 Access2003 表单 我想将多个控件组合在一起并通过 VBA 代码以编程方式更改可见性 这可能吗 我确实知道我可以通过 格式 gt 组 对项目进行分组 但如果这样做 如何在代码中引用整个组 谢谢 您可以将所有控件放置在组框控
  • Android opengl在绘制调用后修改顶点数组

    在opengl中 绘制顶点数组后这是不好的做法还是不建议修改它 It s not如果在将顶点数组绘制为普通顶点数组时修改它 这是一种不好的做法 It s如果在绘制方法中使用顶点缓冲区对象 则修改顶点数组是不好的做法 这是因为编辑后您必须将其
  • RuntimeException:必须提供 MemberAccess 实现

    我正在使用一个访问公共字段的模板Customer像这样的对象 div div div div div div div div div div 然而 当我打电话时process on the TemplateEngine templateEn
  • 随机调用的联系人 ContentObserver

    我正在使用 ContentObserver 来监听联系人数据库中的更改 现在我意识到 onChange 方法会被随机调用 即使我没有对联系人进行任何更改 我怀疑这在某种程度上与自动联系人同步有关 即使此时联系人没有真正的更改 仅当用户对联系
  • 如何估计 std::map 的内存使用情况?

    例如 我有一个已知 sizeof A 和 sizeof B 的 std map 而 map 内部有 N 个条目 您如何估计其内存使用情况 我想说这就像 sizeof A sizeof B N factor 但到底是什么因素呢 也许不同的公式
  • 黄瓜(Java 中):如何仅使用两个标签运行场景

    我有一些功能文件 每个场景都有多个标签 但我想运行那些同时具有 a 和 b 场景的人 我怎样才能做到这一点 tags a b gt this will do a OR b scenarios Thanks 我想到了 Tags a b gt
  • spring boot测试如何获取服务器端口

    我有 Spring Boot 1 5 3 应用程序 有一条线server port 8081在 application properties 文件中 现在我想测试一下 ping 方法 private final Environment en
  • Cakephp 在 Bluehost 上安装

    如何设置 Cakephp 才能在 Bluehost 上正常工作 我应该将我的应用程序 cake 和供应商文件夹以及 htaccess 和 index php 文件放在 public html 目录中吗 我按照这里的说明进行操作 http b
  • 有效大括号 - CodeWars 挑战

    有一个对代码战的挑战 https www codewars com kata valid braces train javascript它要求您检查圆括号 方括号和大括号组成的字符串是否有效 如果所有大括号都与正确的大括号匹配 则认为一串大
  • 禁用淘汰排序中的单个项目

    在淘汰赛排序中 我知道您可以使用禁用可排序列表isEnabled in the sortable捆绑 我还知道您可以使用禁用移动项目cancelDrop in a beforeMove功能 问题是 isEnabled禁用整个列表 并且can
  • pytesseract 不从图像中提取文本

    我有以下图像并尝试使用 pytesseract 提取文本 但是 它总是返回一些未知的字符 Image 这是我正在使用的代码 import pytesseract as pt from PIL import Image Converting
  • 为什么operator = 返回*this?

    假设我想覆盖operator 所以我可以做类似的事情 Poly p1 an object representing a polynomial Poly p2 another object of the same type p2 p1 ass
  • 如何在模板参数列表中传递模板函数

    假设我有一个template功能 template
  • Google Drive api v3 响应为空

    我想尝试上传文件谷歌驱动器 我的代码在这里 public static File UploadFile DriveService service string fileName string filePath string descript
  • 在类内部和外部定义的模板类的成员函数之间的区别

    在类声明内部和外部为模板类定义成员函数之间有区别吗 里面定义 template
  • jQuery 独立于级别包装多个元素

    这是我在 stackoverflow 上的第一篇文章 到目前为止我总能在这里找到答案 但这次我找不到 这是我的 DOM 结构 div div div div div div div div div div 如何将 2 个或更多选定的 随机
  • .NET 有 BITS 模块吗?

    我一直在研究使用后台智能传输服务 http msdn microsoft com en us library aa362708 VS 85 aspx 我见过的大多数文章都说没有官方 NET 端口 但他们建议使用锐利比特 http www c
  • 如何根据输入的内容过滤组合框的内容?

    我们有一个包含 100 多个项目的组合框 当我们在组合框中输入字符时 我们想要过滤掉项目 例如 如果我们输入 ac 并单击下拉选项 那么我们希望它仅显示以 ac 开头的项目 我怎样才能做到这一点 也许您会更喜欢使用操作系统内置的自动完成功能
  • 对于 1080p 视频,MediaCodec.configure 失败并出现 IllegalStateException

    我一直在使用grafika的电影播放器 https github com google grafika blob master src com android grafika MoviePlayer java和大弗莱克的提取Mpeg帧测试