HarmonyOS 鸿蒙Next 使用AVScreenCapture录屏取原始码流(C/C++)代码片段录制H264流报错

发布于 1周前 作者 phonegap100 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 使用AVScreenCapture录屏取原始码流(C/C++)代码片段录制H264流报错

    // 实例化ScreenCapture
capture = OH_AVScreenCapture_Create();

<span class="hljs-comment"><span class="hljs-comment">// 设置回调 </span></span>
OH_AVScreenCapture_SetErrorCallback(capture, OnError, <span class="hljs-keyword"><span class="hljs-keyword">NULL</span></span>);
OH_AVScreenCapture_SetStateCallback(capture, OnStateChange, <span class="hljs-keyword"><span class="hljs-keyword">NULL</span></span>);
OH_AVScreenCapture_SetDataCallback(capture, OnBufferAvailable, <span class="hljs-keyword"><span class="hljs-keyword">NULL</span></span>);

OH_VideoCaptureInfo videoCapInfo = {
    .videoFrameWidth = <span class="hljs-number"><span class="hljs-number">720</span></span>,
    .videoFrameHeight = <span class="hljs-number"><span class="hljs-number">1080</span></span>,
    .videoSource = OH_VIDEO_SOURCE_SURFACE_YUV
};

OH_VideoEncInfo videoEncInfo = {
    .videoCodec = OH_H264,
    .videoBitrate = <span class="hljs-number"><span class="hljs-number">2000000</span></span>,
    .videoFrameRate = <span class="hljs-number"><span class="hljs-number">30</span></span>
};

OH_VideoInfo videoInfo = {
    .videoCapInfo = videoCapInfo,
    .videoEncInfo = videoEncInfo
};

OH_AVScreenCaptureConfig config = {
    .captureMode = OH_CAPTURE_HOME_SCREEN,
    .dataType = OH_ENCODED_STREAM,
    .audioInfo = <span class="hljs-keyword"><span class="hljs-keyword">NULL</span></span>,
    .videoInfo = videoInfo,
};
OH_AVScreenCapture_Init(capture, config);

<span class="hljs-comment"><span class="hljs-comment">// 开始录屏</span></span>
OH_AVSCREEN_CAPTURE_ErrCode err = OH_AVScreenCapture_StartScreenCapture(capture);
OH_LOG_INFO(LOG_APP, <span class="hljs-string"><span class="hljs-string">"DEMO OH_AVScreenCapture_StartScreenCapture %{public}i"</span></span>,err);

<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

我使用官方的代码片段进行录制全屏的H264流数据, 启动时报错AV_SCREEN_CAPTURE_ERR_OPERATE_NOT_PERMIT,我是啥没有传对?

3 回复

可以参考这个代码:

// 开始录屏原始码流
static napi_value StartScreenCapture_01(napi_env env, napi_callback_info info) {
    g_avCapture = OH_AVScreenCapture_Create();
    if (g_avCapture == nullptr) {
        OH_LOG_ERROR(LOG_APP, "create screen capture failed");
    }
    OH_AVScreenCaptureConfig config_;
    SetConfig(config_);
    OpenFile("Demo");
    bool isMicrophone = true;
    OH_AVScreenCapture_SetMicrophoneEnabled(g_avCapture, isMicrophone);
    OH_AVScreenCapture_SetErrorCallback(g_avCapture, OnError, nullptr);
    OH_AVScreenCapture_SetStateCallback(g_avCapture, OnStateChange, nullptr);
    OH_AVScreenCapture_SetDataCallback(g_avCapture, OnBufferAvailable, nullptr);
    int result = OH_AVScreenCapture_Init(g_avCapture, config_);
    if (result != AV_SCREEN_CAPTURE_ERR_OK) {
        OH_LOG_INFO(LOG_APP, "==DEMO== ScreenCapture OH_AVScreenCapture_Init failed %{public}d", result);
    }
    OH_LOG_INFO(LOG_APP, "==DEMO== ScreenCapture OH_AVScreenCapture_Init %{public}d", result);
result = OH_AVScreenCapture_StartScreenCapture(g_avCapture);
<span class="hljs-keyword">if</span> (result != AV_SCREEN_CAPTURE_ERR_OK) {
    OH_LOG_INFO(LOG_APP, <span class="hljs-string">"==DEMO== ScreenCapture Started failed %{public}d"</span>, result);
    OH_AVScreenCapture_Release(g_avCapture);
}
OH_LOG_INFO(LOG_APP, <span class="hljs-string">"==DEMO== ScreenCapture Started %{public}d"</span>, result);

m_isRunning = <span class="hljs-literal">true</span>;

napi_value res;
napi_create_int32(env, result, &amp;res);
<span class="hljs-keyword">return</span> res;

}

// 开始录屏原始码流SurfaceMode static napi_value StartScreenCapture_03(napi_env env, napi_callback_info info) { g_avCapture = OH_AVScreenCapture_Create(); if (g_avCapture == nullptr) { OH_LOG_ERROR(LOG_APP, “create screen capture failed”); } OH_AVScreenCaptureConfig config_; SetConfig(config_); OpenFile(“Demo”); bool isMicrophone = true; OH_AVScreenCapture_SetMicrophoneEnabled(g_avCapture, isMicrophone); OH_AVScreenCapture_SetErrorCallback(g_avCapture, OnError, nullptr); OH_AVScreenCapture_SetStateCallback(g_avCapture, OnStateChange, nullptr); OH_AVScreenCapture_SetDataCallback(g_avCapture, OnBufferAvailable, nullptr); int result = OH_AVScreenCapture_Init(g_avCapture, config_); if (result != AV_SCREEN_CAPTURE_ERR_OK) { OH_LOG_INFO(LOG_APP, “==DEMO== ScreenCapture OH_AVScreenCapture_Init failed %{public}d”, result); } OH_LOG_INFO(LOG_APP, “==DEMO== ScreenCapture OH_AVScreenCapture_Init %{public}d”, result);

<span class="hljs-comment">// 获取需要输入的Surface,以进行编码</span>
OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, <span class="hljs-literal">true</span>);
<span class="hljs-keyword">const</span> char *name = OH_AVCapability_GetName(capability);
g_videoEnc = OH_VideoEncoder_CreateByName(name);
auto sampleInfo = <span class="hljs-keyword">new</span> SampleInfo;
auto codecUserData = <span class="hljs-keyword">new</span> CodecUserData;
codecUserData-&gt;sampleInfo = sampleInfo;
<span class="hljs-comment">// 配置异步回调,调用 OH_VideoEncoder_SetCallback 接口</span>
int32_t ret =
    OH_VideoEncoder_RegisterCallback(g_videoEnc,
                                     {SampleCallback::OnError, SampleCallback::OnStreamChanged,
                                      SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},
                                     codecUserData);
OH_AVFormat *format = OH_AVFormat_Create();
<span class="hljs-comment">// 配置视频帧速率</span>
double frameRate = <span class="hljs-number">30.0</span>;
<span class="hljs-comment">// 配置视频YUV值范围标志</span>
bool rangeFlag = <span class="hljs-literal">false</span>;
<span class="hljs-comment">// 配置视频原色</span>
int32_t primary = static_cast&lt;int32_t&gt;(OH_ColorPrimary::COLOR_PRIMARY_BT709);
<span class="hljs-comment">// 配置传输特性</span>
int32_t transfer = static_cast&lt;int32_t&gt;(OH_TransferCharacteristic::TRANSFER_CHARACTERISTIC_BT709);
<span class="hljs-comment">// 配置最大矩阵系数</span>
int32_t matrix = static_cast&lt;int32_t&gt;(OH_MatrixCoefficient::MATRIX_COEFFICIENT_IDENTITY);
<span class="hljs-comment">// 配置编码Profile</span>
int32_t profile = static_cast&lt;int32_t&gt;(OH_AVCProfile::AVC_PROFILE_BASELINE);
<span class="hljs-comment">// 配置编码比特率模式</span>
int32_t rateMode = static_cast&lt;int32_t&gt;(OH_VideoEncodeBitrateMode::CBR);
<span class="hljs-comment">// 配置关键帧的间隔,单位为毫秒</span>
int32_t iFrameInterval = <span class="hljs-number">23000</span>;
<span class="hljs-comment">// 配置所需的编码质量。只有在恒定质量模式下配置的编码器才支持此配置</span>
int32_t quality = <span class="hljs-number">0</span>;
<span class="hljs-comment">// 配置比特率</span>
int64_t bitRate = <span class="hljs-number">3000000</span>;
OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXELFORMAT);
OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, rangeFlag);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, primary);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, transfer);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, matrix);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, iFrameInterval);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, rateMode);
OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, bitRate);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, quality);
result = OH_VideoEncoder_Configure(g_videoEnc, format);
OH_LOG_INFO(LOG_APP, <span class="hljs-string">"==DEMO==  OH_VideoEncoder_Configure ret=%{public}d"</span>, result);
OH_AVFormat_Destroy(format);

<span class="hljs-comment">// 从视频编码器获取输入Surface</span>
OHNativeWindow *nativeWindow;
result = OH_VideoEncoder_GetSurface(g_videoEnc, &amp;nativeWindow);
<span class="hljs-keyword">if</span> (result != AV_ERR_OK) {
    OH_LOG_INFO(LOG_APP, <span class="hljs-string">"==DEMO== ScreenCapture Started OH_VideoEncoder_GetSurface ret=%{public}d"</span>, result);
}
result = OH_VideoEncoder_Prepare(g_videoEnc);
std::string_view outputFilePath = <span class="hljs-string">"/data/storage/el2/base/files/DemoSurface.h264"</span>;
std::unique_ptr&lt;std::ofstream&gt; outputFile = std::make_unique&lt;std::ofstream&gt;();
outputFile-&gt;open(outputFilePath.data(), std::ios::out | std::ios::binary | std::ios::ate);

<span class="hljs-comment">// 启动编码器</span>
int32_t retEnc = OH_VideoEncoder_Start(g_videoEnc);
<span class="hljs-comment">// 指定surface开始录屏</span>
result = OH_AVScreenCapture_StartScreenCaptureWithSurface(g_avCapture, nativeWindow);
<span class="hljs-keyword">if</span> (result != AV_SCREEN_CAPTURE_ERR_OK) {
    OH_LOG_INFO(LOG_APP, <span class="hljs-string">"==DEMO== ScreenCapture Started failed %{public}d"</span>, result);
    OH_AVScreenCapture_Release(g_avCapture);
}
OH_LOG_INFO(LOG_APP, <span class="hljs-string">"==DEMO== ScreenCapture Started %{public}d"</span>, result);

m_scSurfaceIsRunning = <span class="hljs-literal">true</span>;
napi_value res;
napi_create_int32(env, result, &amp;res);
<span class="hljs-keyword">return</span> res;

}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

同问,官方demo不行

在HarmonyOS鸿蒙Next系统中使用AVScreenCapture进行录屏并获取原始码流(如H264流),遇到报错的问题,通常可能是由于以下几个原因:

  1. 权限配置:确保你的应用已经正确配置了录屏所需的权限,包括屏幕录制权限等。

  2. API使用不当:检查你的C/C++代码是否正确调用了AVScreenCapture的API,包括参数设置和回调处理。

  3. 资源释放问题:确认在录屏过程中和结束后,是否正确释放了所有分配的资源,避免内存泄漏或资源冲突。

  4. 编码格式支持:确认AVScreenCapture是否支持直接输出H264格式,如果不支持,可能需要进行后处理或转换。

  5. 系统兼容性问题:不同版本的HarmonyOS系统可能对API的支持有差异,确保你的代码与当前系统版本兼容。

如果上述检查后问题依旧没法解决,请检查是否有最新的SDK或系统更新,或者尝试在开发者社区寻找是否有其他开发者遇到并解决了类似的问题。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部