HarmonyOS 鸿蒙Next AVScreenCapture的OnBufferAvailable回调中使用napi_call_function实时回传数据报错闪退

HarmonyOS 鸿蒙Next AVScreenCapture的OnBufferAvailable回调中使用napi_call_function实时回传数据报错闪退

代码如下:好心的各位大佬帮忙找找问题吧。。。

#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"
#include <functional>

struct OH_AVScreenCapture *capture;

// 异步工作的上下文结构体
struct AsyncWorkData {
    napi_env env;
    napi_ref callback_ref;
    std::function<void(napi_env, napi_value)> work;
};

// 异步工作的执行函数
void AsyncWorkExecute(napi_env env, void* data) {
    auto asyncData = static_cast<AsyncWorkData*>(data);
    napi_value callback;
    napi_get_reference_value(env, asyncData->callback_ref, &callback);
    asyncData->work(env, callback);
}

// 异步工作的完成回调函数
void AsyncWorkComplete(napi_env env, napi_status status, void* data) {
    auto asyncData = static_cast<AsyncWorkData*>(data);
    napi_delete_reference(env, asyncData->callback_ref);
    delete asyncData;
}

// 自定义结构体,用于传递 napi_env 和回调函数
struct CallbackData {
    napi_env env;
    napi_value callback;
};

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) {
    auto data = static_cast<CallbackData*>(userData);
    napi_env env = data->env;
    if (env == nullptr) {
        return;
    }
    napi_value callback = data->callback;
    // 获取解码后信息 可以参考编解码接口
    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
        napi_value sum;
        napi_create_double(env, 5, &sum);
        napi_value result =nullptr;
        napi_call_function(env, nullptr, callback, 1, &sum, &result);
    } else if (bufferType == OH_SCREEN_CAPTURE_BUFFERTYPE_AUDIO_INNER) {
        // 处理内录buffer
    } else if (bufferType == OH_SCREEN_CAPTURE_BUFFERTYPE_AUDIO_MIC) {
        // 处理麦克风buffer
    }
}

static napi_value Screencapture(napi_env env, napi_callback_info info) {
    // 从js端获取窗口id number[]
    std::vector<int> windowIdsExclude = {};
    size_t argc = 2;
    napi_value args[2] = {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();
    
    auto callbackData = std::make_unique<CallbackData>();
    callbackData->env = env;
    callbackData->callback = args[1];
    
    // 设置回调 
    OH_AVScreenCapture_SetErrorCallback(capture, OnError, callbackData.get());
    OH_AVScreenCapture_SetStateCallback(capture,OnStateChange, callbackData.get());
    OH_AVScreenCapture_SetDataCallback(capture, OnBufferAvailable, callbackData.get());

    // 可选 配置录屏旋转,此接口在感知到手机屏幕旋转时调用,如果手机的屏幕实际上没有发生旋转,调用接口是无效的。
    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_AVScreenCaptureConfig
    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};
    OH_AVScreenCapture_Init(capture, config);

    // 可选 [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); 

    // 开始录屏
    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);  
    
    // 返回调用结果,示例仅返回随意值
    napi_value sum;
    napi_create_double(env, 5, &sum);

    return sum;
}

static napi_value stopScreenCapture(napi_env env, napi_callback_info info){
    // 结束录屏
    OH_AVScreenCapture_StopScreenCapture(capture);
    // 释放ScreenCapture
    OH_AVScreenCapture_Release(capture);
    napi_value sum;
    napi_create_double(env, 5, &sum);

    return sum;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        {"Screencapture", nullptr, Screencapture, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"stopScreenCapture", nullptr, stopScreenCapture, nullptr, nullptr, nullptr, napi_default, nullptr}
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}

更多关于HarmonyOS 鸿蒙Next AVScreenCapture的OnBufferAvailable回调中使用napi_call_function实时回传数据报错闪退的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next AVScreenCapture的OnBufferAvailable回调中使用napi_call_function实时回传数据报错闪退的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS中,AVScreenCaptureOnBufferAvailable回调中使用napi_call_function实时回传数据时,可能会由于线程安全问题或napi调用不当导致闪退。OnBufferAvailable回调通常在一个独立的线程中执行,而napi_call_function涉及到JavaScript引擎的调用,必须在主线程中执行。如果尝试在非主线程中直接调用napi_call_function,可能会导致未定义行为或应用程序崩溃。此外,napi_call_function的参数传递或上下文管理不当也可能引发异常。确保napi_call_function在主线程中执行,并检查参数和上下文是否正确绑定,可以避免此类问题。

回到顶部