HarmonyOS 鸿蒙Next 使用硬编码264数据问题:1280*720可正常编码,720*1280编码后出现画屏

发布于 1周前 作者 htzhanglong 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 使用硬编码264数据问题:1280720可正常编码,7201280编码后出现画屏

如题,使用下面代码初始化编码器

this->capability = OH_AVCodec_GetCapability( OH_AVCODEC_MIMETYPE_VIDEO_AVC, true );

ExecFuncRet( WEBRTC_VIDEO_CODEC_ENCODER_FAILURE, OH_AVCapability_GetEncoderBitrateRange, capability, &supportBitrateRange_ );

codec_.startBitrate = std::max(std::min((int32_t)codec_.startBitrate,supportBitrateRange_.maxVal),supportBitrateRange_.minVal);

codec_.minBitrate = std::max(std::min((int32_t)codec_.minBitrate,supportBitrateRange_.maxVal),supportBitrateRange_.minVal);

codec_.maxBitrate = std::max(std::min((int32_t)codec_.maxBitrate,supportBitrateRange_.maxVal),supportBitrateRange_.minVal);

const char* codecName = OH_AVCapability_GetName( capability );

encoder_ = OH_VideoEncoder_CreateByName( codecName );

if ( encoder_ == nullptr ) {

RTC_LOG( LS_ERROR ) << TAG “OH_VideoEncoder_CreateByName fail”;

return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;

}

// 1. 确认视频宽高是否支持

bool isSupported = OH_AVCapability_IsVideoSizeSupported(this->capability, codec_.width, codec_.height);

if ( !isSupported ) {

int32_t widthAlignment = 0;

ExecFunc(OH_AVCapability_GetVideoWidthAlignment,capability, &widthAlignment);

// 3. 确认视频宽处在可支持宽范围内

OH_AVRange widthRange = {-1, -1};

ExecFunc(OH_AVCapability_GetVideoWidthRange,capability, &widthRange);

// 5. 基于视频宽,获取可选视频高的范围

OH_AVRange heightRange = {-1, -1};

ExecFunc( OH_AVCapability_GetVideoHeightRangeForWidth, capability, codec_.width, &heightRange );

RTC_LOG( LS_ERROR ) << TAG “OH_AVCapability_IsVideoSizeSupported fail:” << codec_.width << “x” << codec_.height << " WidthAlignment:" << widthAlignment

<< " WidthRange:" << widthRange.minVal << “-” << widthRange.maxVal << " HeightRange:" << heightRange.minVal << “-” << heightRange.maxVal;

return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;

}

OH_AVFormat* format = OH_AVFormat_Create();

if ( format == nullptr ) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_Create fail”;

return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;

}

// 写入format

if ( !OH_AVFormat_SetIntValue( format, OH_MD_KEY_WIDTH, codec_.width ) ) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_WIDTH fail”;

}

if (!OH_AVFormat_SetIntValue( format, OH_MD_KEY_HEIGHT, codec_.height )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_HEIGHT fail”;

}

if (!OH_AVFormat_SetDoubleValue( format, OH_MD_KEY_FRAME_RATE, codec_.maxFramerate )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_FRAME_RATE fail”;

}

if (!OH_AVFormat_SetIntValue( format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_YUVI420 )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_PIXEL_FORMAT fail”;

}

if (!OH_AVFormat_SetIntValue( format, OH_MD_KEY_RANGE_FLAG, 1 )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_RANGE_FLAG fail”;

}

if (!OH_AVFormat_SetIntValue( format, OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY, 1 )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY fail”;

}

if (!OH_AVFormat_SetIntValue( format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, OH_VideoEncodeBitrateMode::CBR )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE CBR fail”;

}

if (!OH_AVFormat_SetLongValue( format, OH_MD_KEY_BITRATE, 500000 )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_BITRATE fail:” << codec_.startBitrate;

}

uint32_t key_frame_interval = 3000;

std::string key_frame_interval_str = jrtc_sdk_get_config_by_key( “key_frame_interval” );

if ( key_frame_interval_str.length() > 0 ) {

key_frame_interval = atoi( key_frame_interval_str.c_str() );

}

if(!OH_AVFormat_SetIntValue( format, OH_MD_KEY_I_FRAME_INTERVAL, key_frame_interval )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_I_FRAME_INTERVAL fail:” << key_frame_interval;

}

if(!OH_AVFormat_SetIntValue( format, OH_MD_KEY_PROFILE, static_cast< int32_t >( OH_AVCProfile::AVC_PROFILE_BASELINE ) )) {

RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_PROFILE fail:” << key_frame_interval;

}

//TODO 设置QP

// if (!OH_AVFormat_SetIntValue( format, OH_MD_KEY_VIDEO_ENCODER_QP_MAX, codec_.qpMax )) {

// RTC_LOG( LS_ERROR ) << TAG “OH_AVFormat_SetIntValue OH_MD_KEY_VIDEO_ENCODER_QP_MAX fail:” << codec_.qpMax;

// }

RTC_LOG( LS_INFO ) << TAG “Init OHOS HardWare Codec:”<< encoder_ << " " << codec_.width << “x” << codec_.height << " " << codec_.maxFramerate << "fps " << codec_.startBitrate

<< "bps " << codec_.qpMax << “qpMax EncoderSupport:” << supportBitrateRange_.minVal << " - " << supportBitrateRange_.maxVal << “bps KeyFrameInterval:” << key_frame_interval;

// OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS,

// static_cast<int32_t>(OH_TransferCharacteristic::TRANSFER_CHARACTERISTIC_BT709));

// OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES,

// static_cast<int32_t>(OH_ColorPrimary::COLOR_PRIMARY_BT709));

ExecFuncRet( WEBRTC_VIDEO_CODEC_ENCODER_FAILURE, OH_VideoEncoder_Configure, encoder_, format );

OH_AVFormat_Destroy( format );

看日志初始化也没有报错,而且也在编码前dump下来YUV数据是没有问题的,但是就是如果是7201280的数据就是花的,1280720就没有问题

7201280的数据是采集来1280720(鸿蒙摄像头采集参数没有7201280,只有1280720的格式)进行旋转的到的,旋转时将采集的nv21数据转成I420格式的,所以使用AV_PIXEL_FORMAT_YUVI420


更多关于HarmonyOS 鸿蒙Next 使用硬编码264数据问题:1280*720可正常编码,720*1280编码后出现画屏的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

获取跨距,然后按行拷贝
1.获取跨距
API 12 新增以下方式获取跨距:

// 解码场景,收到输出 Buffer 后
OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(decoder);
int widthStride = 0;
int32_t heightStride = 0;
bool ret = OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, widthStride);
if (ret) {
// Error
}
bool ret = OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, heightStride);
if (ret) {
// Error
}
OH_AVFormat_Destroy(format);

// 编码场景,收到输入 Buffer 后 OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(encoder); int widthStride = 0; bool ret = OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, widthStride); if (ret) { // Error } OH_AVFormat_Destroy(format);

2.按行拷贝:
参考实现:

int32_t ReadYUV420P(std::shared_ptr<VideoEncSignal> &signal, uint8_t *addr, int32_t width, int32_t height, int32_t stride){
if (width == 0) {
return 0;
}
int32_t pixelSize = int32_t(stride / width);
width *= pixelSize;
// Y
for (int32_t i = 0; i < height; ++i) {
signal->inFile_->read(reinterpret_cast<char *>(addr), width);
addr += stride;
}
width >>= 1;
stride >>= 1;
// UV
for (int32_t i = 0; i < height; ++i) {
signal->inFile_->read(reinterpret_cast<char *>(addr), width);
addr += stride;
}
return stride * height * 3 / 2; // 3: nom, 2: denom
}

更多关于HarmonyOS 鸿蒙Next 使用硬编码264数据问题:1280*720可正常编码,720*1280编码后出现画屏的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


使用VLC播放编码的264数据长这样

在HarmonyOS鸿蒙Next系统中,使用硬编码H.264数据时,若遇到1280720分辨率正常而7201280分辨率编码后出现画屏的问题,通常可能由以下几个原因引起:

  1. 编码器支持限制:部分硬件编码器对特定分辨率支持有限,尤其是非标准或非常见分辨率。720*1280可能不在编码器的原生支持列表中。

  2. 内存对齐问题:编码过程中,图像数据需要按照特定对齐要求处理。720*1280可能不满足这些对齐条件,导致数据访问异常。

  3. 编码参数配置:编码参数如比特率、帧率、GOP结构等,对于不同分辨率需调整优化。未正确配置可能导致编码异常。

  4. 驱动或固件问题:硬件驱动或固件可能存在缺陷,不支持或错误处理某些分辨率。

解决方法:

  • 尝试使用标准分辨率如1280720或19201080进行编码。
  • 检查并调整编码参数,确保符合硬件要求。
  • 更新硬件驱动或固件至最新版本。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部