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
更多关于HarmonyOS 鸿蒙Next AVScreenCapture的OnBufferAvailable回调中使用napi_call_function实时回传数据报错闪退的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS中,AVScreenCapture
的OnBufferAvailable
回调中使用napi_call_function
实时回传数据时,可能会由于线程安全问题或napi
调用不当导致闪退。OnBufferAvailable
回调通常在一个独立的线程中执行,而napi_call_function
涉及到JavaScript引擎的调用,必须在主线程中执行。如果尝试在非主线程中直接调用napi_call_function
,可能会导致未定义行为或应用程序崩溃。此外,napi_call_function
的参数传递或上下文管理不当也可能引发异常。确保napi_call_function
在主线程中执行,并检查参数和上下文是否正确绑定,可以避免此类问题。