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 #include "napi/native_api.h"
16 #include <cstdint>
17 #include <map>
18 #include <js_native_api.h>
19 #include "multimedia/player_framework/avtranscoder.h"
20 #include "multimedia/player_framework/avtranscoder_base.h"
21 #include <fstream>
22 #include <hilog/log.h>
23 #include <thread>
24 #include <vector>
25 #include <string>
26 #include <future>
27 #define FAIL (-1)
28 #define SUCCESS 0
29 #define PARAM_0 0
30 #define PARAM_1 1
31 #define PARAM_2 2
32 #define PARAM_3 3
33 #define PARAM_4 4
34 #define LOG_MSG_TAG "AVTransCoderNdk"
35 #define LOG(format, ...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, LOG_MSG_TAG, format, ##__VA_ARGS__))
36 #define LOGE(format, ...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, LOG_MSG_TAG, format, ##__VA_ARGS__))
37 #define LOGD(format, ...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xFF00, LOG_MSG_TAG, format, ##__VA_ARGS__))
38 const std::string CREATEAVTRANSCODER_EVENT = "create";
39 const std::string PREPAREAVTRANSCODER_EVENT = "prepare";
40 const std::string STARTAVTRANSCODER_EVENT = "setVideoType";
41 const std::string PAUSEAVTRANSCODER_EVENT = "pause";
42 const std::string RESUMEAVTRANSCODER_EVENT = "resume";
43 const std::string CANCELAVTRANSCODER_EVENT = "cancel";
44 const std::string RELEASEAVTRANSCODER_EVENT = "release";
45 const std::string ERROR_EVENT = "error";
46 const std::string END_EVENT = "end";
47 const std::int32_t AUDIO_BITRATE = 200000;
48 const std::int32_t VIDEO_BITRATE = 3000000;
49
50 typedef enum {
51 /* prepared states */
52 TRANSCODER_PREPARED = 1,
53 /* started states */
54 TRANSCODER_STARTED = 2,
55 /* paused states */
56 TRANSCODER_PAUSED = 3,
57 /* stopped states */
58 TRANSCODER_CANCELLED = 4,
59 /* completed states */
60 TRANSCODER_COMPLETED = 5,
61 } AVTranscoderState;
62
63 typedef struct NdkAVTransCoderUser {
64 using StateChangeFunc = std::function<void()>;
65 NdkAVTransCoderUser();
66 NdkAVTransCoderUser(const NdkAVTransCoderUser &other) = delete;
67 NdkAVTransCoderUser &operator=(const NdkAVTransCoderUser &other) = delete;
68 ~NdkAVTransCoderUser();
69
70 void OnStateChangeCb(OH_AVTranscoder *transcoder, OH_AVTranscoder_State state);
71 void OnErrorCb(OH_AVTranscoder *transcoder, int32_t errorCode, const char *errorMsg);
72 void OnProgressUpdateCb(OH_AVTranscoder *transcoder, int progress);
73 std::map<uint32_t, StateChangeFunc> stateChangeFuncs_;
74
75 OH_AVTranscoder *transcoder = nullptr;
76 int32_t errorCode = AV_ERR_OK;
77 int32_t transCoderState = -1;
78 int avTranscoderProgress = 0;
79 int inStartStateCount = 0;
80 } NdkAVTransCoderUser;
NdkAVTransCoderUser()81 NdkAVTransCoderUser::NdkAVTransCoderUser() {}
~NdkAVTransCoderUser()82 NdkAVTransCoderUser::~NdkAVTransCoderUser() {}
83
84 typedef struct NdkAVTransCoderContext {
85 NdkAVTransCoderUser *transcoderUser = nullptr;
86 OH_AVTranscoder *transcoder = nullptr;
87 OH_AVTranscoder_Config *config = nullptr;
88 } NdkAVTransCoderContext;
89 static NdkAVTransCoderContext g_ctx;
90
OnProgressUpdateCb(OH_AVTranscoder * transcoder,int progress)91 void NdkAVTransCoderUser::OnProgressUpdateCb(OH_AVTranscoder *transcoder, int progress)
92 {
93 LOG("NdkAVTransCoderUser OnProgressUpdateCb progress: %{public}d", progress);
94 this->avTranscoderProgress = progress;
95 }
96
AvTranscoderRelease(OH_AVTranscoder * transcoder)97 static void AvTranscoderRelease(OH_AVTranscoder *transcoder)
98 {
99 if (transcoder != nullptr) {
100 OH_AVErrCode errCode = OH_AVTranscoder_Release(transcoder);
101 LOG("OH_AVTranscoder_Release errCode:%{public}d", errCode);
102 }
103 if (g_ctx.transcoder != nullptr) {
104 g_ctx.transcoder = nullptr;
105 }
106 if (g_ctx.config != nullptr) {
107 OH_AVErrCode errCode = OH_AVTranscoderConfig_Release(g_ctx.config);
108 g_ctx.config = nullptr;
109 LOG("OH_AVTranscoderConfig_Release errCode:%{public}d", errCode);
110 }
111 }
112
OnErrorCb(OH_AVTranscoder * transcoder,int32_t errorCode,const char * errorMsg)113 void NdkAVTransCoderUser::OnErrorCb(OH_AVTranscoder *transcoder, int32_t errorCode, const char *errorMsg)
114 {
115 LOG("NdkAVTransCoderUser OnErrorCb errorCode: %{public}d ,errorMsg: %{public}s", errorCode,
116 errorMsg == nullptr ? "unknown" : errorMsg);
117 this->errorCode = errorCode;
118 AvTranscoderRelease(transcoder);
119 }
120
OnStateChangeCb(OH_AVTranscoder * transcoder,OH_AVTranscoder_State state)121 void NdkAVTransCoderUser::OnStateChangeCb(OH_AVTranscoder *transcoder, OH_AVTranscoder_State state)
122 {
123 if (transcoder == nullptr) {
124 return;
125 }
126 int32_t ret = -1;
127 switch (state) {
128 case AVTRANSCODER_PREPARED: {
129 this->transCoderState = TRANSCODER_PREPARED;
130 if (this->stateChangeFuncs_.count(TRANSCODER_PREPARED) > 0) {
131 this->stateChangeFuncs_[TRANSCODER_PREPARED]();
132 }
133 break;
134 }
135 case AVTRANSCODER_STARTED: {
136 this->transCoderState = TRANSCODER_STARTED;
137 if (this->stateChangeFuncs_.count(TRANSCODER_STARTED) > 0) {
138 this->stateChangeFuncs_[TRANSCODER_STARTED]();
139 }
140 break;
141 }
142 case AVTRANSCODER_PAUSED: {
143 this->transCoderState = TRANSCODER_PAUSED;
144 if (this->stateChangeFuncs_.count(TRANSCODER_PAUSED) > 0) {
145 this->stateChangeFuncs_[TRANSCODER_PAUSED]();
146 }
147 break;
148 }
149 case AVTRANSCODER_CANCELLED: {
150 this->transCoderState = TRANSCODER_CANCELLED;
151 if (this->stateChangeFuncs_.count(TRANSCODER_CANCELLED) > 0) {
152 this->stateChangeFuncs_[TRANSCODER_CANCELLED]();
153 }
154 break;
155 }
156 case AVTRANSCODER_COMPLETED: {
157 this->transCoderState = TRANSCODER_COMPLETED;
158 if (this->stateChangeFuncs_.count(TRANSCODER_COMPLETED) > 0) {
159 this->stateChangeFuncs_[TRANSCODER_COMPLETED]();
160 }
161 break;
162 }
163 default:
164 break;
165 }
166 }
167
AvTranscoderStateChangeCbImpl(OH_AVTranscoder * transcoder,OH_AVTranscoder_State state,void * userData)168 static void AvTranscoderStateChangeCbImpl(OH_AVTranscoder *transcoder, OH_AVTranscoder_State state, void *userData)
169 {
170 LOG("AvTranscoderStateChangeCbImpl state: %{public}d", state);
171 NdkAVTransCoderUser *ndkAVTransCoderUser = reinterpret_cast<NdkAVTransCoderUser *>(userData);
172 if (ndkAVTransCoderUser == nullptr || transcoder == nullptr) {
173 LOGE("AvTranscoderStateChangeCbImpl ndkAVTransCoderUser or transcoder is nullptr");
174 return;
175 }
176 ndkAVTransCoderUser->OnStateChangeCb(transcoder, state);
177 }
178
AvTranscoderErrorCbImpl(OH_AVTranscoder * transcoder,int32_t errorCode,const char * errorMsg,void * userData)179 static void AvTranscoderErrorCbImpl(OH_AVTranscoder *transcoder, int32_t errorCode, const char *errorMsg,
180 void *userData)
181 {
182 LOG("AvTranscoderErrorCbImpl errorCode: %{public}d, errorMsg: %{public}s", errorCode,
183 errorMsg == nullptr ? "unknown" : errorMsg);
184 NdkAVTransCoderUser *ndkAVTransCoderUser = reinterpret_cast<NdkAVTransCoderUser *>(userData);
185 if (ndkAVTransCoderUser == nullptr || transcoder == nullptr) {
186 LOGE("AvTranscoderErrorCbImpl ndkAVTransCoderUser or transcoder is nullptr");
187 return;
188 }
189 ndkAVTransCoderUser->OnErrorCb(transcoder, errorCode, errorMsg);
190 }
191
AvTranscoderProgressUpdateCbImpl(OH_AVTranscoder * transcoder,int progress,void * userData)192 static void AvTranscoderProgressUpdateCbImpl(OH_AVTranscoder *transcoder, int progress, void *userData)
193 {
194 LOG("AvTranscoderProgressUpdateCbImpl progress: %{public}d", progress);
195 NdkAVTransCoderUser *ndkAVTransCoderUser = reinterpret_cast<NdkAVTransCoderUser *>(userData);
196 if (ndkAVTransCoderUser == nullptr || transcoder == nullptr) {
197 LOGE("AvTranscoderProgressUpdateCbImpl ndkAVTransCoderUser or transcoder is nullptr");
198 return;
199 }
200 ndkAVTransCoderUser->OnProgressUpdateCb(transcoder, progress);
201 }
202
AvTranscoderStateChangeFuncs(NdkAVTransCoderUser * transcoderUser)203 static void AvTranscoderStateChangeFuncs(NdkAVTransCoderUser *transcoderUser)
204 {
205 transcoderUser->stateChangeFuncs_ = {
206 {TRANSCODER_PREPARED, [transcoderUser]() {
207 // 状态为AVTRANSCODER_PREPARED时开始转码
208 OH_AVErrCode errCode = OH_AVTranscoder_Start(transcoderUser->transcoder);
209 transcoderUser->errorCode = errCode;
210 LOG("OH_AVTranscoder_Start errCode:%{public}d", errCode);
211 }},
212 {TRANSCODER_STARTED, []() { LOG("AvTranscoderStateChange: TRANSCODER_STARTED"); }},
213 {TRANSCODER_PAUSED, []() { LOG("AvTranscoderStateChange: TRANSCODER_PAUSED"); }},
214 {TRANSCODER_CANCELLED, []() { LOG("AvTranscoderStateChange: TRANSCODER_CANCELLED"); }},
215 {TRANSCODER_COMPLETED, [transcoderUser]() {
216 // AVTRANSCODER_COMPLETED时释放资源
217 AvTranscoderRelease(transcoderUser->transcoder);
218 }}};
219 }
220
createDefaultTransCoderConfig(int32_t dstFd)221 static OH_AVTranscoder_Config *createDefaultTransCoderConfig(int32_t dstFd)
222 {
223 OH_AVTranscoder_Config *config = OH_AVTranscoderConfig_Create();
224 OH_AVTranscoderConfig_SetDstFD(config, dstFd); // 设置转码的目标文件属dstFd。
225 OH_AVTranscoderConfig_SetDstFileType(config, AV_OUTPUT_FORMAT_MPEG_4); // 封装格式。
226 OH_AVTranscoderConfig_SetDstVideoType(config, "video/avc"); // 视频编码格式,可选。
227 OH_AVTranscoderConfig_SetDstAudioType(config, "audio/mp4a-latm"); // 音频编码格式,可选。
228 OH_AVTranscoderConfig_SetDstAudioBitrate(config, AUDIO_BITRATE); // 音频比特率,可选。
229 OH_AVTranscoderConfig_SetDstVideoBitrate(config, VIDEO_BITRATE); // 视频比特率,可选。
230 return config;
231 }
OHAvTranscoderNdkPlay(napi_env env,napi_callback_info info)232 static napi_value OHAvTranscoderNdkPlay(napi_env env, napi_callback_info info)
233 {
234 napi_value result = nullptr;
235 int backParam = FAIL;
236 size_t argc = PARAM_4;
237 napi_value args[PARAM_4] = {nullptr};
238 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
239 int32_t srcFd = PARAM_0;
240 napi_get_value_int32(env, args[PARAM_0], &srcFd);
241 int64_t srcOffset = PARAM_0;
242 napi_get_value_int64(env, args[PARAM_1], &srcOffset);
243 int64_t length = PARAM_0;
244 napi_get_value_int64(env, args[PARAM_2], &length);
245 int32_t dstFd = PARAM_0;
246 napi_get_value_int32(env, args[PARAM_3], &dstFd);
247
248 OH_AVTranscoder *transcoder = OH_AVTranscoder_Create();
249 NdkAVTransCoderUser *transcoderUser = nullptr;
250 transcoderUser = new NdkAVTransCoderUser();
251 transcoderUser->transcoder = transcoder;
252 g_ctx.transcoder = transcoder;
253 g_ctx.config = createDefaultTransCoderConfig(dstFd);
254
255 OH_AVErrCode errCode = OH_AVTranscoderConfig_SetSrcFD(g_ctx.config, srcFd, srcOffset, length); // 设置转码源视频FD
256 OH_AVTranscoder_SetStateCallback(transcoder, AvTranscoderStateChangeCbImpl, transcoderUser); // 设置状态回调
257 OH_AVTranscoder_SetErrorCallback(transcoder, AvTranscoderErrorCbImpl, transcoderUser); // 设置错误码回调
258 OH_AVTranscoder_SetProgressUpdateCallback(transcoder, AvTranscoderProgressUpdateCbImpl, transcoderUser); // 设置进度值回调
259 g_ctx.transcoderUser = transcoderUser;
260 AvTranscoderStateChangeFuncs(transcoderUser);
261 if (errCode != AV_ERR_OK) {
262 backParam = errCode;
263 LOG("Transcoder setSrcFD failed, ret %{public}d", backParam);
264 }
265 errCode = OH_AVTranscoder_Prepare(transcoder, g_ctx.config);
266 if (errCode != AV_ERR_OK) {
267 backParam = errCode;
268 LOG("Transcoder prepare failed, ret %{public}d", backParam);
269 }
270 napi_create_int32(env, backParam, &result);
271 return result;
272 }
273
OHAvTranscoderNdkPause(napi_env env,napi_callback_info info)274 static napi_value OHAvTranscoderNdkPause(napi_env env, napi_callback_info info)
275 {
276 int ret = 100;
277 ret = OH_AVTranscoder_Pause(g_ctx.transcoder); // 暂停转码
278 LOG("OH_AVTranscoder_Pause ret:%{public}d", ret);
279 napi_value value;
280 napi_create_int32(env, ret, &value);
281 return value;
282 }
283
OHAvTranscoderNdkResume(napi_env env,napi_callback_info info)284 static napi_value OHAvTranscoderNdkResume(napi_env env, napi_callback_info info)
285 {
286 int ret = 100;
287 ret = OH_AVTranscoder_Resume(g_ctx.transcoder); // 恢复转码
288 LOG("OH_AVTranscoder_Resume ret:%{public}d", ret);
289 napi_value value;
290 napi_create_int32(env, ret, &value);
291 return value;
292 }
293
OHAvTranscoderNdkCancel(napi_env env,napi_callback_info info)294 static napi_value OHAvTranscoderNdkCancel(napi_env env, napi_callback_info info)
295 {
296 int ret = 100;
297 ret = OH_AVTranscoder_Cancel(g_ctx.transcoder); // 取消转码
298 LOG("OH_AVTranscoder_Cancel ret:%{public}d", ret);
299 napi_value value;
300 napi_create_int32(env, ret, &value);
301 return value;
302 }
303
OHAvTranscoderNdkRelease(napi_env env,napi_callback_info info)304 static napi_value OHAvTranscoderNdkRelease(napi_env env, napi_callback_info info)
305 {
306 int ret = 100;
307 LOG("OH_AVTranscoder_Release ret:%{public}d", ret);
308 if (g_ctx.transcoder != nullptr) {
309 ret = OH_AVTranscoder_Release(g_ctx.transcoder); // 释放转码实例
310 LOG("OH_AVTranscoder_Release ret:%{public}d", ret);
311 g_ctx.transcoder = nullptr;
312 }
313 if (g_ctx.config != nullptr) {
314 ret = OH_AVTranscoderConfig_Release(g_ctx.config); // 释放转码配置实例
315 LOG("OH_AVTranscoderConfig_Release ret:%{public}d", ret);
316 g_ctx.config = nullptr;
317 }
318 napi_value value;
319 napi_create_int32(env, ret, &value);
320 return value;
321 }
322
323 EXTERN_C_START
Init(napi_env env,napi_value exports)324 static napi_value Init(napi_env env, napi_value exports)
325 {
326 napi_property_descriptor desc[] = {
327 {"AvTranscoderNdkPlay", nullptr, OHAvTranscoderNdkPlay, nullptr, nullptr, nullptr, napi_default, nullptr},
328 {"AvTranscoderNdkPause", nullptr, OHAvTranscoderNdkPause, nullptr, nullptr, nullptr, napi_default, nullptr},
329 {"AvTranscoderNdkResume", nullptr, OHAvTranscoderNdkResume, nullptr, nullptr, nullptr, napi_default, nullptr},
330 {"AvTranscoderNdkCancel", nullptr, OHAvTranscoderNdkCancel, nullptr, nullptr, nullptr, napi_default, nullptr},
331 {"AvTranscoderNdkRelease", nullptr, OHAvTranscoderNdkRelease, nullptr, nullptr, nullptr, napi_default,
332 nullptr}};
333 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
334 return exports;
335 }
336 EXTERN_C_END
337
338 static napi_module demoModule = {
339 .nm_version = 1,
340 .nm_flags = 0,
341 .nm_filename = nullptr,
342 .nm_register_func = Init,
343 .nm_modname = "entry",
344 .nm_priv = ((void *)0),
345 .reserved = {0},
346 };
347
RegisterEntryModule(void)348 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
349