diff --git a/README.md b/README.md index d9cd30498ed004b7a3be5dcd1343359f61356e5d..feae2d250a9e76acd1a2c3177c83743dca2a20d1 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,16 @@ ## 使用说明 -1. 打开应用,点击HDR视频录制,选择Recorder或AVCodec封装方法。 +1. 打开应用,点击AVRecorder或AVCodec进行HDR视频录制。 2. 点击录制视频,完成录制后返回,点击视频播放或暂停视频。 3. 点击保存视频,确认保存。 4. 返回首页,点击HDR视频转码。 5. 点击屏幕选择视频,点击AVCodec或Video_Processing进行SDR转码并送显。 +> **注意**: +> 1. AVRecorder录制不支持设置AVMetadata音视频元数据的HDR类型。 +> 2. 在使用转码的功能时,请选择HDR类型的视频,HDR视频在相册中有HDR标识。 + ## 工程目录 ``` @@ -27,10 +31,10 @@ │ ├──capbilities // 接口能力实现 │ │ ├──include // 编解码模块接口定义 │ │ ├──AudioCapturer.cpp // 音频采集实现 +│ │ ├──AudioDecoder.cpp // 转码音频解码实现 │ │ ├──AudioEncoder.cpp // 音频编码实现 │ │ ├──Demuxer.cpp // 解封装实现 │ │ ├──Muxer.cpp // 封装实现 -│ │ ├──AudioDecoder.cpp // 转码音频解码实现 │ │ ├──Demuxer.cpp // 转码解封装实现 │ │ ├──VideoDecoder.cpp // 转码视频解码实现 │ │ ├──VideoEncoder.cpp // 视频编码实现 @@ -62,11 +66,11 @@ │ │ ├──AVTranscoder.h // AVTranscoder转码功能接口定义 │ │ ├──TranscoderNative.cpp // 转码接口调用入口 │ │ └──TranscoderNative.h // 转码调用入口定义 -│ └──types // Native层暴露上来的接口 -│ ├──libplayer // 转码播放模块暴露给UI层的接口 -│ ├──librecorder // 录制模块暴露给UI层的接口 -│ ├──libtranscoder // 转码模块暴露给UI层的接口 -│ └──CMakeLists.txt // 编译入口 +│ ├──types // Native层暴露上来的接口 +│ │ ├──libplayer // 转码播放模块暴露给UI层的接口 +│ │ ├──librecorder // 录制模块暴露给UI层的接口 +│ │ └──libtranscoder // 转码模块暴露给UI层的接口 +│ └──CMakeLists.txt // 编译入口 ├──ets // UI层 │ ├──common // 公共模块 │ │ ├──utils // 公共工具类 @@ -113,7 +117,7 @@ 视频转码: -1. 用户成功选择文件后,调用playNative转码的接口。 +1. 用户成功选择文件后,调用转码的接口。 2. 开始转码前,调用init函数初始化解封装器、封装器、编码器、解码器。同时保存上下文参数。 3. 调用Start函数开始解码,开启解码线程包括输入子线程和输出子线程对视频数据进行解码。 4. 在输入子线程中,使用解封装后的bufferInfo,调用解码的PushInputData接口将帧buffer、index存入输入队列中。在输出子线程中,把上一步的帧信息储存为bufferInfo后,pop出队,调用FreeOutputData接口后,就会送显并释放buffer。 diff --git a/entry/src/main/cpp/capbilities/AudioCapturer.cpp b/entry/src/main/cpp/capbilities/AudioCapturer.cpp index 0dee5a5bf35b46c334c7d33ea34278dc2e550ef8..c811fc6bdd275afc927e02e528c9c43ed0252305 100644 --- a/entry/src/main/cpp/capbilities/AudioCapturer.cpp +++ b/entry/src/main/cpp/capbilities/AudioCapturer.cpp @@ -16,14 +16,10 @@ #include "AudioCapturer.h" #include "SampleCallback.h" -AudioCapturer::~AudioCapturer() -{ - AudioCapturerRelease(); -} +AudioCapturer::~AudioCapturer() { AudioCapturerRelease(); } // AudioCapturer Callback -static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) -{ +static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) { (void)capturer; CodecUserData *codecUserData = static_cast(userData); if (codecUserData != nullptr) { @@ -33,8 +29,7 @@ static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userDat return 0; } -void AudioCapturer::AudioCapturerInit(SampleInfo &sampleInfo, CodecUserData *audioEncContext) -{ +void AudioCapturer::AudioCapturerInit(SampleInfo &sampleInfo, CodecUserData *audioEncContext) { AudioCapturerRelease(); // Create builder @@ -53,15 +48,13 @@ void AudioCapturer::AudioCapturerInit(SampleInfo &sampleInfo, CodecUserData *aud OH_AudioStreamBuilder_GenerateCapturer(builder_, &audioCapturer_); } -void AudioCapturer::AudioCapturerStart() -{ +void AudioCapturer::AudioCapturerStart() { if (audioCapturer_ != nullptr) { OH_AudioCapturer_Start(audioCapturer_); } } -void AudioCapturer::AudioCapturerRelease() -{ +void AudioCapturer::AudioCapturerRelease() { if (audioCapturer_ != nullptr) { OH_AudioCapturer_Stop(audioCapturer_); OH_AudioCapturer_Release(audioCapturer_); diff --git a/entry/src/main/cpp/capbilities/AudioEncoder.cpp b/entry/src/main/cpp/capbilities/AudioEncoder.cpp index 4391fecfc58c6206d4d981b78c480d7dc08e8298..95a8a86e8d192ee229073c8eaed8900129ef6f9c 100644 --- a/entry/src/main/cpp/capbilities/AudioEncoder.cpp +++ b/entry/src/main/cpp/capbilities/AudioEncoder.cpp @@ -24,24 +24,19 @@ namespace { constexpr int LIMIT_LOGD_FREQUENCY = 50; } -AudioEncoder::~AudioEncoder() -{ - Release(); -} +AudioEncoder::~AudioEncoder() { Release(); } -int32_t AudioEncoder::Create(const std::string &codecMime) -{ +int32_t AudioEncoder::Create(const std::string &codecMime) { encoder_ = OH_AudioCodec_CreateByMime(codecMime.c_str(), true); CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERROR, "Create failed"); return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::SetCallback(CodecUserData *codecUserData) -{ +int32_t AudioEncoder::SetCallback(CodecUserData *codecUserData) { int32_t ret = AV_ERR_OK; ret = OH_AudioCodec_RegisterCallback(encoder_, - { SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange, - SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer }, + {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange, + SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer}, codecUserData); CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERROR, "Set callback failed, ret: %{public}d", ret); AVCODEC_SAMPLE_LOGI("====== AudioEncoder SetCallback ======"); @@ -49,8 +44,7 @@ int32_t AudioEncoder::SetCallback(CodecUserData *codecUserData) return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::Configure(const SampleInfo &sampleInfo) -{ +int32_t AudioEncoder::Configure(const SampleInfo &sampleInfo) { OH_AVFormat *format = OH_AVFormat_Create(); CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERROR, "AVFormat create failed"); @@ -72,8 +66,7 @@ int32_t AudioEncoder::Configure(const SampleInfo &sampleInfo) return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData) -{ +int32_t AudioEncoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecUserData) { CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERROR, "Encoder is null"); CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, AVCODEC_SAMPLE_ERROR, "Invalid param: codecUserData"); @@ -83,8 +76,8 @@ int32_t AudioEncoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecU // SetCallback for audio encoder ret = SetCallback(codecUserData); - CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_OK, AVCODEC_SAMPLE_ERROR, - "Set callback failed, ret: %{public}d", ret); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_OK, AVCODEC_SAMPLE_ERROR, "Set callback failed, ret: %{public}d", + ret); // Prepare audio encoder { @@ -95,8 +88,7 @@ int32_t AudioEncoder::Config(const SampleInfo &sampleInfo, CodecUserData *codecU return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::Start() -{ +int32_t AudioEncoder::Start() { CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERROR, "Encoder is null"); int ret = OH_AudioCodec_Start(encoder_); @@ -104,8 +96,7 @@ int32_t AudioEncoder::Start() return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::PushInputData(CodecBufferInfo &info) -{ +int32_t AudioEncoder::PushInputData(CodecBufferInfo &info) { CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERROR, "Encoder is null"); int32_t ret = OH_AVBuffer_SetBufferAttr(reinterpret_cast(info.buffer), &info.attr); CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERROR, "Set avbuffer attr failed"); @@ -114,8 +105,7 @@ int32_t AudioEncoder::PushInputData(CodecBufferInfo &info) return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::FreeOutputData(uint32_t bufferIndex) -{ +int32_t AudioEncoder::FreeOutputData(uint32_t bufferIndex) { CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERROR, "Encoder is null"); int32_t ret = AVCODEC_SAMPLE_OK; @@ -124,23 +114,15 @@ int32_t AudioEncoder::FreeOutputData(uint32_t bufferIndex) return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::Stop() -{ +int32_t AudioEncoder::Stop() { CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERROR, "Encoder is null"); - - int ret = OH_AudioCodec_Flush(encoder_); - CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERROR, "Flush failed, ret: %{public}d", ret); - - ret = OH_AudioCodec_Stop(encoder_); + int ret = OH_AudioCodec_Stop(encoder_); CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERROR, "Stop failed, ret: %{public}d", ret); return AVCODEC_SAMPLE_OK; } -int32_t AudioEncoder::Release() -{ +int32_t AudioEncoder::Release() { if (encoder_ != nullptr) { - OH_AudioCodec_Flush(encoder_); - OH_AudioCodec_Stop(encoder_); OH_AudioCodec_Destroy(encoder_); encoder_ = nullptr; } diff --git a/entry/src/main/cpp/capbilities/Muxer.cpp b/entry/src/main/cpp/capbilities/Muxer.cpp index 6f38c2c369288acf02288cfbbb81a3ce6c7a8be3..74f14660411ec064e2d2c5ee7ba99c9c5f6e40f7 100644 --- a/entry/src/main/cpp/capbilities/Muxer.cpp +++ b/entry/src/main/cpp/capbilities/Muxer.cpp @@ -38,13 +38,13 @@ int32_t Muxer::Create(int32_t fd) { int32_t Muxer::Config(SampleInfo &sampleInfo) { CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERROR, "Muxer is null"); - + OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(sampleInfo.audioCodecMime.data(), sampleInfo.audioSampleRate, sampleInfo.audioChannelCount); CHECK_AND_RETURN_RET_LOG(formatAudio != nullptr, AVCODEC_SAMPLE_ERROR, "Create audio format failed"); OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_PROFILE, AAC_PROFILE_LC); int32_t ret = OH_AVMuxer_AddTrack(muxer_, &audioTrackId_, formatAudio); - OH_AVFormat_Destroy(formatAudio); + OH_AVFormat_Destroy(formatAudio); OH_AVFormat *formatVideo = OH_AVFormat_CreateVideoFormat(sampleInfo.videoCodecMime.data(), sampleInfo.videoWidth, sampleInfo.videoHeight); @@ -81,7 +81,7 @@ int32_t Muxer::Start() { return AVCODEC_SAMPLE_OK; } -int32_t Muxer::WriteSample(int32_t trackId, OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr){ +int32_t Muxer::WriteSample(int32_t trackId, OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) { CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERROR, "Muxer is null"); CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCODEC_SAMPLE_ERROR, "Get a empty buffer"); diff --git a/entry/src/main/cpp/capbilities/VideoProcessing.cpp b/entry/src/main/cpp/capbilities/VideoProcessing.cpp index bca2e8cd8176678185d754ea2f2766376e7ca4bd..51f471ff28311bb2f7d00f4992a8e0e2cd4316df 100644 --- a/entry/src/main/cpp/capbilities/VideoProcessing.cpp +++ b/entry/src/main/cpp/capbilities/VideoProcessing.cpp @@ -81,7 +81,8 @@ bool VideoProcessing::IsColorSpaceConversionSupported(SampleInfo &sampleInfo) { } void VideoProcessing::StartProcessing() { - VideoProcessing_ErrorCode ret = OH_VideoProcessing_Start(processor);; + VideoProcessing_ErrorCode ret = OH_VideoProcessing_Start(processor); + ; CHECK_AND_RETURN_LOG(ret == VIDEO_PROCESSING_SUCCESS, "OH_VideoProcessing_Start failed"); } diff --git a/entry/src/main/cpp/capbilities/include/AudioCapturer.h b/entry/src/main/cpp/capbilities/include/AudioCapturer.h index 1fd8898a78f34eca77383f01b55d99978c6ea731..ec5f8f59dd6f3468117810ed27cc1023926753e4 100644 --- a/entry/src/main/cpp/capbilities/include/AudioCapturer.h +++ b/entry/src/main/cpp/capbilities/include/AudioCapturer.h @@ -27,7 +27,7 @@ public: AudioCapturer() = default; ~AudioCapturer(); - void AudioCapturerInit(SampleInfo& sampleInfo, CodecUserData *audioEncContext); + void AudioCapturerInit(SampleInfo &sampleInfo, CodecUserData *audioEncContext); void AudioCapturerStart(); void AudioCapturerRelease(); @@ -36,5 +36,4 @@ private: OH_AudioStreamBuilder *builder_ = nullptr; }; - #endif // AVCODECVIDEO_AUDIOCAPTURER_H diff --git a/entry/src/main/cpp/capbilities/include/AudioEncoder.h b/entry/src/main/cpp/capbilities/include/AudioEncoder.h index 63c52bfd05d6caa2e5bea17e559a28ebb2e5bd81..5ab4f95da89f03dd827ac2be149c8f2de92bf23e 100644 --- a/entry/src/main/cpp/capbilities/include/AudioEncoder.h +++ b/entry/src/main/cpp/capbilities/include/AudioEncoder.h @@ -32,11 +32,11 @@ public: int32_t FreeOutputData(uint32_t bufferIndex); int32_t Stop(); int32_t Release(); - + private: int32_t SetCallback(CodecUserData *codecUserData); int32_t Configure(const SampleInfo &sampleInfo); - + bool isAVBufferMode_ = false; OH_AVCodec *encoder_ = nullptr; }; diff --git a/entry/src/main/cpp/capbilities/include/Demuxer.h b/entry/src/main/cpp/capbilities/include/Demuxer.h index 5fb297eec49b64ab6f4e903b1f966073f22a654a..fe5d212bfceb105558451f2da807eae43f6375b8 100644 --- a/entry/src/main/cpp/capbilities/include/Demuxer.h +++ b/entry/src/main/cpp/capbilities/include/Demuxer.h @@ -28,11 +28,11 @@ public: int32_t Release(); int32_t GetVideoTrackId(); int32_t GetAudioTrackId(); - + private: int32_t GetTrackInfo(std::shared_ptr sourceFormat, SampleInfo &info); OH_AVPixelFormat ConvertPixelFormat(int32_t pixelFormat); - + OH_AVSource *source_ = nullptr; OH_AVDemuxer *demuxer_ = nullptr; int32_t videoTrackId_ = -1; diff --git a/entry/src/main/cpp/capbilities/include/VideoEncoder.h b/entry/src/main/cpp/capbilities/include/VideoEncoder.h index f9ffb69d2f8b41289a8ea910f4110c9332faf386..9d5ef5335bcbb08a92f32b31a6f584ba44e63672 100644 --- a/entry/src/main/cpp/capbilities/include/VideoEncoder.h +++ b/entry/src/main/cpp/capbilities/include/VideoEncoder.h @@ -32,7 +32,7 @@ public: int32_t NotifyEndOfStream(); int32_t Stop(); int32_t Release(); - + private: int32_t SetCallback(CodecUserData *codecUserData); int32_t Configure(const SampleInfo &sampleInfo); diff --git a/entry/src/main/cpp/common/SampleInfo.h b/entry/src/main/cpp/common/SampleInfo.h index 3b3f1ab60db2825d9157b55b730dc2fb68d75543..e6ab68143c3be3c532e92dfc3fbb0f192741e7c6 100644 --- a/entry/src/main/cpp/common/SampleInfo.h +++ b/entry/src/main/cpp/common/SampleInfo.h @@ -82,7 +82,7 @@ struct SampleInfo { int32_t rotation = 0; OHNativeWindow *window = nullptr; - + int8_t processType = 0; // 0none,1HDR,2Color int8_t metaData = OH_VIDEO_NONE; OH_NativeBuffer_ColorSpace colorSpace = OH_COLORSPACE_BT709_LIMIT; @@ -90,7 +90,7 @@ struct SampleInfo { VideoProcessing_ColorSpaceInfo outputFormat; OHNativeWindow *inWindow = nullptr; OHNativeWindow *outWindow = nullptr; - + int8_t vpErrorCode = 0; void (*playDoneCallback)(void *context) = nullptr; void *playDoneCallbackData = nullptr; diff --git a/entry/src/main/cpp/render/include/PluginRender.h b/entry/src/main/cpp/render/include/PluginRender.h index bccae2e1a6dd29323962db5f09d6528f79ccc8ee..2cd5a5d2d73c094639e30d79f41c35fa11c8782d 100644 --- a/entry/src/main/cpp/render/include/PluginRender.h +++ b/entry/src/main/cpp/render/include/PluginRender.h @@ -25,8 +25,7 @@ namespace NativeXComponentSample { class PluginRender { public: explicit PluginRender(std::string &id); - ~PluginRender() { - } + ~PluginRender() {} static PluginRender *GetInstance(std::string &id); static void Release(std::string &id); void Export(napi_env env, napi_value exports); diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index 19444936a8bfbe7824c6cd70c618c29c372d9957..fc7a752a44b4192b6a01b3cb75e9e9fdb9275068 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -193,7 +193,6 @@ void Player::Release() { videoDecContext_->inputCond.notify_all(); videoDecContext_->outputCond.notify_all(); } - if (audioDecContext_) { audioDecContext_->inputCond.notify_all(); audioDecContext_->outputCond.notify_all(); @@ -216,7 +215,7 @@ void Player::Release() { videoDecoder_->Release(); videoDecoder_.reset(); } - + if (videoDecContext_ != nullptr) { delete videoDecContext_; videoDecContext_ = nullptr; @@ -232,10 +231,6 @@ void Player::Release() { doneCond_.notify_all(); } -void Player::WaitForStop() { - StartRelease(); -} - void Player::StartRelease() { if (isReleased_) { return; @@ -364,9 +359,6 @@ void Player::AudioDecOutputThread() { return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; }); } - std::unique_lock lockRender(audioDecContext_->renderMutex); - audioDecContext_->renderCond.wait_for(lockRender, 50ms, - [this]() { return audioDecContext_->renderQueue.size() < 1; }); AVCODEC_SAMPLE_LOGI("Out buffer end"); StartRelease(); } \ No newline at end of file diff --git a/entry/src/main/cpp/sample/player/Player.h b/entry/src/main/cpp/sample/player/Player.h index fcd0dfb347d08ec052f99a75f788ff53b6ede95c..564ffc23d42f720188834f74699994060e1f620a 100644 --- a/entry/src/main/cpp/sample/player/Player.h +++ b/entry/src/main/cpp/sample/player/Player.h @@ -32,18 +32,18 @@ class Player { public: Player(){}; ~Player(); - + static Player &GetInstance() { static Player player; return player; } - + int32_t Init(SampleInfo &sampleInfo); int32_t Start(); int32_t Pause(); int32_t Resume(); void StartRelease(); - void WaitForStop(); + private: void VideoDecInputThread(); void VideoDecOutputThread(); @@ -56,7 +56,7 @@ private: std::unique_ptr videoDecoder_ = nullptr; std::shared_ptr audioDecoder_ = nullptr; std::unique_ptr demuxer_ = nullptr; - + std::mutex mutex_; std::atomic isStarted_{false}; std::atomic isReleased_{false}; @@ -71,8 +71,8 @@ private: CodecUserData *audioDecContext_ = nullptr; OH_AudioStreamBuilder *builder_ = nullptr; OH_AudioRenderer *audioRender_ = nullptr; - + static constexpr int64_t MICROSECOND = 1000000; }; -#endif //VIDEOPROCESSING_PLAYER_H +#endif // VIDEOPROCESSING_PLAYER_H diff --git a/entry/src/main/cpp/sample/player/PlayerNative.cpp b/entry/src/main/cpp/sample/player/PlayerNative.cpp index f958bb0d8581d57d9441eb21c3b0ac46835d8d6b..6739b49a82568d7dc802896f32d65e51a031ba76 100644 --- a/entry/src/main/cpp/sample/player/PlayerNative.cpp +++ b/entry/src/main/cpp/sample/player/PlayerNative.cpp @@ -70,7 +70,7 @@ napi_value PlayerNative::SwitchVideo(napi_env env, napi_callback_info info) { napi_value PlayerNative::StartRelease(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "playerNative", "StartRelease123"); // delete all resource - Player::GetInstance().WaitForStop(); + Player::GetInstance().StartRelease(); return nullptr; } diff --git a/entry/src/main/cpp/sample/recorder/Recorder.cpp b/entry/src/main/cpp/sample/recorder/Recorder.cpp index 6397f1bf92280e85ea3a98a08ef2336d7a8ef579..d3f7cadeed1d22b9f353d90d53cfd262928cb7c4 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.cpp +++ b/entry/src/main/cpp/sample/recorder/Recorder.cpp @@ -31,8 +31,7 @@ Recorder::~Recorder() { StartRelease(); } int32_t Recorder::Init(SampleInfo &sampleInfo) { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERROR, "Already started."); - CHECK_AND_RETURN_RET_LOG(videoEncoder_ == nullptr && muxer_ == nullptr, AVCODEC_SAMPLE_ERROR, - "Already started."); + CHECK_AND_RETURN_RET_LOG(videoEncoder_ == nullptr && muxer_ == nullptr, AVCODEC_SAMPLE_ERROR, "Already started."); sampleInfo_ = sampleInfo; // Audio Capturer Init @@ -67,8 +66,7 @@ int32_t Recorder::Start() { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(encContext_ != nullptr, AVCODEC_SAMPLE_ERROR, "Already started."); - CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERROR, - "Already started."); + CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERROR, "Already started."); int32_t ret = muxer_->Start(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_OK, ret, "Muxer start failed"); @@ -217,8 +215,11 @@ int32_t Recorder::WaitForDone() { } int32_t Recorder::Stop() { - int32_t ret = videoEncoder_->NotifyEndOfStream(); - CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_OK, ret, "Encoder notifyEndOfStream failed"); + if (isStarted_) { + int32_t ret = videoEncoder_->NotifyEndOfStream(); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_OK, ret, "Encoder notifyEndOfStream failed"); + } + StartRelease(); return WaitForDone(); } @@ -265,7 +266,7 @@ void Recorder::AudioEncInputThread() { CodecBufferInfo bufferInfo = audioEncContext_->inputBufferInfoQueue.front(); audioEncContext_->inputBufferInfoQueue.pop(); audioEncContext_->inputFrameCount++; - + uint8_t *inputBufferAddr = OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)); audioEncContext_->ReadCache(inputBufferAddr, sampleInfo_.audioMaxInputSize); lock.unlock(); diff --git a/entry/src/main/cpp/sample/recorder/Recorder.h b/entry/src/main/cpp/sample/recorder/Recorder.h index 92cf0f16f8802ab572d6ff01e13f5b7560a8425e..9567d014f67d1d9ea7703bd9d4165af253a2b57f 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.h +++ b/entry/src/main/cpp/sample/recorder/Recorder.h @@ -47,7 +47,7 @@ private: void Release(); void StartRelease(); int32_t WaitForDone(); - + int32_t CreateAudioEncoder(); int32_t CreateVideoEncoder(); diff --git a/entry/src/main/cpp/sample/recorder/RecorderNative.h b/entry/src/main/cpp/sample/recorder/RecorderNative.h index f518e75634fd4e703be02ce3ecfb1051e64e7a63..da81ed501ca8cbe4fe7a3b6c11f3c73ac6aa6ae0 100644 --- a/entry/src/main/cpp/sample/recorder/RecorderNative.h +++ b/entry/src/main/cpp/sample/recorder/RecorderNative.h @@ -21,7 +21,6 @@ #include "napi/native_api.h" #include "Recorder.h" - class RecorderNative { public: static napi_value Init(napi_env env, napi_callback_info info); diff --git a/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.cpp b/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.cpp index 8ae2557c2eafd9a1caa29f55e9a946adf3b806ee..745e40e6d741de3b265933da16449860a64dce05 100644 --- a/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.cpp +++ b/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.cpp @@ -38,13 +38,17 @@ AVCodecTranscoder::~AVCodecTranscoder() { AVCodecTranscoder::StartEncRelease(); } -bool AVCodecTranscoder::GetIsDecStarted() { return isDecStarted_; } - -bool AVCodecTranscoder::GetIsEncStarted() { return isEncStarted_; } - - void AVCodecTranscoder::NotifyEndOfStream() { videoEncoder_->NotifyEndOfStream(); } +bool AVCodecTranscoder::IsHDR(const SampleInfo &sampleInfo) { + sampleInfo_ = sampleInfo; + demuxer_ = std::make_unique(); + demuxer_->Create(sampleInfo_); + demuxer_->Release(); + demuxer_ = nullptr; + return sampleInfo_.isHDRVivid; +} + int32_t AVCodecTranscoder::PreInit(const SampleInfo &sampleInfo) { CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(demuxer_ == nullptr && videoDecoder_ == nullptr, AVCODEC_SAMPLE_ERROR, "Already started."); @@ -148,6 +152,17 @@ void AVCodecTranscoder::StartDecRelease() { } } +void AVCodecTranscoder::StartRelease() { + if (!isDecReleased_) { + isDecReleased_ = true; + DecRelease(); + } + if (!isEncReleased_) { + isEncReleased_ = true; + EncRelease(); + } +} + void AVCodecTranscoder::DecRelease() { isDecStarted_ = false; AVCODEC_SAMPLE_LOGI("DecRelease Succeed: %{public}d, %{public}d", isDecStarted_.load(), isEncStarted_.load()); @@ -209,7 +224,9 @@ void AVCodecTranscoder::EncRelease() { } std::string id("AVCodecTranscoder"); AVCODEC_SAMPLE_LOGI("EncRelease Succeed"); - sampleInfo_.playDoneCallback(sampleInfo_.playDoneCallbackData); + if (sampleInfo_.playDoneCallback != nullptr) { + sampleInfo_.playDoneCallback(sampleInfo_.playDoneCallbackData); + } } void AVCodecTranscoder::VideoDecInputThread() { @@ -231,7 +248,7 @@ void AVCodecTranscoder::VideoDecInputThread() { bufferInfo.attr); int32_t ret = videoDecoder_->PushInputBuffer(bufferInfo); - AVCODEC_SAMPLE_LOGW("Out buffer count: %{public}u, size: %{public}d, flag: %{public}u, pts: %{public}" PRId64, + AVCODEC_SAMPLE_LOGW("Out buffer count: %{public}u, size: %{public}d, flag: %{public}u, pts: %{public}" PRId64, videoDecContext_->inputFrameCount, bufferInfo.attr.size, bufferInfo.attr.flags, bufferInfo.attr.pts); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_OK, "Push data failed, thread out"); @@ -273,7 +290,6 @@ void AVCodecTranscoder::VideoDecOutputThread() { StartDecRelease(); } - void AVCodecTranscoder::VideoEncOutputThread() { while (true) { CHECK_AND_BREAK_LOG(isEncStarted_, "Work done, thread out"); @@ -305,7 +321,6 @@ void AVCodecTranscoder::VideoEncOutputThread() { int32_t ret = videoEncoder_->FreeOutputBuffer(bufferInfo.bufferIndex); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_OK, "Encoder output thread out"); } - AVCODEC_SAMPLE_LOGI("Exit, frame count: %{public}u", videoEncContext_->inputFrameCount); StartEncRelease(); } diff --git a/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.h b/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.h index 56654c39d2b14c8b5ac450e4098ea6f559a7f021..3fa5a11b96d10e1aaa3a948b76c58f9296ea8d49 100644 --- a/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.h +++ b/entry/src/main/cpp/sample/transcoder/AVCodecTranscoder.h @@ -31,23 +31,21 @@ public: AVCodecTranscoder(){}; ~AVCodecTranscoder(); - static AVCodecTranscoder &GetInstance() - { + static AVCodecTranscoder &GetInstance() { static AVCodecTranscoder avCodecTranscoder; return avCodecTranscoder; } - bool GetIsDecStarted(); - bool GetIsEncStarted(); void NotifyEndOfStream(); + bool IsHDR(const SampleInfo &sampleInfo); int32_t PreInit(const SampleInfo &sampleInfo); int32_t MuxerAndDemuxerInit(SampleInfo &sampleInfo); int32_t EncoderInit(SampleInfo &sampleInfo); int32_t AfterInit(); int32_t Start(); - void SetNativeImageWindow(OHNativeWindow * nativeImageWindow); void StartDecRelease(); void StartEncRelease(); + void StartRelease(); private: void VideoDecInputThread(); @@ -55,9 +53,9 @@ private: void VideoEncOutputThread(); void DecRelease(); void EncRelease(); - + int32_t CreateVideoDecoder(); - + std::unique_ptr muxer_ = nullptr; std::unique_ptr demuxer_ = nullptr; std::unique_ptr videoProcessing = nullptr; @@ -65,13 +63,13 @@ private: std::shared_ptr audioDecoder_ = nullptr; std::unique_ptr videoEncoder_ = nullptr; std::shared_ptr audioEncoder_ = nullptr; - + std::mutex mutex_; - std::atomic isStarted_{ false }; - std::atomic isDecStarted_{ false }; - std::atomic isEncStarted_{ false }; - std::atomic isEncReleased_{ false }; - std::atomic isDecReleased_{ false }; + std::atomic isStarted_{false}; + std::atomic isDecStarted_{false}; + std::atomic isEncStarted_{false}; + std::atomic isEncReleased_{false}; + std::atomic isDecReleased_{false}; std::unique_ptr videoDecInputThread_ = nullptr; std::unique_ptr videoDecOutputThread_ = nullptr; std::unique_ptr videoEncOutputThread_ = nullptr; @@ -91,4 +89,4 @@ private: static constexpr int64_t NANO_TO_S = 1000000000; }; -#endif //HDR2SDR_AVCODECTRANSCODER_H +#endif // HDR2SDR_AVCODECTRANSCODER_H diff --git a/entry/src/main/cpp/sample/transcoder/AVTranscoder.cpp b/entry/src/main/cpp/sample/transcoder/AVTranscoder.cpp index 68b709bdfee03308021f158eef470ed3acf71b39..49f12d17bfdf5bd821575772dc4f1faf4f09cf04 100644 --- a/entry/src/main/cpp/sample/transcoder/AVTranscoder.cpp +++ b/entry/src/main/cpp/sample/transcoder/AVTranscoder.cpp @@ -70,8 +70,19 @@ void AVTranscoder::OnErrorCb(OH_AVTranscoder *transcoder, int32_t errorCode, con AVTranscoder::GetInstance().ReleaseAVTranscoder(); } +int32_t AVTranscoder::StopAVTranscoder() { + OH_AVErrCode result = AV_ERR_OK; + if (transcoder != nullptr) { + result = OH_AVTranscoder_Cancel(transcoder); + if (result != AV_ERR_OK) { + AVCODEC_SAMPLE_LOGI("Transcoder prepare failed, ret %{public}d", result); + } + } + return result; +} + int32_t AVTranscoder::ReleaseAVTranscoder() { - int ret = 100; + int ret = 0; AVCODEC_SAMPLE_LOGI("OH_AVTranscoder_Release ret:%{public}d", ret); if (transcoder != nullptr) { ret = OH_AVTranscoder_Release(transcoder); diff --git a/entry/src/main/cpp/sample/transcoder/AVTranscoder.h b/entry/src/main/cpp/sample/transcoder/AVTranscoder.h index 34135828f50f6d946ee2bf94031afb24d0b43437..6ff4eb53ab2ec55aaaead7f4f12800489fe446eb 100644 --- a/entry/src/main/cpp/sample/transcoder/AVTranscoder.h +++ b/entry/src/main/cpp/sample/transcoder/AVTranscoder.h @@ -27,7 +27,7 @@ public: static AVTranscoder avTranscoder; return avTranscoder; } - + OH_AVTranscoder *transcoder = nullptr; OH_AVTranscoder_Config *config = nullptr; int32_t result = 0; @@ -35,9 +35,9 @@ public: int32_t StartAVTranscoder(const SampleInfo &sampleInfo); void CreateDefaultTransCoderConfig(int32_t dstFd); static void AvTranscoderStateChangeCb(OH_AVTranscoder *transcoder, OH_AVTranscoder_State state, void *userData); - static void OnErrorCb(OH_AVTranscoder *transcoder, int32_t errorCode, const char *errorMsg, void *userData); -private: + static void OnErrorCb(OH_AVTranscoder *transcoder, int32_t errorCode, const char *errorMsg, void *userData); + int32_t StopAVTranscoder(); int32_t ReleaseAVTranscoder(); }; -#endif //HDR2SDR_AVTRANSCODER_H +#endif // HDR2SDR_AVTRANSCODER_H diff --git a/entry/src/main/cpp/sample/transcoder/TranscoderNative.cpp b/entry/src/main/cpp/sample/transcoder/TranscoderNative.cpp index a51bd2d5bbabbe03205f4a7ec5cd646ba1093570..0a36cd06192afd67215d143d73ab48c044380cc8 100644 --- a/entry/src/main/cpp/sample/transcoder/TranscoderNative.cpp +++ b/entry/src/main/cpp/sample/transcoder/TranscoderNative.cpp @@ -48,6 +48,21 @@ void Callback(void *asyncContext) { }); } +napi_value TranscoderNative::IsHdr(napi_env env, napi_callback_info info) { + SampleInfo sampleInfo; + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + napi_get_value_int32(env, args[0], &sampleInfo.inputFd); + napi_get_value_int64(env, args[1], &sampleInfo.inputFileSize); + + napi_value value; + bool isHdr = AVCodecTranscoder::GetInstance().IsHDR(sampleInfo); + napi_get_boolean(env, isHdr, &value); + return value; +} + napi_value TranscoderNative::StartAVTranscoder(napi_env env, napi_callback_info info) { SampleInfo sampleInfo; size_t argc = 3; @@ -57,7 +72,7 @@ napi_value TranscoderNative::StartAVTranscoder(napi_env env, napi_callback_info napi_get_value_int32(env, args[0], &sampleInfo.inputFd); napi_get_value_int64(env, args[1], &sampleInfo.inputFileSize); napi_get_value_int32(env, args[2], &sampleInfo.outputFd); - + AVTranscoder::GetInstance().StartAVTranscoder(sampleInfo); return nullptr; } @@ -90,6 +105,11 @@ napi_value TranscoderNative::StartAVCodecTranscoder(napi_env env, napi_callback_ return nullptr; } +napi_value TranscoderNative::ReleaseAVCodecTranscoder(napi_env env, napi_callback_info info) { + AVCodecTranscoder::GetInstance().StartRelease(); + return nullptr; +} + napi_value TranscoderNative::StartVideoProcessingTranscoder(napi_env env, napi_callback_info info) { SampleInfo sampleInfo; size_t argc = 4; @@ -112,7 +132,7 @@ napi_value TranscoderNative::StartVideoProcessingTranscoder(napi_env env, napi_c sampleInfo.outputFormat.metadataType = OH_VIDEO_NONE; sampleInfo.outputFormat.colorSpace = OH_COLORSPACE_BT709_LIMIT; sampleInfo.outputFormat.pixelFormat = NATIVEBUFFER_PIXEL_FMT_YCBCR_420_SP; - + int32_t ret = AVCodecTranscoder::GetInstance().PreInit(sampleInfo); ret = AVCodecTranscoder::GetInstance().AfterInit(); AVCodecTranscoder::GetInstance().Start(); @@ -143,7 +163,7 @@ napi_value TranscoderNative::StartTransformColorspace(napi_env env, napi_callbac sampleInfo.outputFormat.metadataType = OH_VIDEO_HDR_VIVID; sampleInfo.outputFormat.colorSpace = OH_COLORSPACE_BT2020_PQ_LIMIT; sampleInfo.outputFormat.pixelFormat = NATIVEBUFFER_PIXEL_FMT_YCBCR_P010; - + int32_t ret = AVCodecTranscoder::GetInstance().PreInit(sampleInfo); ret = AVCodecTranscoder::GetInstance().AfterInit(); AVCodecTranscoder::GetInstance().Start(); @@ -154,11 +174,19 @@ napi_value TranscoderNative::StartTransformColorspace(napi_env env, napi_callbac EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { - {"startAVTranscoder", nullptr, TranscoderNative::StartAVTranscoder, nullptr, nullptr, nullptr, napi_default, nullptr}, - {"startAVCodecTranscoder", nullptr, TranscoderNative::StartAVCodecTranscoder, nullptr, nullptr, nullptr, napi_default, nullptr}, - {"startVideoProcessingTranscoder", nullptr, TranscoderNative::StartVideoProcessingTranscoder, nullptr, nullptr, nullptr, napi_default, nullptr}, - {"startTransformColorspace", nullptr, TranscoderNative::StartTransformColorspace, nullptr, nullptr, nullptr, napi_default, nullptr}, - {"getAVTranscoderState", nullptr, TranscoderNative::GetAVTranscoderState, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"isHdr", nullptr, TranscoderNative::IsHdr, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"startAVTranscoder", nullptr, TranscoderNative::StartAVTranscoder, nullptr, nullptr, nullptr, napi_default, + nullptr}, + {"startAVCodecTranscoder", nullptr, TranscoderNative::StartAVCodecTranscoder, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"startVideoProcessingTranscoder", nullptr, TranscoderNative::StartVideoProcessingTranscoder, nullptr, nullptr, + nullptr, napi_default, nullptr}, + {"startTransformColorspace", nullptr, TranscoderNative::StartTransformColorspace, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"getAVTranscoderState", nullptr, TranscoderNative::GetAVTranscoderState, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"releaseAVCodecTranscoder", nullptr, TranscoderNative::ReleaseAVCodecTranscoder, nullptr, nullptr, nullptr, + napi_default, nullptr}, }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; diff --git a/entry/src/main/cpp/sample/transcoder/TranscoderNative.h b/entry/src/main/cpp/sample/transcoder/TranscoderNative.h index fa4b8bfac25f9b523abbbf5927d251b8e1d67bc1..c8fca8299c896448ff4118e1f9a6acf2ac616485 100644 --- a/entry/src/main/cpp/sample/transcoder/TranscoderNative.h +++ b/entry/src/main/cpp/sample/transcoder/TranscoderNative.h @@ -22,11 +22,13 @@ class TranscoderNative { public: + static napi_value IsHdr(napi_env env, napi_callback_info info); static napi_value StartAVTranscoder(napi_env env, napi_callback_info info); static napi_value StartAVCodecTranscoder(napi_env env, napi_callback_info info); static napi_value StartVideoProcessingTranscoder(napi_env env, napi_callback_info info); static napi_value GetAVTranscoderState(napi_env env, napi_callback_info info); static napi_value StartTransformColorspace(napi_env env, napi_callback_info info); + static napi_value ReleaseAVCodecTranscoder(napi_env env, napi_callback_info info); }; #endif // VIDEO_CODEC_SAMPLE_TRANSCODER_NATIVE_H \ No newline at end of file diff --git a/entry/src/main/cpp/types/libtranscoder/index.d.ts b/entry/src/main/cpp/types/libtranscoder/index.d.ts index 0000c9909d6728e8010dc427772e7e6b480e9d1e..e14a210c3d1af380f129c7ee32933d25e7a7ae59 100644 --- a/entry/src/main/cpp/types/libtranscoder/index.d.ts +++ b/entry/src/main/cpp/types/libtranscoder/index.d.ts @@ -20,6 +20,11 @@ // cbFn: () => void // ) => void; +export const isHdr: ( + inputFileFd: number, + inputFileSize: number +) => boolean; + export const startAVTranscoder: ( inputFileFd: number, inputFileSize: number, @@ -49,6 +54,8 @@ export const startTransformColorspace: ( export const getAVTranscoderState: () => number; +export const releaseAVCodecTranscoder: () => void; + export class Response { code: number surfaceId: string diff --git a/entry/src/main/ets/common/CommonEnum.ets b/entry/src/main/ets/common/CommonEnum.ets index 9594ae383e5cab0850e164deb5b42916d28f6640..3fcbe1fe4b47ee09dcdb4e4446e7aeb6e7827184 100644 --- a/entry/src/main/ets/common/CommonEnum.ets +++ b/entry/src/main/ets/common/CommonEnum.ets @@ -16,11 +16,12 @@ export enum VideoStatus { NO_VIDEO = 0, // No videos SELECTED_VIDEOS = 1, // Selected videos - OPTIMIZE_VIDEOS = 2 // Optimize videos + OPTIMIZE_VIDEOS = 2, // Optimize videos + TRANSCODER_VIDEOS = 3 // Optimize videos } export enum StatusEnum { - UNAVAILABLE = 0, // unavailable - AVAILABLE = 1, // available - SELECTED = 2 // selected + UNAVAILABLE = 0, // unavailable + AVAILABLE = 1, // available + SELECTED = 2 // selected } \ No newline at end of file diff --git a/entry/src/main/ets/common/utils/VideoOperationUtils.ets b/entry/src/main/ets/common/utils/VideoOperationUtils.ets index 3081342d49692fbced404a18b0a7d9840fb4d3ee..9c38a3eafd4441914008adf528bc0ac1fafa001d 100644 --- a/entry/src/main/ets/common/utils/VideoOperationUtils.ets +++ b/entry/src/main/ets/common/utils/VideoOperationUtils.ets @@ -28,10 +28,10 @@ export async function saveFile(context: Context) { const srcUri: string = fileUri.getUriFromPath(AppStorage.get('path')); // Create album resources try { - const asset = await helper.createAsset(photoAccessHelper.PhotoType.VIDEO, 'mp4', { - title: `Video_${DATETIME.getDate()}_${DATETIME.getTime()}` - }); - // Write sandbox file to album + const asset = await helper.createAsset(photoAccessHelper.PhotoType.VIDEO, 'mp4', { + title: `Video_${DATETIME.getDate()}_${DATETIME.getTime()}` + }); + // Write sandbox file to album const srcFd = await fileIo.open(srcUri, fileIo.OpenMode.READ_ONLY); const destFd = await fileIo.open(asset, fileIo.OpenMode.WRITE_ONLY); await fileIo.copyFile(srcFd.fd, destFd.fd); @@ -55,7 +55,8 @@ export function setVideoStabilizationMode(session: camera.VideoSession): boolean let activeVideoStabilizationMode = session.getActiveVideoStabilizationMode(); hilog.info(0x0000, TAG, `activeVideoStabilizationMode: ${activeVideoStabilizationMode}`); } catch (error) { - hilog.error(0x0000, TAG, `setVideoStabilizationMode failed. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `setVideoStabilizationMode failed. code is =${error.code}, message is = ${error.message}`); } } else { hilog.info(0x0000, TAG, `videoStabilizationMode: ${mode} is not support`); @@ -70,7 +71,8 @@ export function isVideoStabilizationModeSupported(session: camera.VideoSession, isSupported = session.isVideoStabilizationModeSupported(mode); } catch (error) { // Failed to return error code error. code and handle it. - hilog.error(0x0000, TAG, `The isVideoStabilizationModeSupported call failed. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `The isVideoStabilizationModeSupported call failed. code is =${error.code}, message is = ${error.message}`); } return isSupported; } @@ -99,7 +101,8 @@ export function getSupportedColorSpaces(session: camera.VideoSession): Array { + curWindow.setWindowKeepScreenOn(isKeepScreenOn, (err: BusinessError) => { + if (err.code) { + Logger.error(`Failed to set the screen. Cause code: ${err.code}, message: ${err.message}`); + return; + } + Logger.info(`Succeeded in setting the screen ${isKeepScreenOn}.`); + }); + }).catch((err: string) => { + Logger.error(`Failed to obtain the top window.. Cause code:: ${err}`); + }); +} \ No newline at end of file diff --git a/entry/src/main/ets/controller/AVCodecController.ets b/entry/src/main/ets/controller/AVCodecController.ets index 07001a0b9d29189e036437bf7178010fcca00659..a95f7fd8583ba4b60d593f5443dc70340ab8cfff 100644 --- a/entry/src/main/ets/controller/AVCodecController.ets +++ b/entry/src/main/ets/controller/AVCodecController.ets @@ -36,10 +36,7 @@ export class AVCodecController { private encoderVideoOutput: camera.VideoOutput | undefined = undefined; private XComponentPreviewOutput: camera.PreviewOutput | undefined = undefined; - public async createRecorder(context: common.Context, XComponentSurfaceId: string): Promise { - this.releaseCamera().catch((error: BusinessError) => { - Logger.error(TAG, `releaseCamera fail. code is =${error.code}, message is = ${error.message}`); - }); + public async createRecorder(context: common.Context, XComponentSurfaceId: string, filePath: string): Promise { // Create the CameraManager object. try { this.cameraManager = camera.getCameraManager(context); @@ -51,7 +48,7 @@ export class AVCodecController { return; } - this.path = context.filesDir + `/VIDEO_${DATETIME.getDate()}_${DATETIME.getTime()}.mp4`; + this.path = filePath; let file = FileUtil.createOrOpen(this.path); if (file) { this.cameraData.outputfd = file.fd; @@ -296,6 +293,8 @@ export class AVCodecController { public async stopRecord(): Promise { recorder.stopNative(); - AppStorage.set('path', this.path); + this.releaseCamera().catch((error: BusinessError) => { + Logger.error(TAG, `releaseCamera fail. code is =${error.code}, message is = ${error.message}`); + }); } } \ No newline at end of file diff --git a/entry/src/main/ets/controller/AVPlayerController.ets b/entry/src/main/ets/controller/AVPlayerController.ets index 617e3d1c2b8582bb518e030d293fcd339d91150a..2043992499dd5a7d5dbb0e55164b83c26260b5c1 100644 --- a/entry/src/main/ets/controller/AVPlayerController.ets +++ b/entry/src/main/ets/controller/AVPlayerController.ets @@ -26,6 +26,7 @@ export class AVPlayerController { @Track isPlaying: boolean = false; private avPlayer?: media.AVPlayer; private context: common.UIAbilityContext | undefined = AppStorage.get('uiContext'); + // [Start create_instance] // Create an AVPlayer instance public async initAVPlayer(surfaceId: string, path: string) { @@ -48,6 +49,7 @@ export class AVPlayerController { } this.setAVPlayerCallback(); } + // [End create_instance] public async initAVPlayerByFd(surfaceId: string, fd: number) { diff --git a/entry/src/main/ets/controller/RecordController.ets b/entry/src/main/ets/controller/RecordController.ets index 8fd4b577a69b5e938e32605f8ef007bdcfa596f6..0eb26db6ce588457fc383521f8a9010cbb4f15fc 100644 --- a/entry/src/main/ets/controller/RecordController.ets +++ b/entry/src/main/ets/controller/RecordController.ets @@ -37,7 +37,7 @@ export class RecordController { private captureSession: camera.VideoSession | undefined = undefined; private url: string = ''; - public async initCamera(context: common.Context, surfaceId: string) { + public async initCamera(context: common.Context, surfaceId: string, filePath: string) { try { this.cameraManager = camera.getCameraManager(context); } catch (error) { @@ -47,7 +47,7 @@ export class RecordController { hilog.error(0x0000, TAG, 'camera.getCameraManager error'); return; } - this.path = context.filesDir + `/VIDEO_${DATETIME.getDate()}_${DATETIME.getTime()}.mp4`; + this.path = filePath; let file = FileUtil.createOrOpen(this.path); if (file) { this.url = 'fd://' + file.fd; @@ -57,7 +57,8 @@ export class RecordController { try { cameraArray = this.cameraManager.getSupportedCameras(); } catch (error) { - hilog.error(0x0000, TAG, `getSupportedCameras call failed. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `getSupportedCameras call failed. code is =${error.code}, message is = ${error.message}`); } if (cameraArray.length <= 0) { @@ -180,7 +181,8 @@ export class RecordController { try { this.videoOutput = this.cameraManager.createVideoOutput(videoProfile, videoSurfaceId); } catch (error) { - hilog.error(0x0000, TAG, `Failed to create the videoOutput instance. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `Failed to create the videoOutput instance. code is =${error.code}, message is = ${error.message}`); } // [End create_video_output] @@ -202,7 +204,8 @@ export class RecordController { this.captureSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession; } catch (error) { // [StartExclude set_session] - hilog.error(0x0000, TAG, `Failed to create the CaptureSession instance. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `Failed to create the CaptureSession instance. code is =${error.code}, message is = ${error.message}`); // [EndExclude set_session] } // [StartExclude set_session] @@ -250,7 +253,8 @@ export class RecordController { try { this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, surfaceId); } catch (error) { - hilog.error(0x0000, TAG, `Failed to create the PreviewOutput instance. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `Failed to create the PreviewOutput instance. code is =${error.code}, message is = ${error.message}`); } if (this.previewOutput === undefined) { @@ -294,7 +298,8 @@ export class RecordController { // [Start start_fn] this.videoOutput.start((error: BusinessError) => { if (error) { - hilog.error(0x0000, TAG, `Failed to start the video output. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `Failed to start the video output. code is =${error.code}, message is = ${error.message}`); return; } hilog.info(0x0000, TAG, 'Callback invoked to indicate the video output start success.'); @@ -311,7 +316,8 @@ export class RecordController { if (this.videoOutput) { this.videoOutput.stop((error: BusinessError) => { if (error) { - hilog.error(0x0000, TAG, `Failed to stop the video output. code is =${error.code}, message is = ${error.message}`); + hilog.error(0x0000, TAG, + `Failed to stop the video output. code is =${error.code}, message is = ${error.message}`); return; } hilog.info(0x0000, TAG, 'Callback invoked to indicate the video output stop success.'); @@ -348,7 +354,6 @@ export class RecordController { } catch (error) { hilog.error(0x0000, TAG, `avRecorder stop code is =${error.code}, message is = ${error.message}`); } - AppStorage.set('path', this.path); } } diff --git a/entry/src/main/ets/pages/AVCodecPage.ets b/entry/src/main/ets/pages/AVCodecPage.ets index 86c1cd8f5a8d53bf09d6ff5627dd65ce5de38b80..bd649de2b8784ea86dc7d0ab0b8c611bea454a17 100644 --- a/entry/src/main/ets/pages/AVCodecPage.ets +++ b/entry/src/main/ets/pages/AVCodecPage.ets @@ -21,6 +21,7 @@ import { AVPlayerController } from '../controller/AVPlayerController'; import { VideoStatus } from '../common/CommonEnum'; import { Logger } from '../common/utils/Logger'; import transcoder from 'libtranscoder.so'; +import { setScreenState } from '../common/utils/WindowUtils'; const TAG = '[AVCodecPage]'; @@ -39,7 +40,8 @@ struct AVCodecPage { private XComponentSurfaceId: string = ''; private XComponentController: XComponentController = new XComponentController(); private outputFile?: fileIo.File; - private intervalID: number = 0; + private isTranscoder: boolean = false; + dialogController: CustomDialogController = new CustomDialogController({ builder: LoadingDialog({ content: $r('app.string.Video_reminder_message') @@ -52,18 +54,13 @@ struct AVCodecPage { aboutToAppear(): void { this.mode = this.PathStack.getParamByName('AVCodecPage').pop() as number; + setScreenState(true, this.getUIContext().getHostContext()); } aboutToDisappear(): void { this.XComponentSurfaceId = ''; this.avPlayerController.videoRelease(); - clearTimeout(this.intervalID); - } - - closeDialog(): void { - this.intervalID = setTimeout(() => { - this.dialogController.close(); - }, 20); + setScreenState(false, this.getUIContext().getHostContext()); } selectFile() { @@ -106,13 +103,26 @@ struct AVCodecPage { Logger.error(TAG, 'player inputFile size is 0'); } - this.dialogController.open(); + let isHdrVivid: boolean = transcoder.isHdr(inputFile.fd, inputFileState.size); + if (!isHdrVivid) { + try { + this.getUIContext().getPromptAction().showToast({ + message: $r('app.string.video_is_not_hdr'), + duration: 3000, + bottom: 280 + }); + } catch (error) { + Logger.error(TAG, `showToast fail, error code is =${error.code}, message is = ${error.message}`); + } + return; + } this.outputFile = fileIo.openSync(this.getUIContext().getHostContext()?.cacheDir + '/transform.mp4', fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + this.dialogController.open(); + this.isTranscoder = true; if (this.mode === 0) { transcoder.startAVCodecTranscoder(inputFile.fd, inputFileState.size, this.outputFile.fd, () => { this.dialogController.close(); - this.closeDialog(); if (this.outputFile) { this.avPlayerController.initAVPlayerByFd(this.XComponentSurfaceId, this.outputFile.fd); } @@ -120,7 +130,6 @@ struct AVCodecPage { } else if (this.mode === 1) { transcoder.startVideoProcessingTranscoder(inputFile.fd, inputFileState.size, this.outputFile.fd, () => { this.dialogController.close(); - this.closeDialog(); if (this.outputFile) { this.avPlayerController.initAVPlayerByFd(this.XComponentSurfaceId, this.outputFile.fd); } @@ -128,7 +137,6 @@ struct AVCodecPage { } else { transcoder.startTransformColorspace(inputFile.fd, inputFileState.size, this.outputFile.fd, () => { this.dialogController.close(); - this.closeDialog(); if (this.outputFile) { this.avPlayerController.initAVPlayerByFd(this.XComponentSurfaceId, this.outputFile.fd); } @@ -198,9 +206,8 @@ struct AVCodecPage { .fontWeight(500) .backgroundColor($r('app.color.button_bg_color')) .fontColor($r('app.color.button_text_color')) - .enabled(this.viewState !== VideoStatus.NO_VIDEO ? true : false) + .enabled(this.viewState !== VideoStatus.NO_VIDEO) .onClick(() => { - this.dialogController.open(); this.transcoder(); }) @@ -210,7 +217,6 @@ struct AVCodecPage { .backgroundColor($r('app.color.button_bg_color')) .fontColor($r('app.color.button_text_color')) .fontWeight(500) - .enabled(this.viewState !== VideoStatus.NO_VIDEO ? true : false) .onClick(() => { this.selectFile(); }) @@ -229,6 +235,17 @@ struct AVCodecPage { .title(this.mode === 0 ? $r('app.string.transcoder_base_on_avcodec') : this.mode === 1 ? $r('app.string.transcoder_base_on_videoprocess') : $r('app.string.transform_colorspace')) .hideToolBar(true) + .onHidden(() => { + if (this.isTranscoder) { + console.log('releaseAVCodecTranscoder releaseAVCodecTranscoder') + this.dialogController.close(); + transcoder.releaseAVCodecTranscoder(); + this.viewState = VideoStatus.NO_VIDEO; + this.isTranscoder = false; + this.XComponentSurfaceId = ''; + this.avPlayerController.videoRelease(); + } + }) .onReady((context: NavDestinationContext) => { this.PathStack = context.pathStack; }) diff --git a/entry/src/main/ets/pages/AVCodecPlayPage.ets b/entry/src/main/ets/pages/AVCodecPlayPage.ets index 97400f899b57503efec95038c0d1784c1267a8c5..904de515c44e654e3ae11b852eb1ad64980c68dc 100644 --- a/entry/src/main/ets/pages/AVCodecPlayPage.ets +++ b/entry/src/main/ets/pages/AVCodecPlayPage.ets @@ -20,6 +20,7 @@ import player from 'libplayer.so'; import { BusinessError } from '@kit.BasicServicesKit'; import { VideoStatus } from '../common/CommonEnum'; import { Logger } from '../common/utils/Logger'; +import { setScreenState } from '../common/utils/WindowUtils'; const TAG = '[AVCodecPlayPage]'; @@ -41,6 +42,10 @@ export struct AVCodecPlayPage { private XComponentController: XComponentController = new XComponentController(); private inputFile: fileIo.File | undefined; + aboutToAppear(): void { + setScreenState(true, this.getUIContext().getHostContext()); + } + aboutToDisappear(): void { if (this.inputFile) { fileIo.close(this.inputFile.fd).catch((error: BusinessError) => { @@ -49,6 +54,7 @@ export struct AVCodecPlayPage { }); } player.startRelease(); + setScreenState(false, this.getUIContext().getHostContext()); } selectFile() { @@ -57,25 +63,24 @@ export struct AVCodecPlayPage { MIMEType: photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE, maxSelectNumber: 1 }).then(async (photoSelectResult) => { - try { - this.selectFilePath = photoSelectResult.photoUris[0]; - if (this.selectFilePath === undefined) { - this.getUIContext().getPromptAction().showToast({ - message: $r('app.string.alert'), - duration: 2000, - bottom: 280 - }); - } else { - this.play(); - Logger.info(TAG, 'documentViewPicker.select to file succeed and URI is:' + this.selectFilePath); - } - } catch (error) { - Logger.error(TAG, `showToast fail, error code is =${error.code}, message is = ${error.message}`); + try { + this.selectFilePath = photoSelectResult.photoUris[0]; + if (this.selectFilePath === undefined) { + this.getUIContext().getPromptAction().showToast({ + message: $r('app.string.alert'), + duration: 2000, + bottom: 280 + }); + } else { + this.play(); + Logger.info(TAG, 'documentViewPicker.select to file succeed and URI is:' + this.selectFilePath); } - }) + } catch (error) { + Logger.error(TAG, `showToast fail, error code is =${error.code}, message is = ${error.message}`); + } + }) .catch((error: BusinessError) => { - Logger.error(TAG, - `photoPicker select fail, error code is =${error.code}, message is = ${error.message}`); + Logger.error(TAG, `photoPicker select fail, error code is =${error.code}, message is = ${error.message}`); }) } @@ -160,7 +165,6 @@ export struct AVCodecPlayPage { .backgroundColor($r('app.color.button_bg_color')) .fontColor($r('app.color.button_text_color')) .fontWeight(500) - .enabled(this.viewState !== VideoStatus.NO_VIDEO ? true : false) .onClick(() => { this.selectFile(); }) diff --git a/entry/src/main/ets/pages/AVPlayerPage.ets b/entry/src/main/ets/pages/AVPlayerPage.ets index 569f7b4307b09415140e452ba13261b61d421e17..a9efa08a630418c6b7db5b7ff6de370fe264fe55 100644 --- a/entry/src/main/ets/pages/AVPlayerPage.ets +++ b/entry/src/main/ets/pages/AVPlayerPage.ets @@ -18,6 +18,7 @@ import { photoAccessHelper } from '@kit.MediaLibraryKit'; import { VideoStatus } from '../common/CommonEnum'; import { AVPlayerController } from '../controller/AVPlayerController'; import { Logger } from '../common/utils/Logger'; +import { setScreenState } from '../common/utils/WindowUtils'; @Builder export function AVPlayerPageBuilder() { @@ -25,6 +26,7 @@ export function AVPlayerPageBuilder() { } const TAG = '[AVPlayerPage]'; + @Component export struct AVPlayerPage { @State viewState: number = VideoStatus.NO_VIDEO; @@ -33,9 +35,14 @@ export struct AVPlayerPage { private XComponentSurfaceId: string = ''; private XComponentController: XComponentController = new XComponentController(); + aboutToAppear(): void { + setScreenState(true, this.getUIContext().getHostContext()); + } + aboutToDisappear(): void { this.XComponentSurfaceId = ''; this.avPlayerController.videoRelease(); + setScreenState(false, this.getUIContext().getHostContext()); } selectFile() { @@ -119,7 +126,6 @@ export struct AVPlayerPage { .backgroundColor($r('app.color.button_bg_color')) .fontColor($r('app.color.button_text_color')) .fontWeight(500) - .enabled(this.viewState !== VideoStatus.NO_VIDEO ? true : false) .onClick(() => { this.selectFile(); }) @@ -140,5 +146,4 @@ export struct AVPlayerPage { .title($r('app.string.play_video_base_on_avplayer')) .hideToolBar(true) } - } \ No newline at end of file diff --git a/entry/src/main/ets/pages/AVTranscoderPage.ets b/entry/src/main/ets/pages/AVTranscoderPage.ets index 3d56f230a180e071b807054be01cab2082a20e54..31602d79a0eb731ad5c6488804788bf4c4e2541a 100644 --- a/entry/src/main/ets/pages/AVTranscoderPage.ets +++ b/entry/src/main/ets/pages/AVTranscoderPage.ets @@ -21,6 +21,7 @@ import { AVPlayerController } from '../controller/AVPlayerController'; import { VideoStatus } from '../common/CommonEnum'; import { Logger } from '../common/utils/Logger'; import transcoder from 'libtranscoder.so'; +import { setScreenState } from '../common/utils/WindowUtils'; const TAG = '[AVTranscoderPage]'; @@ -46,9 +47,14 @@ struct AVTranscoderPage { autoCancel: false }); + aboutToAppear(): void { + setScreenState(true, this.getUIContext().getHostContext()); + } + aboutToDisappear(): void { this.XComponentSurfaceId = ''; this.avPlayerController.videoRelease(); + setScreenState(false, this.getUIContext().getHostContext()); } closeDialog(): void { @@ -122,9 +128,23 @@ struct AVTranscoderPage { Logger.error(TAG, 'player inputFile size is 0'); } - this.dialogController.open(); + this.outputFile = fileIo.openSync(this.getUIContext().getHostContext()?.cacheDir + '/transform.mp4', fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + let isHdrVivid: boolean = transcoder.isHdr(inputFile.fd, inputFileState.size); + if (!isHdrVivid) { + try { + this.getUIContext().getPromptAction().showToast({ + message: $r('app.string.video_is_not_hdr'), + duration: 2000, + bottom: 280 + }); + } catch (error) { + Logger.error(TAG, `showToast fail, error code is =${error.code}, message is = ${error.message}`); + } + return; + } + this.dialogController.open(); transcoder.startAVTranscoder(inputFile.fd, inputFileState.size, this.outputFile.fd); this.closeDialog(); } catch (error) { @@ -191,7 +211,6 @@ struct AVTranscoderPage { .fontColor($r('app.color.button_text_color')) .enabled(this.viewState !== VideoStatus.NO_VIDEO ? true : false) .onClick(() => { - this.dialogController.open(); this.transcoder(); }) Row() { @@ -201,7 +220,6 @@ struct AVTranscoderPage { .fontColor($r('app.color.button_text_color')) .fontWeight(500) .margin({ right: 6 }) - .enabled(this.viewState !== VideoStatus.NO_VIDEO ? true : false) .onClick(() => { this.selectFile(); }) diff --git a/entry/src/main/ets/pages/CameraPage.ets b/entry/src/main/ets/pages/CameraPage.ets index 7871f59fc6afcd0d8d6744bcc27b437962455536..3ce614445ca0e319362a304737a717b6ac513d11 100644 --- a/entry/src/main/ets/pages/CameraPage.ets +++ b/entry/src/main/ets/pages/CameraPage.ets @@ -13,15 +13,17 @@ * limitations under the License. */ -import { display } from '@kit.ArkUI'; +import { display, window } from '@kit.ArkUI'; import { CommonConstants as Const } from '../common/CommonConstants'; import { RecordController } from '../controller/RecordController' import { AVCodecController } from '../controller/AVCodecController' -import { dateTime } from '../common/utils/DateTimeUtils'; +import DateTimeUtil, { dateTime } from '../common/utils/DateTimeUtils'; import { BusinessError } from '@kit.BasicServicesKit'; import { Logger } from '../common/utils/Logger'; +import { setScreenState } from '../common/utils/WindowUtils'; const TAG = '[CameraPage]'; +const DATETIME: DateTimeUtil = new DateTimeUtil(); @Builder export function CameraPageBuilder() { @@ -46,13 +48,8 @@ export struct CameraPage { private widthPx = Const.DEFAULT_ID; private timer: number = Const.DEFAULT_VALUE; private seconds: number = Const.DEFAULT_VALUE; - - getRecordTime(): void { - this.timer = setInterval(() => { - this.seconds += 1; - this.videoRecorderTimeText = dateTime(this.seconds); - }, 1000); - } + private filePath: string = + this.getUIContext().getHostContext()?.filesDir + `/VIDEO_${DATETIME.getDate()}_${DATETIME.getTime()}.mp4`; aboutToAppear(): void { this.mode = this.PathStack.getParamByName('CameraPage').pop() as number; @@ -68,6 +65,24 @@ export struct CameraPage { Logger.error(TAG, `getSupportedCameras call failed. code is =${error.code}, message is = ${error.message}`); } + setScreenState(true, this.getUIContext().getHostContext()); + } + + aboutToDisappear(): void { + if (!this.recording) { + this.mode === 0 ? this.recordController.stopRecord().catch((error: BusinessError) => { + Logger.error(TAG, `stopRecord failed. code is =${error.code}, message is = ${error.message}`); + }) : this.aVCodecController.stopRecord(); + this.recording = false; + } + setScreenState(false, this.getUIContext().getHostContext()); + } + + getRecordTime(): void { + this.timer = setInterval(() => { + this.seconds += 1; + this.videoRecorderTimeText = dateTime(this.seconds); + }, 1000); } build() { @@ -81,10 +96,11 @@ export struct CameraPage { .onLoad(async () => { this.XComponentSurfaceId = this.XComponentController.getXComponentSurfaceId(); if (this.mode === 0) { - await this.recordController.initCamera(this.getUIContext().getHostContext()!, this.XComponentSurfaceId); + await this.recordController.initCamera(this.getUIContext().getHostContext()!, this.XComponentSurfaceId, + this.filePath); } else { await this.aVCodecController.createRecorder(this.getUIContext().getHostContext()!, - this.XComponentSurfaceId) + this.XComponentSurfaceId, this.filePath) } }) .width(this.widthPx) @@ -125,6 +141,7 @@ export struct CameraPage { await (this.mode === 0 ? this.recordController.stopRecord().catch((error: BusinessError) => { Logger.error(TAG, `stopRecord failed. code is =${error.code}, message is = ${error.message}`); }) : this.aVCodecController.stopRecord()); + AppStorage.set('path', this.filePath); clearInterval(this.timer); this.PathStack.pop(); return; diff --git a/entry/src/main/ets/pages/Recording.ets b/entry/src/main/ets/pages/Recording.ets index 4e5bff1357f7f8683c7692cfb7d6d8756b6e8331..6373ec297d5711648d7525e5b1c99944d99d8d76 100644 --- a/entry/src/main/ets/pages/Recording.ets +++ b/entry/src/main/ets/pages/Recording.ets @@ -18,6 +18,7 @@ import { checkPermissions, PermissionsFromUser } from '../common/utils/Permissio import { AVPlayerController } from '../controller/AVPlayerController'; import { SaveDialog } from '../view/SaveDialog'; import { Logger } from '../common/utils/Logger'; +import { setScreenState } from '../common/utils/WindowUtils'; @Builder export function RecordingBuilder() { @@ -51,10 +52,13 @@ export struct Recording { Logger.error(TAG, `showToast fail, error code is =${error.code}, message is = ${error.message}`); } } + setScreenState(true, this.getUIContext().getHostContext()); } aboutToDisappear(): void { this.avPlayerController.videoRelease(); + setScreenState(false, this.getUIContext().getHostContext()); + AppStorage.set('path', ''); } build() { @@ -88,30 +92,32 @@ export struct Recording { .width('100%') .layoutWeight(1) - Row() { + Column() { Button($r('app.string.record_video')) - .layoutWeight(1) .backgroundColor($r('app.color.button_bg_color')) .fontColor($r('app.color.button_text_color')) .fontWeight(500) - .margin({ right: 6 }) + .width('100%') + .margin({ + bottom: 12 + }) .onClick(async () => { AppStorage.set('cameraData', this.cameraData) this.PathStack.pushPathByName('CameraPage', this.mode); }) - SaveDialog() + if (this.path !== '') { + SaveDialog() + } } - .justifyContent(FlexAlign.Center) .margin({ left: 16, top: 12, - right: 16, - bottom: 12 + right: 16 }) } .height('100%') + .justifyContent(FlexAlign.Center) .margin({ top: 10 }) - } .title(this.mode ? $r('app.string.record_base_on_avcodec') : $r('app.string.record_base_on_avrecorder')) .onReady((context: NavDestinationContext) => { diff --git a/entry/src/main/ets/view/MultiStatusButton.ets b/entry/src/main/ets/view/MultiStatusButton.ets index 4fb3c3e6de066a58baa206717372f151fa2e1a47..ad72ef8add9a2eb21d27cd9e27c267856ff63366 100644 --- a/entry/src/main/ets/view/MultiStatusButton.ets +++ b/entry/src/main/ets/view/MultiStatusButton.ets @@ -28,8 +28,8 @@ export struct MultiStatusButton { .fontColor($r('sys.color.dialog_outer_border_color')) .backgroundColor($r('sys.color.container_modal_button_hover_baseboard')) .borderRadius(16) - .padding({left: 16}) - .margin({top: 8}) + .padding({ left: 16 }) + .margin({ top: 8 }) } else if (this.status === StatusEnum.AVAILABLE) { Text(this.text) .width('100%') @@ -37,9 +37,9 @@ export struct MultiStatusButton { .fontColor($r('sys.color.black')) .backgroundColor($r('sys.color.container_modal_button_hover_baseboard')) .borderRadius(16) - .padding({left: 16}) - .margin({top: 8}) - .onTouch(()=>{ + .padding({ left: 16 }) + .margin({ top: 8 }) + .onTouch(() => { this.status = StatusEnum.SELECTED; }) } else if (this.status === StatusEnum.SELECTED) { @@ -49,13 +49,13 @@ export struct MultiStatusButton { .fontColor('#0A59F7') .backgroundColor('#0C0A59F7') .borderRadius(16) - .padding({left: 16}) - .margin({top: 8}) + .padding({ left: 16 }) + .margin({ top: 8 }) .borderWidth(1) .borderColor('#0A59F7') } } - .margin({top: 8}) + .margin({ top: 8 }) .width('100%') .height(56) } diff --git a/entry/src/main/ets/view/SaveDialog.ets b/entry/src/main/ets/view/SaveDialog.ets index c7b30ce1a24aa4d1cc354f1741b75966c5a6d9d1..dbc4790c13b0430c7229dfdb904356990d8f8120 100644 --- a/entry/src/main/ets/view/SaveDialog.ets +++ b/entry/src/main/ets/view/SaveDialog.ets @@ -18,6 +18,7 @@ import { saveFile } from '../common/utils/VideoOperationUtils'; @CustomDialog struct SaveCustomDialog { controller: CustomDialogController; + build() { Column() { Text($r('app.string.save_button_title')) @@ -74,11 +75,13 @@ export struct SaveDialog { build() { Button($r('app.string.save_video')) - .layoutWeight(1) .backgroundColor($r('app.color.button_bg_color')) .fontColor($r('app.color.button_text_color')) .fontWeight(500) - .margin({ right: 6 }) + .width('100%') + .margin({ + bottom: 12 + }) .size({ width: '100%', height: '40vp' diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json index 9f773210af5423c756978495792f2b81cbec6e38..3089f097e75210826a1cf2ab7fc17afe14cd3006 100644 --- a/entry/src/main/resources/base/element/string.json +++ b/entry/src/main/resources/base/element/string.json @@ -163,6 +163,10 @@ { "name": "no_permission", "value": "No Permission" + }, + { + "name": "video_is_not_hdr", + "value": "Video is not HDR" } ] } \ No newline at end of file diff --git a/entry/src/main/resources/en_US/element/string.json b/entry/src/main/resources/en_US/element/string.json index 8206beab466396bcae3b76e1e073ce3802beafea..0a09622c34b0cd0984650ea6d123ff9d894d9e10 100644 --- a/entry/src/main/resources/en_US/element/string.json +++ b/entry/src/main/resources/en_US/element/string.json @@ -151,6 +151,10 @@ { "name": "no_permission", "value": "No Permission" + }, + { + "name": "video_is_not_hdr", + "value": "Video is not HDR" } ] } \ No newline at end of file diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json index 9e2266fe8c1f6b0f02d5d8de0ee181403975d431..7ea8088a4bfc5324ea4c08039beed5f9033bdf0c 100644 --- a/entry/src/main/resources/zh_CN/element/string.json +++ b/entry/src/main/resources/zh_CN/element/string.json @@ -143,6 +143,10 @@ { "name": "no_permission", "value": "用户未授权" + }, + { + "name": "video_is_not_hdr", + "value": "视频非HDR格式" } ] } \ No newline at end of file diff --git a/screenshots/devices/RecordPage.png b/screenshots/devices/RecordPage.png index cd30ca1aa473b163162b981f29dd292be98bcad0..4d0381b8b2e1101c5a7c1b8c83eb7535d5844e1d 100644 Binary files a/screenshots/devices/RecordPage.png and b/screenshots/devices/RecordPage.png differ diff --git a/screenshots/devices/RecordPage_en.png b/screenshots/devices/RecordPage_en.png index e9908dd95a02d13ca5f085af47a8771bdedf0c5d..672fb95702b9c90cea79d3b99e7cecf11c75ffa4 100644 Binary files a/screenshots/devices/RecordPage_en.png and b/screenshots/devices/RecordPage_en.png differ