Android 视频解码器仅在棒棒糖上不绘制到 gles 表面
Android video decoder not drawing to gles surface on lollipop only
简而言之,我将两个开源应用程序合并到一个新的 VR 应用程序中,因此它只能在使用 GearVR 耳机的 Note 4 和 S6 上运行。我的应用程序适用于 kitkat,但视频在棒棒糖上是黑色的。这两个源应用程序在棒棒糖上都运行良好。
我有一个由 gl 纹理创建的表面:
glGenTextures( 1, &textureId );
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
将其放入 SurfaceTexture 中,再将其放入 Surface 中,经过一些传递,然后发送到视频解码器:
videoDecoder = MediaCodec.createByCodecName(decoderName);
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
// OMX.qcom.video.decoder.avc gets picked for decodername
// Width and height at 1280x720 everywhere
纹理已更新并绑定到表面并进行渲染。
这在 kitkat 上非常有效。在棒棒糖上,视频是全黑的。
您可以在此处查看日志的差异(好的 kitkat 红色,坏的棒棒糖绿色):
https://www.diffchecker.com/lxxopmhc
对我来说没有什么特别有用。
(我能找到的消息 do not know color format 0x7fa30c04 = 2141391876
只是来自将解码器 ID 转换为名称的东西,不应该影响任何东西。另一个解码器不提供此消息,但也不起作用。)
向 MediaFormat 添加明确的颜色格式,并在其他地方摆弄颜色格式和图像大小没有任何效果(只有黑屏,没有错误)
我可以在表面上锁定一个canvas并绘制ARGB(255,0,255,0),屏幕变绿。
我创建了一个表面的子类,它记录了每个 public 方法并将其传递给解码器,其中 none 在 kitkat 上被调用(除了我创建它时的初始化)或棒棒糖,工作与否,所以这根本没有告诉我任何事情。
用于设置视频解码器的代码来自 Moonlight,它在棒棒糖上运行得非常好:
github.com/moonlight-stream/moonlight-android
另一半是 Oculus Cinema,它使用 android.media.MediaPlayer 在 Surface 上显示并且在棒棒糖上运行良好。
所以我的问题是棒棒糖发生了什么变化或者我做错了什么,我该如何进一步调试这个问题?
我的代码在这里:
https://github.com/GTMoogle/StreamTheater
6 月 2 日更新:
尝试按照 http://bigflake.com/mediacodec/ Q11 的建议设置缓冲区位置和限制,但仍然没有输出,尽管我可能实施不正确。也处理了一些depricated调用,同样没有效果。
Up-Update:dequeueOutputBuffer 的 BufferInfo 似乎总是大小为 8,偏移量为 0,未设置标志。还不确定健康的流是什么样子。
啊哈。终于找到了。
出于某种原因,updateTexImage 没有更改表面纹理的时间戳。 Mediacodec 在 kitkat 上设置它,所以输入缓冲区没有正确设置时间戳并且 mediacodec 正在清理它,或者 mediacodec 在更新纹理时不再设置它?
我可以调试它,但我至少可以暂时只更新而不是检查时间戳是否更改。
简而言之,我将两个开源应用程序合并到一个新的 VR 应用程序中,因此它只能在使用 GearVR 耳机的 Note 4 和 S6 上运行。我的应用程序适用于 kitkat,但视频在棒棒糖上是黑色的。这两个源应用程序在棒棒糖上都运行良好。
我有一个由 gl 纹理创建的表面:
glGenTextures( 1, &textureId );
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
将其放入 SurfaceTexture 中,再将其放入 Surface 中,经过一些传递,然后发送到视频解码器:
videoDecoder = MediaCodec.createByCodecName(decoderName);
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
// OMX.qcom.video.decoder.avc gets picked for decodername
// Width and height at 1280x720 everywhere
纹理已更新并绑定到表面并进行渲染。
这在 kitkat 上非常有效。在棒棒糖上,视频是全黑的。
您可以在此处查看日志的差异(好的 kitkat 红色,坏的棒棒糖绿色):
https://www.diffchecker.com/lxxopmhc
对我来说没有什么特别有用。
(我能找到的消息 do not know color format 0x7fa30c04 = 2141391876
只是来自将解码器 ID 转换为名称的东西,不应该影响任何东西。另一个解码器不提供此消息,但也不起作用。)
向 MediaFormat 添加明确的颜色格式,并在其他地方摆弄颜色格式和图像大小没有任何效果(只有黑屏,没有错误)
我可以在表面上锁定一个canvas并绘制ARGB(255,0,255,0),屏幕变绿。
我创建了一个表面的子类,它记录了每个 public 方法并将其传递给解码器,其中 none 在 kitkat 上被调用(除了我创建它时的初始化)或棒棒糖,工作与否,所以这根本没有告诉我任何事情。
用于设置视频解码器的代码来自 Moonlight,它在棒棒糖上运行得非常好:
github.com/moonlight-stream/moonlight-android
另一半是 Oculus Cinema,它使用 android.media.MediaPlayer 在 Surface 上显示并且在棒棒糖上运行良好。
所以我的问题是棒棒糖发生了什么变化或者我做错了什么,我该如何进一步调试这个问题?
我的代码在这里:
https://github.com/GTMoogle/StreamTheater
6 月 2 日更新:
尝试按照 http://bigflake.com/mediacodec/ Q11 的建议设置缓冲区位置和限制,但仍然没有输出,尽管我可能实施不正确。也处理了一些depricated调用,同样没有效果。
Up-Update:dequeueOutputBuffer 的 BufferInfo 似乎总是大小为 8,偏移量为 0,未设置标志。还不确定健康的流是什么样子。
啊哈。终于找到了。
出于某种原因,updateTexImage 没有更改表面纹理的时间戳。 Mediacodec 在 kitkat 上设置它,所以输入缓冲区没有正确设置时间戳并且 mediacodec 正在清理它,或者 mediacodec 在更新纹理时不再设置它?
我可以调试它,但我至少可以暂时只更新而不是检查时间戳是否更改。