• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "RecorderNative.h"
17 #include <bits/alltypes.h>
18 
19 #undef LOG_DOMAIN
20 #undef LOG_TAG
21 #define LOG_DOMAIN 0xFF00
22 #define LOG_TAG "recorder"
23 
24 namespace {
25 constexpr int RGBA = 3;
26 }
27 
28 struct AsyncCallbackInfo {
29     napi_env env;
30     napi_async_work asyncWork;
31     napi_deferred deferred;
32     int32_t resultCode = 0;
33     std::string surfaceId = "";
34     SampleInfo sampleInfo;
35 };
36 
DealCallBack(napi_env env,void * data)37 void DealCallBack(napi_env env, void *data)
38 {
39     AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
40     napi_value code;
41     napi_create_int32(env, asyncCallbackInfo->resultCode, &code);
42     napi_value surfaceId;
43     napi_create_string_utf8(env, asyncCallbackInfo->surfaceId.data(), NAPI_AUTO_LENGTH, &surfaceId);
44     napi_value obj;
45     napi_create_object(env, &obj);
46 
47     napi_set_named_property(env, obj, "code", code);
48     napi_set_named_property(env, obj, "surfaceId", surfaceId);
49     napi_resolve_deferred(asyncCallbackInfo->env, asyncCallbackInfo->deferred, obj);
50     napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
51     delete asyncCallbackInfo;
52 }
53 
SetCallBackResult(AsyncCallbackInfo * asyncCallbackInfo,int32_t code)54 void SetCallBackResult(AsyncCallbackInfo *asyncCallbackInfo, int32_t code)
55 {
56     asyncCallbackInfo->resultCode = code;
57 }
58 
SurfaceIdCallBack(AsyncCallbackInfo * asyncCallbackInfo,std::string surfaceId)59 void SurfaceIdCallBack(AsyncCallbackInfo *asyncCallbackInfo, std::string surfaceId)
60 {
61     asyncCallbackInfo->surfaceId = surfaceId;
62 }
63 
NativeInit(void * data)64 void NativeInit(void *data)
65 {
66     AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
67     int32_t ret = Recorder::GetInstance().Init(asyncCallbackInfo->sampleInfo);
68     if (ret != AVCODEC_SAMPLE_ERR_OK) {
69         SetCallBackResult(asyncCallbackInfo, -1);
70     }
71 
72     uint64_t id = 0;
73     ret = OH_NativeWindow_GetSurfaceId(asyncCallbackInfo->sampleInfo.window, &id);
74     if (ret != AVCODEC_SAMPLE_ERR_OK) {
75         SetCallBackResult(asyncCallbackInfo, -1);
76     }
77     asyncCallbackInfo->surfaceId = std::to_string(id);
78     SurfaceIdCallBack(asyncCallbackInfo, asyncCallbackInfo->surfaceId);
79 }
80 
ParseSampleInfo(napi_env env,napi_value args[])81 static SampleInfo ParseSampleInfo(napi_env env, napi_value args[])
82 {
83     SampleInfo sampleInfo;
84     int index = 0;
85     napi_get_value_int32(env, args[index++], &sampleInfo.outputFd);
86     char videoCodecMime[20] = {0};
87     size_t videoCodecMimeStrlen;
88     size_t len = 20;
89     napi_get_value_string_utf8(env, args[index++], videoCodecMime, len, &videoCodecMimeStrlen);
90     napi_get_value_int32(env, args[index++], &sampleInfo.videoWidth);
91     napi_get_value_int32(env, args[index++], &sampleInfo.videoHeight);
92     napi_get_value_double(env, args[index++], &sampleInfo.frameRate);
93     napi_get_value_int32(env, args[index++], &sampleInfo.isHDRVivid);
94     napi_get_value_int64(env, args[index++], &sampleInfo.bitrate);
95 
96     int32_t format;
97     if (napi_ok == napi_get_value_int32(env, args[index], &format)) {
98         sampleInfo.pixelFormat = (format == RGBA) ? AV_PIXEL_FORMAT_RGBA : AV_PIXEL_FORMAT_NV12;
99     }
100 
101     sampleInfo.videoCodecMime = videoCodecMime;
102     if (sampleInfo.isHDRVivid) {
103         sampleInfo.hevcProfile = HEVC_PROFILE_MAIN_10;
104     }
105     return sampleInfo;
106 }
107 
CreateAsyncInfo(napi_env env,napi_deferred deferred,SampleInfo sampleInfo)108 static AsyncCallbackInfo* CreateAsyncInfo(napi_env env, napi_deferred deferred, SampleInfo sampleInfo)
109 {
110     AsyncCallbackInfo* asyncInfo = new AsyncCallbackInfo();
111     asyncInfo->env = env;
112     asyncInfo->deferred = deferred;
113     asyncInfo->sampleInfo = sampleInfo;
114     asyncInfo->resultCode = -1;
115     return asyncInfo;
116 }
117 
StartAsyncWork(napi_env env,AsyncCallbackInfo * asyncInfo)118 static void StartAsyncWork(napi_env env, AsyncCallbackInfo* asyncInfo)
119 {
120     napi_value resourceName;
121     napi_create_string_latin1(env, "recorder", NAPI_AUTO_LENGTH, &resourceName);
122     napi_create_async_work(env, nullptr, resourceName,
123         [](napi_env env, void* data) { NativeInit(data); },
124         [](napi_env env, napi_status status, void* data) { DealCallBack(env, data); },
125         asyncInfo, &asyncInfo->asyncWork);
126     napi_queue_async_work(env, asyncInfo->asyncWork);
127 }
128 
Init(napi_env env,napi_callback_info info)129 napi_value RecorderNative::Init(napi_env env, napi_callback_info info)
130 {
131     size_t argc = 8;
132     napi_value args[8] = {nullptr};
133     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
134 
135     SampleInfo sampleInfo = ParseSampleInfo(env, args);
136 
137     //音频
138     sampleInfo.audioCodecMime = OH_AVCODEC_MIMETYPE_AUDIO_AAC;
139     sampleInfo.audioSampleForamt = OH_BitsPerSample::SAMPLE_S16LE;
140     sampleInfo.audioSampleRate = 48000; // sample rate 48000
141     sampleInfo.audioChannelCount = 2; // channel count 2
142     sampleInfo.audioBitRate = 32000; // bit rate 32000
143     sampleInfo.audioChannelLayout = OH_AudioChannelLayout::CH_LAYOUT_STEREO;
144     sampleInfo.audioMaxInputSize = sampleInfo.audioSampleRate * sampleInfo.audioChannelCount *
145                                    sizeof(short) * 0.02; // 0.02 is 20ms
146 
147     napi_value promise;
148     napi_deferred deferred;
149     napi_create_promise(env, &deferred, &promise);
150 
151     AsyncCallbackInfo* asyncInfo = CreateAsyncInfo(env, deferred, sampleInfo);
152     StartAsyncWork(env, asyncInfo);
153     return promise;
154 }
155 
Start(napi_env env,napi_callback_info info)156 napi_value RecorderNative::Start(napi_env env, napi_callback_info info)
157 {
158     Recorder::GetInstance().Start();
159     return nullptr;
160 }
161 
NativeStop(napi_env env,void * data)162 void NativeStop(napi_env env, void *data)
163 {
164     AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
165     int32_t ret = Recorder::GetInstance().Stop();
166     if (ret != AVCODEC_SAMPLE_ERR_OK) {
167         SetCallBackResult(asyncCallbackInfo, -1);
168     }
169     SetCallBackResult(asyncCallbackInfo, 0);
170 }
171 
Stop(napi_env env,napi_callback_info info)172 napi_value RecorderNative::Stop(napi_env env, napi_callback_info info)
173 {
174     napi_value promise;
175     napi_deferred deferred;
176     napi_create_promise(env, &deferred, &promise);
177 
178     AsyncCallbackInfo *asyncCallbackInfo = new AsyncCallbackInfo();
179 
180     asyncCallbackInfo->env = env;
181     asyncCallbackInfo->asyncWork = nullptr;
182     asyncCallbackInfo->deferred = deferred;
183 
184     napi_value resourceName;
185     napi_create_string_latin1(env, "recorder", NAPI_AUTO_LENGTH, &resourceName);
186     napi_create_async_work(
187         env, nullptr, resourceName, [](napi_env env, void *data) { NativeStop(env, data); },
188         [](napi_env env, napi_status status, void *data) { DealCallBack(env, data); }, (void *)asyncCallbackInfo,
189         &asyncCallbackInfo->asyncWork);
190     napi_queue_async_work(env, asyncCallbackInfo->asyncWork);
191     return promise;
192 }
193 
194 EXTERN_C_START
Init(napi_env env,napi_value exports)195 static napi_value Init(napi_env env, napi_value exports)
196 {
197     napi_property_descriptor classProp[] = {
198         {"initNative", nullptr, RecorderNative::Init, nullptr, nullptr, nullptr, napi_default, nullptr},
199         {"startNative", nullptr, RecorderNative::Start, nullptr, nullptr, nullptr, napi_default, nullptr},
200         {"stopNative", nullptr, RecorderNative::Stop, nullptr, nullptr, nullptr, napi_default, nullptr},
201     };
202 
203     napi_value RecorderNative = nullptr;
204     const char *classBindName = "recorderNative";
205     napi_define_class(env, classBindName, strlen(classBindName), nullptr, nullptr, 1, classProp, &RecorderNative);
206     napi_define_properties(env, exports, sizeof(classProp) / sizeof(classProp[0]), classProp);
207     return exports;
208 }
209 EXTERN_C_END
210 
211 static napi_module RecorderModule = {
212     .nm_version = 1,
213     .nm_flags = 0,
214     .nm_filename = nullptr,
215     .nm_register_func = Init,
216     .nm_modname = "recorder",
217     .nm_priv = ((void *)0),
218     .reserved = {0},
219 };
220 
221 
RegisterRecorderModule(void)222 extern "C" __attribute__((constructor)) void RegisterRecorderModule(void) { napi_module_register(&RecorderModule); }
223