native_window_api_connect返回错误:参数无效(-22)

saa*_*saa 8 android android-mediaplayer mediacodec

我正在使用MediaCodec API编写视频播放器应用程序.我必须在视频解码开始前显示空白屏幕.所以我使用以下代码显示空白屏幕.

Canvas c=null;
            c = surfaceView.getHolder().lockCanvas();
            c.drawColor(Color.BLACK);
            surfaceView.getHolder().unlockCanvasAndPost(c);
Run Code Online (Sandbox Code Playgroud)

此视频解码将开始.但在配置时

videoDecoder.configure(format, surfaceView.getHolder().getSurface(), null, 0);
Run Code Online (Sandbox Code Playgroud)

它给出了以下错误

02-03 03:52:37.542: E/MediaCodec(9655): native_window_api_connect returned an error: Invalid argument (-22)
02-03 03:52:37.542: E/Video Decoder Configuration(9655): java.lang.IllegalStateException
Run Code Online (Sandbox Code Playgroud)

所以我的应用程序因该错误而崩溃.没有那个空白屏幕代码解码器工作正常.我该如何解决这个问题?

fad*_*den 7

这是我的理论,基于对框架代码的快速浏览.

Canvas锁定操作(最终)调用Surface::lock()(此处代码).这有一段代码说:

if (!mConnectedToCpu) {
    int err = Surface::connect(NATIVE_WINDOW_API_CPU);
Run Code Online (Sandbox Code Playgroud)

这是将"CPU生产者"(即在CPU上运行并生成图形数据的代码)连接到缓冲区队列的生产者端,该缓冲队列将提供给Surface.该生产者没有断开连接unlockAndPost().您实际上可以在Surface析构函数中找到断开连接调用,这对于您的目的而言有点晚.

您不能在一个缓冲区队列上有两个生成器,因此当您将Surface传递给MediaCodec解码器时,它无法连接.

我相信你有几个选择:

  1. 使用OpenGL ES清空表面.当你摧毁EGLSurface它时会断开连接.这需要设置EGL/GLES并获得正确的EGL发布代码.
  2. 使用除了绘制SurfaceView自身之外的方法(h/t我的办公室伙伴)建立一个空白矩形.

对于方法#2,您只需要第二个视图(可能是一个ImageView),其位置和尺寸与其相同SurfaceView,并用不透明的黑色填充.该SurfaceView图层始终位于其他所有位置(假设您尚未将其配置为位于顶部),因此UI元素将在其上绘制.当开始播放电影时,您将禁用其他视图.

更新:你现在可以看到格拉菲卡的方法#1 .在"播放电影(SurfaceView)"活动中,它会创建EGL上下文,清除曲面并破坏上下文.(有必要立即销毁EGL上下文并避免出现"两个生产者"问题.)

  • 我让它工作了。非常感谢!我已经写了一个片段来做到这一点并将其留在这里。我希望这对其他人有帮助。https://gist.github.com/hisui/433e09e899175844cfc4 (3认同)
  • 我可以写一本关于通过阅读你 @fadden 的答案来解决我的问题的所有时间的书。您的贡献和工作是宝贵的资源,感谢您的分享!我喜欢有时你的同事会突然出现在这些答案中,通常会带来一些棘手的解决方案或不同的观点。几乎感觉我认识你们两个。谢谢! (3认同)