HarmonyOS 鸿蒙Next 使用AVScreenCapture录屏取码流(C/C++),在回调OnBufferAvailable()中获取不到码流数据

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

使用版本:HarmonyOS 5.0.1(13)

功能描述:需要做一个录屏的功能,获取录屏的H.264的码数数据

场景描述:参考了官方例子:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/using-avscreencapture-for-buffer-V13

问题:其中,OH_AVScreenCapture_SetDataCallback(capture, OnBufferAvailable, userData); 配置获取码流的回调方法“OnBufferAvailable”没有触发回调,调试状态下打断点也没有进去。

说明:

// 开始录屏

result =   OH_AVScreenCapture_StartScreenCapture(capture); 返回的参数为0(这个状态是正常的)
OH_AVScreenCapture_SetStateCallback(capture, OnStateChange, nullptr);此方法也能拿到state为
OH_SCREEN_CAPTURE_STATE_STARTED。

请问,如何才能触发“OnBufferAvailable”方法

代码:

// // Created on 2024/12/19. // // Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, // please include “napi/native_api.h”.

#include "screen_capture.h"
#include "napi/native_api.h"
#include <multimedia/player_framework/native_avscreen_capture.h>
#include <multimedia/player_framework/native_avscreen_capture_base.h>
#include <multimedia/player_framework/native_avscreen_capture_errors.h>
#include <multimedia/player_framework/native_avbuffer.h>
#include <native_buffer/native_buffer.h>
#include <fcntl.h>
#include "string"
#include "unistd.h"

screen_capture::~screen_capture() {  }

void OnError(OH_AVScreenCapture *capture, int32_t errorCode, void *userData) {
    (void)capture;
    (void)errorCode;
    (void)userData;
}

void OnStateChange(struct OH_AVScreenCapture *capture, OH_AVScreenCaptureStateCode stateCode, void *userData) {
    (void)capture;
    
    if (stateCode == OH_SCREEN_CAPTURE_STATE_STARTED) {
        // 处理状态变更
    }
    if (stateCode == OH_SCREEN_CAPTURE_STATE_STOPPED_BY_CALL ||
        stateCode == OH_SCREEN_CAPTURE_STATE_STOPPED_BY_USER_SWITCHES) {
        // 录屏中断状态处理
    }
    if (stateCode == OH_SCREEN_CAPTURE_STATE_INTERRUPTED_BY_OTHER) {
        // 处理状态变更
    }
    (void)userData;
}

void OnBufferAvailable(OH_AVScreenCapture *capture, OH_AVBuffer *buffer,
    OH_AVScreenCaptureBufferType bufferType, int64_t timestamp, void *userData) {
    // 获取解码后信息 可以参考编解码接口
    int bufferLen = OH_AVBuffer_GetCapacity(buffer);
    OH_NativeBuffer *nativeBuffer = OH_AVBuffer_GetNativeBuffer(buffer);
    OH_NativeBuffer_Config config;
    OH_NativeBuffer_GetConfig(nativeBuffer, &config);
    int32_t videoSize= config.height * config.width * 4;
    uint8_t *buf = OH_AVBuffer_GetAddr(buffer);
    if (bufferType == OH_SCREEN_CAPTURE_BUFFERTYPE_VIDEO) {
        // 处理视频buffer
    } else if (bufferType == OH_SCREEN_CAPTURE_BUFFERTYPE_AUDIO_INNER) {
        // 处理内录buffer
    } else if (bufferType == OH_SCREEN_CAPTURE_BUFFERTYPE_AUDIO_MIC) {
        // 处理麦克风buffer
    }
}

struct OH_AVScreenCapture *capture;
void screen_capture:: Screencast() {
//     // 从js端获取窗口id number[]
//     std::vector<int> windowIdsExclude = {};
//     size_t argc = 1;
//     napi_value args[1] = {nullptr};
//     // 获取参数
//     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
//     // 获取数组长度
//     uint32_t array_length;
//     napi_get_array_length(env, args[0], &array_length);
//     // 读初窗口id
//     for (int32_t i = 0; i < array_length; i++) {
//         napi_value temp;
//         napi_get_element(env, args[0], i, &temp);
//         uint32_t tempValue;
//         napi_get_value_uint32(env, temp, &tempValue);
//         windowIdsExclude.push_back(tempValue);
//      }
    // 实例化ScreenCapture
    capture = OH_AVScreenCapture_Create();
    
    // 设置回调 
    OH_AVScreenCapture_SetErrorCallback(capture, OnError, nullptr);
    OH_AVScreenCapture_SetStateCallback(capture, OnStateChange, nullptr);
    OH_AVScreenCapture_SetDataCallback(capture, OnBufferAvailable, nullptr);

    // 可选 配置录屏旋转,此接口在感知到手机屏幕旋转时调用,如果手机的屏幕实际上没有发生旋转,调用接口是无效的。
    OH_AVScreenCapture_SetCanvasRotation(capture, true);
    // 可选 [过滤音频]
    OH_AVScreenCapture_ContentFilter *contentFilter= OH_AVScreenCapture_CreateContentFilter();
    // 添加过滤通知音
    OH_AVScreenCapture_ContentFilter_AddAudioContent(contentFilter, OH_SCREEN_CAPTURE_NOTIFICATION_AUDIO);
    // 排除指定窗口id
//     OH_AVScreenCapture_ContentFilter_AddWindowContent(contentFilter, &windowIdsExclude[0],
//                                                       static_cast<int32_t>(windowIdsExclude.size()));

    OH_AVScreenCapture_ExcludeContent(capture, contentFilter);

    // 初始化录屏,传入配置信息OH_AVScreenRecorderConfig
    OH_AudioCaptureInfo miccapinfo = {.audioSampleRate = 16000, .audioChannels = 2, .audioSource = OH_MIC};
    OH_VideoCaptureInfo videocapinfo = {
        .videoFrameWidth = 768, .videoFrameHeight = 1280, .videoSource = OH_VIDEO_SOURCE_SURFACE_RGBA};
    OH_AudioInfo audioinfo = {
        .micCapInfo = miccapinfo,
    };
    OH_VideoInfo videoinfo = {.videoCapInfo = videocapinfo};
    OH_AVScreenCaptureConfig config = {.captureMode = OH_CAPTURE_HOME_SCREEN,
                                       .dataType = OH_ORIGINAL_STREAM,
                                       //.audioInfo = audioinfo,
                                       .videoInfo = videoinfo};
   int result =  OH_AVScreenCapture_Init(capture, config);
    
    if (result != AV_SCREEN_CAPTURE_ERR_OK) {
       
    }
    
    // 可选 [Surface模式]
    // 通过 MIME TYPE 创建编码器,系统会根据MIME创建最合适的编码器。
    // OH_AVCodec *codec = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);    
    // 从视频编码器获取输入Surface
    // OH_AVErrCode OH_VideoEncoder_GetSurface(codec, window);
    // 启动编码器
    // int32_t retEnc = OH_VideoEncoder_Start(codec);
    // 指定surface开始录屏
    // int32_t retStart = OH_AVScreenCapture_StartScreenCaptureWithSurface(capture, window); 

    // 开始录屏
    result =   OH_AVScreenCapture_StartScreenCapture(capture);
    

    // mic开关设置
    OH_AVScreenCapture_SetMicrophoneEnabled(capture, true);

    // 可选 豁免隐私窗口 需传递应用豁免子窗口和主窗口ID,传空数组取消豁免隐私窗口
    // std::vector<int> windowIdsSkipPrivacy = {};
    // OH_AVScreenCapture_SkipPrivacyMode(capture, &windowIdsSkipPrivacy[0],
    //     static_cast<int32_t>(windowIdsSkipPrivacy.size()));

    // 可选 调整录屏分辨率 需在启动后调用,分辨率有范围限制 可参考avcodec编解码能力
    // OH_AVScreenCapture_ResizeCanvas(capture, 768, 1280);

    sleep(10); // 录制10s
    // 结束录屏
    OH_AVScreenCapture_StopScreenCapture(capture);
    // 释放ScreenCapture
    OH_AVScreenCapture_Release(capture);
    // 返回调用结果,示例仅返回随意值
//     napi_value sum;
//     napi_create_double(env, 5, &sum);

    return void(0);
}

更多关于HarmonyOS 鸿蒙Next 使用AVScreenCapture录屏取码流(C/C++),在回调OnBufferAvailable()中获取不到码流数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复
这里面的Demo OnBufferAvailable在模拟器上跑的取不到回调,在手机上运行没问题。

更多关于HarmonyOS 鸿蒙Next 使用AVScreenCapture录屏取码流(C/C++),在回调OnBufferAvailable()中获取不到码流数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


补充:
OH_AVScreenCapture_SetDataCallback 返回的状态也是正常的
cke_137.png

在HarmonyOS鸿蒙Next系统中使用AVScreenCapture进行录屏并尝试在OnBufferAvailable()回调中获取码流数据时,若未能成功获取,可能的原因及潜在解决方案包括:

  1. 权限检查:确保应用已正确声明并获取了录屏所需的权限,如ohos.permission.RECORD_AUDIOohos.permission.CAPTURE_VIDEO_OUTPUT

  2. 回调注册:验证OnBufferAvailable()回调是否已正确注册到AVScreenCapture实例,且回调方法签名与API要求一致。

  3. Buffer状态:检查传入的MediaCodec.BufferInfo对象是否有效,确保offsetsize等字段正确设置,且presentationTimeUs反映了正确的时间戳。

  4. 线程安全:确保回调处理逻辑不会因线程安全问题导致数据访问失败,考虑使用同步机制保护数据访问。

  5. 设备兼容性:确认目标设备支持当前使用的录屏功能,并检查是否有特定的硬件或软件限制。

如果上述检查后问题依旧没法解决,请访问官网客服寻求进一步帮助。官网地址是:https://www.itying.com/category-93-b0.html。

回到顶部