* Copyright (C) 2025 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.
*/
#define MLOG_TAG "MediaCallTranscode"
#include "moving_photo_call_transcoder.h"
#include "medialibrary_errno.h"
#include "medialibrary_napi_log.h"
#include "moving_photo_transcoder_observer.h"
namespace OHOS {
namespace Media {
const char* ON_PROGRESS_FUNC = "onProgress";
bool MovingPhotoCallTranscoder::DoTranscode(const std::shared_ptr<MovingPhotoProgressHandler>
&movingPhotoProgressHandler)
{
if (movingPhotoProgressHandler == nullptr) {
NAPI_ERR_LOG("movingPhotoProgressHandler is null");
return false;
}
auto transCoder = TransCoderFactory::CreateTransCoder();
if (transCoder == nullptr) {
NAPI_ERR_LOG("Failed to create TransCoder");
return false;
}
auto transCoderCb = std::make_shared<OHOS::Media::MovingphotoTranscoderObserver>();
if (transCoderCb == nullptr) {
NAPI_ERR_LOG("Failed to create transCoderCb");
return false;
}
transCoderCb->SetMovingPhotoProgress(movingPhotoProgressHandler);
transCoderCb->setTransCoder(transCoder);
if (transCoder->SetTransCoderCallback(transCoderCb) != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to set TransCoder callback");
}
if (transCoder->SetInputFile(movingPhotoProgressHandler->srcFd.Get(), movingPhotoProgressHandler->offset,
movingPhotoProgressHandler->size) != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to set input file for TransCoder");
}
if (transCoder->SetOutputFile(movingPhotoProgressHandler->destFd.Get()) != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to set output file for TransCoder");
}
if (transCoder->SetOutputFormat(FORMAT_MPEG_4) != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to SetOutputFormat");
}
if (transCoder->SetColorSpace(TRANSCODER_COLORSPACE_P3_FULL) != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to SetColorSpace");
}
if (transCoder->Prepare() != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to prepare TransCoder");
}
if (transCoder->Start() != E_OK) {
return transCoderCb->DoTranscodePrepareError("Failed to TransCoder Start");
}
NAPI_INFO_LOG("DoTranscode success");
return true;
}
bool MovingphotoTranscoderObserver::DoTranscodePrepareError(const std::string &errorMsg)
{
NAPI_ERR_LOG("DoTranscodePrepareError errorMsg:%{public}s", errorMsg.c_str());
isPrepareError.store(true);
if (transCoder_ != nullptr) {
transCoder_->Release();
}
return false;
}
void MovingphotoTranscoderObserver::CallMovingProgressCallback(bool isComplete)
{
NAPI_DEBUG_LOG("CallMovingProgressCallback");
if (movingPhotoProgressHandler_ == nullptr || movingPhotoProgressHandler_->onProgressFunc == nullptr) {
NAPI_ERR_LOG("CallMovingProgressCallback: movingPhotoProgressHandler_ is null");
return;
}
napi_status status = napi_acquire_threadsafe_function(movingPhotoProgressHandler_->onProgressFunc);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
return;
}
auto asyncHandler = std::make_unique<MovingPhotoProgressHandler>();
if (asyncHandler == nullptr) {
NAPI_ERR_LOG("CallMovingProgressCallback: asyncHandler is null");
return;
}
asyncHandler->isComplete = isComplete;
if (isComplete) {
asyncHandler->env = movingPhotoProgressHandler_->env;
asyncHandler->contextData = movingPhotoProgressHandler_->contextData;
asyncHandler->errCode = movingPhotoProgressHandler_->errCode;
asyncHandler->callbackFunc = movingPhotoProgressHandler_->callbackFunc;
} else {
asyncHandler->mediaAssetEnv = movingPhotoProgressHandler_->mediaAssetEnv;
asyncHandler->extra = movingPhotoProgressHandler_->extra;
asyncHandler->progressHandlerRef = movingPhotoProgressHandler_->progressHandlerRef;
}
status = napi_call_threadsafe_function(movingPhotoProgressHandler_->onProgressFunc, (void *)asyncHandler.get(),
napi_tsfn_blocking);
if (status != napi_ok) {
NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
}
(void)asyncHandler.release();
}
void MovingPhotoCallTranscoder::OnProgress(napi_env env, napi_value cb, void *context, void *data)
{
NAPI_DEBUG_LOG("OnProgress");
auto mpHandler = reinterpret_cast<MovingPhotoProgressHandler *>(data);
if (mpHandler == nullptr) {
NAPI_ERR_LOG("Moving photo progress env is null");
return;
}
if (mpHandler->isComplete) {
if (mpHandler->callbackFunc == nullptr) {
NAPI_ERR_LOG("OnProgress callbackFunc is null");
return;
}
mpHandler->callbackFunc(mpHandler->env, mpHandler->contextData, mpHandler->errCode);
return;
}
if (mpHandler->mediaAssetEnv == nullptr) {
NAPI_ERR_LOG("mpHandler mediaAssetEnv is null");
return;
}
napi_value result;
napi_status status = napi_create_int32(mpHandler->mediaAssetEnv,
mpHandler->extra, &result);
if (status != napi_ok) {
NAPI_ERR_LOG("OnProgress napi_create_int32 fail");
return;
}
napi_value jsCallback = nullptr;
status = napi_get_reference_value(mpHandler->mediaAssetEnv,
mpHandler->progressHandlerRef, &jsCallback);
if (status != napi_ok) {
NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
return;
}
napi_value jsOnProgress;
status = napi_get_named_property(mpHandler->mediaAssetEnv, jsCallback, ON_PROGRESS_FUNC,
&jsOnProgress);
if (status != napi_ok) {
NAPI_ERR_LOG("jsOnProgress napi_get_named_property fail, napi status: %{public}d",
static_cast<int>(status));
return;
}
const size_t ARGS_ONE = 1;
napi_value argv[ARGS_ONE];
napi_value retVal = nullptr;
argv[0] = result;
napi_call_function(mpHandler->mediaAssetEnv, nullptr, jsOnProgress, ARGS_ONE, argv, &retVal);
if (status != napi_ok) {
NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", static_cast<int>(status));
}
}
void MovingphotoTranscoderObserver::SetMovingPhotoProgress(
const std::shared_ptr<MovingPhotoProgressHandler> &movingPhotoProgressHandler)
{
movingPhotoProgressHandler_ = movingPhotoProgressHandler;
}
void MovingphotoTranscoderObserver::OnInfo(int32_t type, int32_t extra)
{
NAPI_INFO_LOG("MediaAssetManagerCallback OnInfo type:%{public}d extra:%{public}d", type, extra);
if (movingPhotoProgressHandler_ == nullptr) {
NAPI_ERR_LOG("OnInfo, movingPhotoProgressHandler_ is null");
return;
}
if (type == INFO_TYPE_TRANSCODER_COMPLETED) {
if (transCoder_ == nullptr) {
NAPI_ERR_LOG("transCoder_ is null, cannot release resources");
return;
}
movingPhotoProgressHandler_->errCode = E_OK;
CallMovingProgressCallback(true);
transCoder_->Release();
return;
}
if (movingPhotoProgressHandler_->progressHandlerRef == nullptr) {
NAPI_INFO_LOG("progressHandlerRef is nullptr");
return;
}
movingPhotoProgressHandler_->extra = extra;
CallMovingProgressCallback();
}
void MovingphotoTranscoderObserver::OnError(int32_t errCode, const std::string &errorMsg)
{
NAPI_ERR_LOG("MediaAssetManagerCallback OnError errCode:%{public}d errorMsg:%{public}s",
errCode, errorMsg.c_str());
if (transCoder_ != nullptr) {
transCoder_->Release();
}
if (isPrepareError.load()) {
return;
}
if (movingPhotoProgressHandler_ != nullptr) {
movingPhotoProgressHandler_->errCode = E_ERR;
}
CallMovingProgressCallback(true);
}
}
}