使用Android NDK Camera API编码视频出现画面全绿问题求助
问题排查与修复方案
核心问题分析
录制视频画面全绿的本质是YUV420数据的UV分量未正确传递给编码器,解码器会将缺失的UV通道默认填充为0(对应视觉上的绿色)。结合你的代码,主要存在以下几个关键问题:
具体修复点
1. 完整拷贝YUV三个平面的数据
你当前仅拷贝了Y平面(索引0),但YUV420_888格式包含Y、U、V三个独立平面,必须全部传入编码器。修改image_reader_on_image_available中的数据拷贝逻辑:
// 需要确保width、height为全局可访问变量,或从上下文传入 extern int32_t width, height; if (inputBufferIdx >= 0) { LOGI("dequeue input buffer (size: %u)", bufferSize); int dataSizeTotal = 0; // 处理Y平面(索引0) uint8_t* yData = NULL; int ySize = 0; int yRowStride = 0; AImage_getPlaneData(image, 0, &yData, &ySize); AImage_getPlaneRowStride(image, 0, &yRowStride); // 逐行拷贝Y数据(stride可能大于width,避免冗余数据) for (int i = 0; i < height; i++) { memcpy(inputBuffer + i * width, yData + i * yRowStride, width); } dataSizeTotal += height * width; // 处理U平面(索引1) uint8_t* uData = NULL; int uSize = 0; int uRowStride = 0; int uPixelStride = 0; AImage_getPlaneData(image, 1, &uData, &uSize); AImage_getPlaneRowStride(image, 1, &uRowStride); AImage_getPixelStride(image, 1, &uPixelStride); int uHeight = (height + 1) / 2; int uWidth = (width + 1) / 2; // 拷贝U平面数据 for (int i = 0; i < uHeight; i++) { for (int j = 0; j < uWidth; j++) { inputBuffer[dataSizeTotal + i * uWidth + j] = uData[i * uRowStride + j * uPixelStride]; } } dataSizeTotal += uHeight * uWidth; // 处理V平面(索引2) uint8_t* vData = NULL; int vSize = 0; int vRowStride = 0; int vPixelStride = 0; AImage_getPlaneData(image, 2, &vData, &vSize); AImage_getPlaneRowStride(image, 2, &vRowStride); AImage_getPixelStride(image, 2, &vPixelStride); int vHeight = (height + 1) / 2; int vWidth = (width + 1) / 2; // 拷贝V平面数据 for (int i = 0; i < vHeight; i++) { for (int j = 0; j < vWidth; j++) { inputBuffer[dataSizeTotal + i * vWidth + j] = vData[i * vRowStride + j * vPixelStride]; } } dataSizeTotal += vHeight * vWidth; int64_t timestamp = 0; AImage_getTimestamp(image, ×tamp); // 传入实际总数据大小,而非缓冲区总大小 AMediaCodec_queueInputBuffer(mediaCodec, inputBufferIdx, 0, dataSizeTotal, timestamp, 0); }
2. 修正编码器ColorFormat配置
COLOR_FormatYUV420Flexible为兼容格式,部分设备编码器对其支持不佳,建议改用明确的平面格式:
// 替换原ColorFormat设置 AMediaFormat_setInt32(mediaFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, AMEDIACODEC_COLOR_FormatYUV420Planar);
3. 修复输入缓冲区参数错误
你之前调用AMediaCodec_queueInputBuffer时传入的bufferSize是编码器输入缓冲区的总大小,但实际拷贝的数据仅为Y平面大小,会导致编码器读取无效数据。改用上述代码中计算的dataSizeTotal作为实际数据长度。
4. 验证时间戳正确性
确认AImage_getTimestamp返回的时间戳单位为微秒,若单位不符需转换,避免编码器时序错误导致画面异常。
额外适配建议
- 若编码器配置失败,可枚举当前设备支持的编码器格式进行适配:
AMediaCodecInfo* codecInfo = AMediaCodec_createCodecInfoByName("OMX.google.h264.encoder"); const AMediaFormat* const* formats = AMediaCodecInfo_getSupportedInputFormats(codecInfo); for (int i = 0; formats[i]; i++) { LOGI("Supported input format: %s", AMediaFormat_toString(formats[i])); } AMediaCodecInfo_delete(codecInfo);
内容的提问来源于stack exchange,提问作者gatosempai
相关产品推荐
相关产品推荐

