我正在尝试使用 cpp 中的 mediacodec 库在 Android 中实现转码管道。我有一个在表面模式下运行的 h265 解码器。我通过在配置解码器时删除表面参数将其更改为缓冲模式。 现在我可以看到输出缓冲区在解码后有一些数据。我的计划是使用输出缓冲区并将其复制到 h264 编码器的输入中。
我看到的问题是解码器的输出缓冲区的大小大于编码器的输入缓冲区的大小。我检查过两者之间的颜色格式是否相同。我不确定为什么会有差异。 对于 YUV420 格式的 1080p 视频,缓冲区的大小应该是
Y Plane Size: 2,073,600 bytes
U Plane Size: 518,400 bytes
V Plane Size: 518,400 bytes
Total Frame Size: 2,073,600 + 518,400 + 518,400 = 3,110,400 bytes
配置编码器的代码片段:
AMediaFormat* avc_format = AMediaFormat_new();
AMediaFormat_setString(avc_format, AMEDIAFORMAT_KEY_MIME, "video/avc");
AMediaFormat_setInt32(avc_format, AMEDIAFORMAT_KEY_WIDTH, 1920);
AMediaFormat_setInt32(avc_format, AMEDIAFORMAT_KEY_HEIGHT, 1080);
AMediaFormat_setInt32(avc_format, AMEDIAFORMAT_KEY_BIT_RATE, 17000000);
AMediaFormat_setInt32(avc_format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1);
AMediaFormat_setFloat(avc_format, AMEDIAFORMAT_KEY_FRAME_RATE, 30.0);
AMediaFormat_setInt32(avc_format, AMEDIAFORMAT_KEY_COLOR_FORMAT, 21);
avc_encoder_ = AMediaCodec_createCodecByName("OMX.qcom.video.encoder.avc");
AMediaCodec_configure(
avc_encoder_, avc_format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
获取缓冲区的代码片段:
ssize_t codec_out_buf_idx = AMediaCodec_dequeueOutputBuffer(hevc_decoder_ &info, timeout);
ssize_t bufidx = AMediaCodec_dequeueInputBuffer(avc_encoder_, timeout);
if (bufidx >= 0) {
uint8_t* buf = AMediaCodec_getInputBuffer(avc_encoder_, bufidx, &bufsize);
size_t codec_out_bufsize = 0;
uint8_t* codec_out_buf = AMediaCodec_getOutputBuffer(hevc_decoder_, codec_out_buf_idx, &codec_out_bufsize);
if (codec_out_bufsize > bufsize) {
return;
}
}
我看到的问题是解码器的输出缓冲区的大小大于编码器的输入缓冲区的大小。我检查过两者之间的颜色格式是否相同。我不确定为什么会有差异。 但我看到解码器输出缓冲区大小 3133440 大于输入缓冲区大小 3110400。 另外,关于解码器的输出格式更改回调,我得到了这个:
Output format changed
Width: 1920, Height: 1080
Frame Rate: 30
Color Format: 21
MIME Type: video/raw
我尝试了不同的颜色格式,但我检查了编码器和解码器之间的颜色格式是否匹配。知道为什么缓冲区大小不同吗?有更好的方法吗?
一些解码器更喜欢使用尺寸为 16 倍数的缓冲区(可能是因为它们使用 16 x 16 像素块)。
因此,在您的情况下,解码器分配尺寸为 1920 x 1088 的缓冲区(因为 1080 不是 16 的倍数),导致缓冲区大小为 3,133,440 字节。并且填充应该被忽略。
当解码器配置为“表面模式”时,这不是问题。
在“缓冲区模式”下,来自解码器缓冲区的数据必须复制到编码器缓冲区。但编码器根据给定的视频尺寸分配缓冲区,从而导致缓冲区较小。
解决此问题的一种方法是考虑给定的裁剪矩形逐行复制数据。