* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PlayerNative.h"
#include <cstdint>
#include <uv.h>
#include <hilog/log.h>
#include <native_buffer/buffer_common.h>
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0xFF00
#define LOG_TAG "Player"
Player *player[2];
SampleInfo *p_sampleInfo[2];
void Callback(void *asyncContext) {
uv_loop_s *loop = nullptr;
CallbackContext *context = (CallbackContext *)asyncContext;
napi_get_uv_event_loop(context->env, &loop);
if (loop != nullptr) {
uv_work_t *work = new uv_work_t;
work->data = context;
uv_queue_work(
loop, work, [](uv_work_t *work){},
[](uv_work_t *work, int status) {
CallbackContext *context = (CallbackContext *)work->data;
napi_handle_scope scope = nullptr;
napi_open_handle_scope(context->env, &scope);
napi_value callbck = nullptr;
napi_get_reference_value(context->env, context->callbackRef, &callbck);
size_t argc = 1;
napi_value arg;
napi_create_int32(context->env, context->code, &arg);
napi_value* argv = &arg;
napi_call_function(context->env, nullptr, callbck, argc, argv, nullptr);
napi_close_handle_scope(context->env, scope);
delete context;
delete work;
});
} else {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "playerNative", "callback::loop is nullptr");
}
}
napi_value Preload(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t inputFD = 0;
int64_t offset = 0;
int64_t size = 0;
napi_get_value_int32(env, args[0], &inputFD);
napi_get_value_int64(env, args[1], &size);
auto source = OH_AVSource_CreateWithFD(inputFD, offset, size);
auto sourceFormat = OH_AVSource_GetSourceFormat(source);
int32_t trackCount = 0;
OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "playerNative", "playerNative::Preload track count: %{public}d", trackCount);
std::string msg = "";
for(int i = 0; i < trackCount; i++) {
OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(source, i);
int32_t trackType = -1;
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType);
if (trackType == OH_MediaType::MEDIA_TYPE_VID) {
int32_t isVivid = 0;
int32_t profile = 0;
int32_t transfer = 0;
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_VIDEO_IS_HDR_VIVID, &isVivid);
if (isVivid) {
msg = "HDRVivid";
} else {
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_PROFILE, &profile);
if (profile == HEVC_PROFILE_MAIN_10) {
msg = "HDR";
} else {
msg = "SDR";
}
}
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRANSFER_CHARACTERISTICS, &transfer);
switch(transfer) {
case TRANSFER_CHARACTERISTIC_PQ:
msg += " PQ";
break;
case TRANSFER_CHARACTERISTIC_HLG:
msg += " HLG";
break;
default:
msg += " UNKNOWN";
}
int32_t width = 0;
int32_t height = 0;
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_WIDTH, &width);
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_HEIGHT, &height);
int32_t pixelFormat = 0;
OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_PIXEL_FORMAT, &pixelFormat);
msg += "@" + std::to_string(width) + "x" + std::to_string(height) + "@" + std::to_string(pixelFormat);
}
OH_AVFormat_Destroy(trackFormat);
}
OH_AVFormat_Destroy(sourceFormat);
OH_AVSource_Destroy(source);
napi_value retVal;
napi_create_string_utf8(env, msg.c_str(), msg.size(), &retVal);
return retVal;
}
napi_value StartPlay(napi_env env, napi_callback_info info) {
size_t argc = 10;
napi_value args[10] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t outputFd = -1;
int32_t color = 0;
int32_t metaData = 0;
int32_t zoomLevel = 0;
int32_t videoIndex = 0;
int32_t processType = 0;
napi_get_value_int32(env, args[8], &processType);
napi_get_value_int32(env, args[3], &videoIndex);
if (p_sampleInfo[videoIndex] == nullptr) {
p_sampleInfo[videoIndex] = new SampleInfo();
}
p_sampleInfo[videoIndex]->videoIndex = videoIndex;
p_sampleInfo[videoIndex]->processType = processType;
napi_get_value_int32(env, args[0], &p_sampleInfo[videoIndex]->inputFd);
napi_get_value_int64(env, args[1], &p_sampleInfo[videoIndex]->inputFileOffset);
napi_get_value_int64(env, args[2], &p_sampleInfo[videoIndex]->inputFileSize);
auto asyncContext = new CallbackContext();
asyncContext->env = env;
napi_create_reference(env, args[9], 1, &asyncContext->callbackRef);
p_sampleInfo[videoIndex]->playDoneCallback = &Callback;
p_sampleInfo[videoIndex]->playDoneCallbackData = asyncContext;
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "playerNative", "StartPlay: index:%{public}d, type:%{public}d", videoIndex, processType);
if (p_sampleInfo[videoIndex]->processType) {
napi_get_value_int32(env, args[4], &outputFd);
p_sampleInfo[videoIndex]->outputFd = outputFd;
napi_get_value_int32(env, args[5], &color);
p_sampleInfo[videoIndex]->colorSpace = (OH_NativeBuffer_ColorSpace)color;
napi_get_value_int32(env, args[6], &metaData);
p_sampleInfo[videoIndex]->metaData = metaData;
napi_get_value_int32(env, args[7], &zoomLevel);
p_sampleInfo[videoIndex]->zoomLevel = zoomLevel;
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "playerNative",
"StartPlay: fd:%{public}d, color:%{public}d,metadata:%{public}d, zoomLevel:%{public}d ",
outputFd, color, metaData, zoomLevel);
player[videoIndex] = new Player();
player[videoIndex]->Init(*p_sampleInfo[videoIndex]);
player[videoIndex]->Start();
NativeXComponentSample::PluginManager::GetInstance()->SetSampleInfo(p_sampleInfo[videoIndex]);
NativeXComponentSample::PluginManager::GetInstance()->StartProcessing();
} else {
player[videoIndex] = new Player();
player[videoIndex]->Init(*p_sampleInfo[videoIndex]);
player[videoIndex]->Start();
}
return nullptr;
}
napi_value Destroy(napi_env env, napi_callback_info info) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "playerNative", "playerNative::Destroy");
if (p_sampleInfo[0] != nullptr) {
delete p_sampleInfo[0];
p_sampleInfo[0] = nullptr;
}
if (p_sampleInfo[1] != nullptr) {
delete p_sampleInfo[1];
p_sampleInfo[1] = nullptr;
}
NativeXComponentSample::PluginManager::GetInstance()->Release();
return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor classProp[] = {
{"preload", nullptr, Preload, nullptr, nullptr, nullptr, napi_default, nullptr},
{"playNative", nullptr, StartPlay, nullptr, nullptr, nullptr, napi_default, nullptr},
{"destroy", nullptr, Destroy, nullptr, nullptr, nullptr, napi_default, nullptr}
};
napi_define_properties(env, exports, sizeof(classProp) / sizeof(classProp[0]), classProp);
NativeXComponentSample::PluginManager::GetInstance()->Export(env, exports);
return exports;
}
EXTERN_C_END
static napi_module PlayerModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "player",
.nm_priv = ((void *)0),
.reserved = {0}
};
extern "C" __attribute__((constructor)) void RegisterPlayerModule(void) { napi_module_register(&PlayerModule); }