From b980aef9e2991fe0341ad943a7990fa363ecb594 Mon Sep 17 00:00:00 2001 From: ziyugao Date: Mon, 30 Dec 2024 19:52:58 +0800 Subject: [PATCH 01/18] add audio capability Signed-off-by: ziyugao --- entry/src/main/cpp/CMakeLists.txt | 18 +- .../src/main/cpp/sample/recorder/Recorder.cpp | 5 + entry/src/main/cpp/sample/recorder/Recorder.h | 2 + .../main/cpp/sample/recorder/audiorecord.cpp | 196 ++++++++++++++++++ .../main/cpp/sample/recorder/audiorecord.h | 60 ++++++ .../main/ets/entryability/EntryAbility.ets | 12 ++ entry/src/main/ets/pages/Index.ets | 13 ++ entry/src/main/module.json5 | 30 +++ 8 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 entry/src/main/cpp/sample/recorder/audiorecord.cpp create mode 100644 entry/src/main/cpp/sample/recorder/audiorecord.h diff --git a/entry/src/main/cpp/CMakeLists.txt b/entry/src/main/cpp/CMakeLists.txt index e498f02..7026bb7 100644 --- a/entry/src/main/cpp/CMakeLists.txt +++ b/entry/src/main/cpp/CMakeLists.txt @@ -33,10 +33,26 @@ add_library(player SHARED sample/player/PlayerNative.cpp add_library(recorder SHARED sample/recorder/RecorderNative.cpp sample/recorder/Recorder.cpp + sample/recorder/audiorecord.cpp capbilities/Muxer.cpp capbilities/VideoEncoder.cpp common/SampleCallback.cpp ) target_link_libraries(player PUBLIC ${BASE_LIBRARY}) -target_link_libraries(recorder PUBLIC ${BASE_LIBRARY}) \ No newline at end of file +target_link_libraries(recorder PUBLIC ${BASE_LIBRARY}) + +target_link_libraries(recorder PUBLIC libace_napi.z.so libohaudio.so libhilog_ndk.z.so) +target_link_libraries(recorder PUBLIC libnative_media_codecbase.so) +target_link_libraries(recorder PUBLIC libnative_media_avmuxer.so) +target_link_libraries(recorder PUBLIC libnative_media_core.so) +target_link_libraries(recorder PUBLIC libnative_media_acodec.so ) +target_link_libraries(recorder PUBLIC libace_napi.z.so + libhilog_ndk.z.so + libnative_window.so + libnative_window.so + libnative_media_core.so + libnative_media_avdemuxer.so + libnative_media_avsource.so + libnative_media_codecbase.so + libnative_media_acodec.so) \ No newline at end of file diff --git a/entry/src/main/cpp/sample/recorder/Recorder.cpp b/entry/src/main/cpp/sample/recorder/Recorder.cpp index 2688b3f..9b70ded 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.cpp +++ b/entry/src/main/cpp/sample/recorder/Recorder.cpp @@ -17,6 +17,7 @@ #include #include "AVCodecSampleLog.h" #include "dfx/error/AVCodecSampleError.h" +#include "audiorecord.h" #undef LOG_TAG #define LOG_TAG "recorder" @@ -30,6 +31,8 @@ Recorder::~Recorder() { StartRelease(); } int32_t Recorder::Init(SampleInfo &sampleInfo) { std::lock_guard lock(mutex_); + audioRecord_ = std::make_unique(); + audioRecord_->AudioCapturerInit(); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(videoEncoder_ == nullptr && muxer_ == nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); @@ -61,6 +64,7 @@ int32_t Recorder::Init(SampleInfo &sampleInfo) { int32_t Recorder::Start() { std::lock_guard lock(mutex_); + audioRecord_->AudioCapturerStart(muxer_); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(encContext_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, @@ -125,6 +129,7 @@ void Recorder::StartRelease() { void Recorder::Release() { std::lock_guard lock(mutex_); + audioRecord_->AudioCapturerRelease(); isStarted_ = false; if (encOutputThread_ && encOutputThread_->joinable()) { encOutputThread_->join(); diff --git a/entry/src/main/cpp/sample/recorder/Recorder.h b/entry/src/main/cpp/sample/recorder/Recorder.h index 5fd7b28..4fc69df 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.h +++ b/entry/src/main/cpp/sample/recorder/Recorder.h @@ -25,6 +25,7 @@ #include "VideoEncoder.h" #include "Muxer.h" #include "SampleInfo.h" +#include "audiorecord.h" class Recorder { public: @@ -47,6 +48,7 @@ private: int32_t WaitForDone(); std::unique_ptr videoEncoder_ = nullptr; + std::unique_ptr audioRecord_ = nullptr; std::unique_ptr muxer_ = nullptr; std::mutex mutex_; diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.cpp b/entry/src/main/cpp/sample/recorder/audiorecord.cpp new file mode 100644 index 0000000..2642a9c --- /dev/null +++ b/entry/src/main/cpp/sample/recorder/audiorecord.cpp @@ -0,0 +1,196 @@ +#include "audiorecord.h" + +using namespace std; + +int32_t g_samplingRate = 16000; +int32_t g_channelCount = 1; +static OH_AudioCapturer *audioCapturer; +static OH_AudioStreamBuilder *builder; + +constexpr int32_t buffer_size = 100000; +static char pcm_buffers[buffer_size]; +static int buffer_count = 0; +AEncSignal *signal_; + +constexpr int32_t INPUT_FRAME_BYTES = 2 * 1024; + +static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)codec; + (void)errorCode; + (void)userData; + cout << "Error received, errorCode:" << errorCode << endl; +} + +static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)codec; + (void)format; + (void)userData; + cout << "OnOutputFormatChanged received" << endl; +} + +static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) +{ + (void)codec; + AEncSignal *signal = static_cast(userData); + unique_lock lock(signal->inMutex_); + signal->inQueue_.push(index); + signal->inBufferQueue_.push(buffer); + signal->inCond_.notify_all(); +} + +static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) +{ + (void)codec; + AEncSignal *signal = static_cast(userData); + unique_lock lock(signal->outMutex_); + signal->outQueue_.push(index); + signal->outBufferQueue_.push(buffer); + signal->outCond_.notify_all(); +} + +static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) { + unique_lock lock(signal_->inMutex_); + memcpy(pcm_buffers+buffer_count, buffer, bufferLen); + buffer_count += bufferLen; + signal_->inCond_.notify_all(); + return 0; +} + +void AudioRecord::InputFunc() +{ + while (isRunning_.load()) { + unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return ((buffer_count > INPUT_FRAME_BYTES && signal_->inQueue_.size() > 0) || !isRunning_.load()); }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signal_->inQueue_.front(); + auto buffer = signal_->inBufferQueue_.front(); + + OH_AVCodecBufferAttr info; + memcpy(reinterpret_cast(OH_AVBuffer_GetAddr(buffer)), pcm_buffers, INPUT_FRAME_BYTES); + buffer_count -= INPUT_FRAME_BYTES; + memcpy(pcm_buffers, pcm_buffers+INPUT_FRAME_BYTES, buffer_count); + + info.size = INPUT_FRAME_BYTES; + + int32_t ret = 0; + if (isFirstFrame_) { + info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; + OH_AVBuffer_SetBufferAttr(buffer, &info); + ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index); + isFirstFrame_ = false; + } else { + info.flags = AVCODEC_BUFFER_FLAGS_NONE; + OH_AVBuffer_SetBufferAttr(buffer, &info); + ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index); + } + signal_->inQueue_.pop(); + signal_->inBufferQueue_.pop(); + } +} + +void AudioRecord::OutputFunc() +{ + int64_t size; + while (isRunning_.load()) { + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signal_->outQueue_.front(); + OH_AVBuffer *avBuffer = signal_->outBufferQueue_.front(); + + OH_AVCodecBufferAttr info; + OH_AVBuffer_GetBufferAttr(avBuffer, &info); + size = info.size; + AVCODEC_SAMPLE_LOGD("pts %{public}ld", info.pts); + muxerA_->WriteFrame(avBuffer, info); + signal_->outBufferQueue_.pop(); + signal_->outQueue_.pop(); + OH_AudioCodec_FreeOutputBuffer(audioEnc_, index); + } + +} + + +void AudioRecord::AudioCapturerInit() +{ + if (audioCapturer) { + OH_AudioCapturer_Release(audioCapturer); + OH_AudioStreamBuilder_Destroy(builder); + audioCapturer = nullptr; + builder = nullptr; + } + + // Create builder + OH_AudioStream_Type type = AUDIOSTREAM_TYPE_CAPTURER; + OH_AudioStreamBuilder_Create(&builder, type); + // set params and callbacks + OH_AudioStreamBuilder_SetSamplingRate(builder, g_samplingRate); + OH_AudioStreamBuilder_SetChannelCount(builder, g_channelCount); + OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); + OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST); + OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); + OH_AudioCapturer_Callbacks callbacks; + callbacks.OH_AudioCapturer_OnReadData = AudioCapturerOnReadData; + OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr); + // create OH_AudioCapturer + OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer); + + //create audio encoder stream + OH_AVFormat *format = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(format, "channel_count", g_channelCount); + OH_AVFormat_SetIntValue(format, "sample_rate", g_samplingRate); + OH_AVFormat_SetIntValue(format, "audio_sample_format", AUDIOSTREAM_SAMPLE_S16LE); + + audioEnc_ = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.AAC"); + if (signal_) { + delete signal_; + signal_ = nullptr; + } + signal_ = new AEncSignal(); + cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable}; + int32_t ret = OH_AudioCodec_RegisterCallback(audioEnc_, cb_, signal_); + + OH_AudioCodec_Configure(audioEnc_, format); +} + +void AudioRecord::AudioCapturerStart(std::unique_ptr& muxer) +{ + muxerA_ = muxer.get(); + isRunning_.store(true); + OH_AudioCapturer_Start(audioCapturer); + + inputLoop_ = make_unique(&AudioRecord::InputFunc, this); + outputLoop_ = make_unique(&AudioRecord::OutputFunc, this); + + OH_AudioCodec_Start(audioEnc_); + +} + +void AudioRecord::AudioCapturerRelease() { + if (audioCapturer) { + OH_AudioCapturer_Release(audioCapturer); + OH_AudioStreamBuilder_Destroy(builder); + audioCapturer = nullptr; + builder = nullptr; + } + OH_AudioCodec_Stop(audioEnc_); + OH_AudioCodec_Destroy(audioEnc_); + audioEnc_ = nullptr; + isRunning_ = false; + if (signal_) { + signal_->inCond_.notify_all(); + signal_->outCond_.notify_all(); + inputLoop_->join(); + inputLoop_ = nullptr; + outputLoop_->join(); + outputLoop_ = nullptr; + delete signal_; + signal_ = nullptr; + } +} diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.h b/entry/src/main/cpp/sample/recorder/audiorecord.h new file mode 100644 index 0000000..9d101c2 --- /dev/null +++ b/entry/src/main/cpp/sample/recorder/audiorecord.h @@ -0,0 +1,60 @@ +#ifndef AUDIO_ENCODE_H +#define AUDIO_ENCODE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "multimedia/player_framework/native_avbuffer.h" +#include "ohaudio/native_audiocapturer.h" +#include "ohaudio/native_audiorenderer.h" +#include "ohaudio/native_audiostreambuilder.h" +#include "ohaudio/native_audiostream_base.h" +#include "multimedia/player_framework/native_avformat.h" +#include "multimedia/player_framework/native_avcodec_base.h" +#include "multimedia/player_framework/native_avcodec_audiocodec.h" +#include "multimedia/player_framework/native_avbuffer.h" +#include "Muxer.h" + +using namespace std; + + +class AEncSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::mutex startMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::condition_variable startCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; +}; +class AudioRecord { +public: + AudioRecord(){}; + ~AudioRecord(){ + AudioCapturerRelease(); + }; + void AudioCapturerInit(); + void AudioCapturerRelease(); + void AudioCapturerStart(std::unique_ptr& muxer); +private: + void InputFunc(); + void OutputFunc(); + + struct OH_AVCodecCallback cb_; + unique_ptr inputLoop_; + unique_ptr outputLoop_; + OH_AVCodec *audioEnc_; + Muxer *muxerA_ = nullptr; + int32_t isFirstFrame_ = true; + std::atomic isRunning_; +}; +#endif \ No newline at end of file diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index e45511c..995d2cb 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -32,6 +32,18 @@ export default class EntryAbility extends UIAbility { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + try { + let atManager = abilityAccessCtrl.createAtManager(); + atManager.requestPermissionsFromUser(this.context, ['ohos.permission.MICROPHONE']).then((data) => { + console.info('data:' + JSON.stringify(data)); + console.info('data permissions:' + data.permissions); + console.info('data authResults:' + data.authResults); + }).catch((err: BusinessError) => { + console.info('data:' + JSON.stringify(err)); + }); + } catch (err) { + Logger.error('Entry', 'requestPre() data: ' + JSON.stringify(err)); + } try { let atManager = abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(this.context, ['ohos.permission.CAMERA']) diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 56f63f5..a1ba7aa 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -24,7 +24,11 @@ import DateTimeUtil from '../common/utils/DateTimeUtils'; import { CommonConstants as Const } from '../common/CommonConstants'; import { CameraDataModel } from '../model/CameraDateModel'; import { cameraCheck } from '../common/utils/CameraCheck'; +import { abilityAccessCtrl, common } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +let context = getContext(this) as common.UIAbilityContext; +let atManager = abilityAccessCtrl.createAtManager(); const TAG: string = Const.INDEX_TAG; const DATETIME: DateTimeUtil = new DateTimeUtil(); @@ -281,6 +285,15 @@ struct Player { Button($r('app.string.record')) .onClick(() => { this.isShow = true; + atManager.requestPermissionsFromUser(context, ['ohos.permission.MICROPHONE', 'ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA']).then((data) => { + console.info('data: ' + JSON.stringify(data)); + console.info('result : ' + data.authResults[0]); + if (data.authResults[0] !== 0) { + return; + } + }).catch((err: BusinessError) => { + console.error('data:' + JSON.stringify(err)); + }) }) .bindSheet($$this.isShow, this.Authorized, { height: 210, diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 index 8bd98e4..f557649 100644 --- a/entry/src/main/module.json5 +++ b/entry/src/main/module.json5 @@ -54,6 +54,36 @@ "abilities": ["EntryAbility"], "when": "always" } + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } } ] } -- Gitee From 00f809c3139e5f5570ef9fbbd166dd6a8cbd7e0e Mon Sep 17 00:00:00 2001 From: ziyugao Date: Tue, 31 Dec 2024 11:20:20 +0800 Subject: [PATCH 02/18] bugfix Signed-off-by: ziyugao --- .vscode/settings.json | 5 +++ .../main/cpp/sample/recorder/audiorecord.cpp | 34 ++++++++----------- .../main/cpp/sample/recorder/audiorecord.h | 1 - 3 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..70abd31 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "mutex": "cpp" + } +} \ No newline at end of file diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.cpp b/entry/src/main/cpp/sample/recorder/audiorecord.cpp index 2642a9c..848d73b 100644 --- a/entry/src/main/cpp/sample/recorder/audiorecord.cpp +++ b/entry/src/main/cpp/sample/recorder/audiorecord.cpp @@ -2,18 +2,15 @@ using namespace std; -int32_t g_samplingRate = 16000; -int32_t g_channelCount = 1; +int32_t samplingRate = 16000; +int32_t channelCount = 1; +constexpr int32_t INPUT_FRAME_BYTES = 2 * 1024; static OH_AudioCapturer *audioCapturer; static OH_AudioStreamBuilder *builder; -constexpr int32_t buffer_size = 100000; -static char pcm_buffers[buffer_size]; -static int buffer_count = 0; +vector pcmBuffer; AEncSignal *signal_; -constexpr int32_t INPUT_FRAME_BYTES = 2 * 1024; - static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) { (void)codec; @@ -52,8 +49,7 @@ static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuff static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) { unique_lock lock(signal_->inMutex_); - memcpy(pcm_buffers+buffer_count, buffer, bufferLen); - buffer_count += bufferLen; + pcmBuffer.insert(pcmBuffer.end(), reinterpret_cast(buffer), reinterpret_cast(buffer) + bufferLen); signal_->inCond_.notify_all(); return 0; } @@ -62,7 +58,7 @@ void AudioRecord::InputFunc() { while (isRunning_.load()) { unique_lock lock(signal_->inMutex_); - signal_->inCond_.wait(lock, [this]() { return ((buffer_count > INPUT_FRAME_BYTES && signal_->inQueue_.size() > 0) || !isRunning_.load()); }); + signal_->inCond_.wait(lock, [this]() { return ((pcmBuffer.size() > INPUT_FRAME_BYTES && signal_->inQueue_.size() > 0) || !isRunning_.load()); }); if (!isRunning_.load()) { break; } @@ -70,9 +66,8 @@ void AudioRecord::InputFunc() auto buffer = signal_->inBufferQueue_.front(); OH_AVCodecBufferAttr info; - memcpy(reinterpret_cast(OH_AVBuffer_GetAddr(buffer)), pcm_buffers, INPUT_FRAME_BYTES); - buffer_count -= INPUT_FRAME_BYTES; - memcpy(pcm_buffers, pcm_buffers+INPUT_FRAME_BYTES, buffer_count); + memcpy(reinterpret_cast(OH_AVBuffer_GetAddr(buffer)), pcmBuffer.data(), INPUT_FRAME_BYTES); + pcmBuffer.erase(pcmBuffer.begin(), pcmBuffer.begin() + INPUT_FRAME_BYTES); info.size = INPUT_FRAME_BYTES; @@ -130,8 +125,8 @@ void AudioRecord::AudioCapturerInit() OH_AudioStream_Type type = AUDIOSTREAM_TYPE_CAPTURER; OH_AudioStreamBuilder_Create(&builder, type); // set params and callbacks - OH_AudioStreamBuilder_SetSamplingRate(builder, g_samplingRate); - OH_AudioStreamBuilder_SetChannelCount(builder, g_channelCount); + OH_AudioStreamBuilder_SetSamplingRate(builder, samplingRate); + OH_AudioStreamBuilder_SetChannelCount(builder, channelCount); OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST); OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); @@ -143,11 +138,11 @@ void AudioRecord::AudioCapturerInit() //create audio encoder stream OH_AVFormat *format = OH_AVFormat_Create(); - OH_AVFormat_SetIntValue(format, "channel_count", g_channelCount); - OH_AVFormat_SetIntValue(format, "sample_rate", g_samplingRate); - OH_AVFormat_SetIntValue(format, "audio_sample_format", AUDIOSTREAM_SAMPLE_S16LE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, channelCount); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, samplingRate); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AUDIOSTREAM_SAMPLE_S16LE); - audioEnc_ = OH_AudioCodec_CreateByName("OH.Media.Codec.Encoder.Audio.AAC"); + audioEnc_ = OH_AudioCodec_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); if (signal_) { delete signal_; signal_ = nullptr; @@ -193,4 +188,5 @@ void AudioRecord::AudioCapturerRelease() { delete signal_; signal_ = nullptr; } + pcmBuffer.shrink_to_fit(); } diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.h b/entry/src/main/cpp/sample/recorder/audiorecord.h index 9d101c2..1f50b65 100644 --- a/entry/src/main/cpp/sample/recorder/audiorecord.h +++ b/entry/src/main/cpp/sample/recorder/audiorecord.h @@ -17,7 +17,6 @@ #include "multimedia/player_framework/native_avformat.h" #include "multimedia/player_framework/native_avcodec_base.h" #include "multimedia/player_framework/native_avcodec_audiocodec.h" -#include "multimedia/player_framework/native_avbuffer.h" #include "Muxer.h" using namespace std; -- Gitee From e62a639489a06205504753931983bb03dc167d2b Mon Sep 17 00:00:00 2001 From: ziyugao Date: Tue, 31 Dec 2024 14:14:01 +0800 Subject: [PATCH 03/18] bugfix Signed-off-by: ziyugao --- entry/src/main/cpp/capbilities/Muxer.cpp | 18 ++++++++++++++++++ entry/src/main/cpp/capbilities/include/Muxer.h | 2 ++ .../main/cpp/sample/recorder/audiorecord.cpp | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/entry/src/main/cpp/capbilities/Muxer.cpp b/entry/src/main/cpp/capbilities/Muxer.cpp index 59eb4ab..0cc2b22 100644 --- a/entry/src/main/cpp/capbilities/Muxer.cpp +++ b/entry/src/main/cpp/capbilities/Muxer.cpp @@ -59,6 +59,14 @@ int32_t Muxer::Config(SampleInfo &sampleInfo) CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "AddTrack failed"); OH_AVFormat_Destroy(formatVideo); OH_AVMuxer_SetRotation(muxer_, sampleInfo.videoHeight > sampleInfo.videoWidth ? VERTICAL_ANGLE : HORIZONTAL_ANGLE); + + OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(OH_AVCODEC_MIMETYPE_AUDIO_AAC, 16000, 1); + OH_AVFormat_SetIntValue(formatAudio, "audio_samples_per_frame", 1024); + OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_PROFILE, AAC_PROFILE_LC); + + OH_AVMuxer_AddTrack(muxer_, &audioTrackId_, formatAudio); + OH_AVFormat_Destroy(formatAudio); + return AVCODEC_SAMPLE_ERR_OK; } @@ -84,6 +92,16 @@ int32_t Muxer::WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) return AVCODEC_SAMPLE_ERR_OK; } +int32_t Muxer::WriteFrame(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +{ + CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null"); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get a empty buffer"); + + ret = OH_AVMuxer_WriteSampleBuffer(muxer_, audioTrackId_, buffer); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Write sample failed"); + return AVCODEC_SAMPLE_ERR_OK; +} + int32_t Muxer::Release() { if (muxer_ != nullptr) { diff --git a/entry/src/main/cpp/capbilities/include/Muxer.h b/entry/src/main/cpp/capbilities/include/Muxer.h index 8354a9c..60d465f 100644 --- a/entry/src/main/cpp/capbilities/include/Muxer.h +++ b/entry/src/main/cpp/capbilities/include/Muxer.h @@ -31,11 +31,13 @@ public: int32_t Config(SampleInfo &sampleInfo); int32_t Start(); int32_t WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + int32_t WriteFrame(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); int32_t Release(); private: OH_AVMuxer *muxer_ = nullptr; int32_t videoTrackId_ = -1; + int32_t audioTrackId_ = -1; }; #endif // MUXER_H \ No newline at end of file diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.cpp b/entry/src/main/cpp/sample/recorder/audiorecord.cpp index 848d73b..4dbc11f 100644 --- a/entry/src/main/cpp/sample/recorder/audiorecord.cpp +++ b/entry/src/main/cpp/sample/recorder/audiorecord.cpp @@ -67,7 +67,7 @@ void AudioRecord::InputFunc() OH_AVCodecBufferAttr info; memcpy(reinterpret_cast(OH_AVBuffer_GetAddr(buffer)), pcmBuffer.data(), INPUT_FRAME_BYTES); - pcmBuffer.erase(pcmBuffer.begin(), pcmBuffer.begin() + INPUT_FRAME_BYTES); + pcmBuffer.erase(pcmBuffer.begin(), pcmBuffer.begin() + INPUT_FRAME_BYTES); info.size = INPUT_FRAME_BYTES; -- Gitee From 7df663e98329abadc629db7f2294331e22b587dd Mon Sep 17 00:00:00 2001 From: ziyugao Date: Tue, 31 Dec 2024 14:59:41 +0800 Subject: [PATCH 04/18] bugfix Signed-off-by: ziyugao --- entry/src/main/cpp/capbilities/Muxer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entry/src/main/cpp/capbilities/Muxer.cpp b/entry/src/main/cpp/capbilities/Muxer.cpp index 0cc2b22..0c215b0 100644 --- a/entry/src/main/cpp/capbilities/Muxer.cpp +++ b/entry/src/main/cpp/capbilities/Muxer.cpp @@ -97,7 +97,7 @@ int32_t Muxer::WriteFrame(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null"); CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get a empty buffer"); - ret = OH_AVMuxer_WriteSampleBuffer(muxer_, audioTrackId_, buffer); + int32_t ret = OH_AVMuxer_WriteSampleBuffer(muxer_, audioTrackId_, buffer); CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Write sample failed"); return AVCODEC_SAMPLE_ERR_OK; } -- Gitee From b14453237a94b2c89b4222468dbcae0ac9d8377d Mon Sep 17 00:00:00 2001 From: ziyugao Date: Thu, 2 Jan 2025 09:26:52 +0800 Subject: [PATCH 05/18] bugfix Signed-off-by: ziyugao --- entry/src/main/cpp/capbilities/Muxer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/entry/src/main/cpp/capbilities/Muxer.cpp b/entry/src/main/cpp/capbilities/Muxer.cpp index 0c215b0..a7d4416 100644 --- a/entry/src/main/cpp/capbilities/Muxer.cpp +++ b/entry/src/main/cpp/capbilities/Muxer.cpp @@ -60,8 +60,7 @@ int32_t Muxer::Config(SampleInfo &sampleInfo) OH_AVFormat_Destroy(formatVideo); OH_AVMuxer_SetRotation(muxer_, sampleInfo.videoHeight > sampleInfo.videoWidth ? VERTICAL_ANGLE : HORIZONTAL_ANGLE); - OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(OH_AVCODEC_MIMETYPE_AUDIO_AAC, 16000, 1); - OH_AVFormat_SetIntValue(formatAudio, "audio_samples_per_frame", 1024); + OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(OH_AVCODEC_MIMETYPE_AUDIO_AAC, 16000, 1); // 16000 for sample rate OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_PROFILE, AAC_PROFILE_LC); OH_AVMuxer_AddTrack(muxer_, &audioTrackId_, formatAudio); -- Gitee From 0331c80e0b088c4eb718a4e7d0e10cf805806875 Mon Sep 17 00:00:00 2001 From: ziyugao Date: Thu, 2 Jan 2025 09:44:50 +0800 Subject: [PATCH 06/18] bugfix Signed-off-by: ziyugao --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 70abd31..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "mutex": "cpp" - } -} \ No newline at end of file -- Gitee From a60df95c8abb1b950c8e1b1fbac3538dec5df94c Mon Sep 17 00:00:00 2001 From: ziyugao Date: Fri, 3 Jan 2025 10:11:24 +0800 Subject: [PATCH 07/18] fix bug Signed-off-by: ziyugao --- entry/src/main/cpp/CMakeLists.txt | 17 +---------------- entry/src/main/cpp/capbilities/Muxer.cpp | 5 +++-- entry/src/main/cpp/capbilities/include/Muxer.h | 2 +- .../main/cpp/sample/recorder/audiorecord.cpp | 16 ++++++++-------- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/entry/src/main/cpp/CMakeLists.txt b/entry/src/main/cpp/CMakeLists.txt index 7026bb7..f60208c 100644 --- a/entry/src/main/cpp/CMakeLists.txt +++ b/entry/src/main/cpp/CMakeLists.txt @@ -33,7 +33,7 @@ add_library(player SHARED sample/player/PlayerNative.cpp add_library(recorder SHARED sample/recorder/RecorderNative.cpp sample/recorder/Recorder.cpp - sample/recorder/audiorecord.cpp + sample/recorder/AudioRecord.cpp capbilities/Muxer.cpp capbilities/VideoEncoder.cpp common/SampleCallback.cpp @@ -41,18 +41,3 @@ add_library(recorder SHARED sample/recorder/RecorderNative.cpp target_link_libraries(player PUBLIC ${BASE_LIBRARY}) target_link_libraries(recorder PUBLIC ${BASE_LIBRARY}) - -target_link_libraries(recorder PUBLIC libace_napi.z.so libohaudio.so libhilog_ndk.z.so) -target_link_libraries(recorder PUBLIC libnative_media_codecbase.so) -target_link_libraries(recorder PUBLIC libnative_media_avmuxer.so) -target_link_libraries(recorder PUBLIC libnative_media_core.so) -target_link_libraries(recorder PUBLIC libnative_media_acodec.so ) -target_link_libraries(recorder PUBLIC libace_napi.z.so - libhilog_ndk.z.so - libnative_window.so - libnative_window.so - libnative_media_core.so - libnative_media_avdemuxer.so - libnative_media_avsource.so - libnative_media_codecbase.so - libnative_media_acodec.so) \ No newline at end of file diff --git a/entry/src/main/cpp/capbilities/Muxer.cpp b/entry/src/main/cpp/capbilities/Muxer.cpp index a7d4416..0b53813 100644 --- a/entry/src/main/cpp/capbilities/Muxer.cpp +++ b/entry/src/main/cpp/capbilities/Muxer.cpp @@ -21,6 +21,7 @@ namespace { constexpr int32_t VERTICAL_ANGLE = 90; constexpr int32_t HORIZONTAL_ANGLE = 0; +constexpr int32_t SAMPLE_RATE = 16000; } Muxer::~Muxer() @@ -60,7 +61,7 @@ int32_t Muxer::Config(SampleInfo &sampleInfo) OH_AVFormat_Destroy(formatVideo); OH_AVMuxer_SetRotation(muxer_, sampleInfo.videoHeight > sampleInfo.videoWidth ? VERTICAL_ANGLE : HORIZONTAL_ANGLE); - OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(OH_AVCODEC_MIMETYPE_AUDIO_AAC, 16000, 1); // 16000 for sample rate + OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(OH_AVCODEC_MIMETYPE_AUDIO_AAC, SAMPLE_RATE, 1); OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_PROFILE, AAC_PROFILE_LC); OH_AVMuxer_AddTrack(muxer_, &audioTrackId_, formatAudio); @@ -91,7 +92,7 @@ int32_t Muxer::WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) return AVCODEC_SAMPLE_ERR_OK; } -int32_t Muxer::WriteFrame(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +int32_t Muxer::WriteFrame(OH_AVBuffer *buffer) { CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null"); CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get a empty buffer"); diff --git a/entry/src/main/cpp/capbilities/include/Muxer.h b/entry/src/main/cpp/capbilities/include/Muxer.h index 60d465f..0e736c4 100644 --- a/entry/src/main/cpp/capbilities/include/Muxer.h +++ b/entry/src/main/cpp/capbilities/include/Muxer.h @@ -31,7 +31,7 @@ public: int32_t Config(SampleInfo &sampleInfo); int32_t Start(); int32_t WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); - int32_t WriteFrame(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + int32_t WriteFrame(OH_AVBuffer *buffer); int32_t Release(); private: diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.cpp b/entry/src/main/cpp/sample/recorder/audiorecord.cpp index 4dbc11f..cbb0726 100644 --- a/entry/src/main/cpp/sample/recorder/audiorecord.cpp +++ b/entry/src/main/cpp/sample/recorder/audiorecord.cpp @@ -1,9 +1,9 @@ -#include "audiorecord.h" +#include "AudioRecord.h" using namespace std; -int32_t samplingRate = 16000; -int32_t channelCount = 1; +int32_t SAMPLE_RATE = 16000; +int32_t CHANNEL_COUNT = 1; constexpr int32_t INPUT_FRAME_BYTES = 2 * 1024; static OH_AudioCapturer *audioCapturer; static OH_AudioStreamBuilder *builder; @@ -103,7 +103,7 @@ void AudioRecord::OutputFunc() OH_AVBuffer_GetBufferAttr(avBuffer, &info); size = info.size; AVCODEC_SAMPLE_LOGD("pts %{public}ld", info.pts); - muxerA_->WriteFrame(avBuffer, info); + muxerA_->WriteFrame(avBuffer); signal_->outBufferQueue_.pop(); signal_->outQueue_.pop(); OH_AudioCodec_FreeOutputBuffer(audioEnc_, index); @@ -125,8 +125,8 @@ void AudioRecord::AudioCapturerInit() OH_AudioStream_Type type = AUDIOSTREAM_TYPE_CAPTURER; OH_AudioStreamBuilder_Create(&builder, type); // set params and callbacks - OH_AudioStreamBuilder_SetSamplingRate(builder, samplingRate); - OH_AudioStreamBuilder_SetChannelCount(builder, channelCount); + OH_AudioStreamBuilder_SetSamplingRate(builder, SAMPLE_RATE); + OH_AudioStreamBuilder_SetChannelCount(builder, CHANNEL_COUNT); OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST); OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); @@ -138,8 +138,8 @@ void AudioRecord::AudioCapturerInit() //create audio encoder stream OH_AVFormat *format = OH_AVFormat_Create(); - OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, channelCount); - OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, samplingRate); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT ); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AUDIOSTREAM_SAMPLE_S16LE); audioEnc_ = OH_AudioCodec_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); -- Gitee From df9080cf7dbb4a240a254cd7931592dc3b4230df Mon Sep 17 00:00:00 2001 From: ziyugao Date: Fri, 3 Jan 2025 15:37:17 +0800 Subject: [PATCH 08/18] fix bug Signed-off-by: ziyugao --- entry/src/main/cpp/sample/player/Player.cpp | 9 +++++++++ entry/src/main/cpp/sample/player/Player.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index 7f89adc..c473961 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -157,6 +157,8 @@ int32_t Player::Start() { } void Player::StartRelease() { + std::unique_lock lock(doneMutex); + doneCond_.wait(lock, [this]() {return isAudioDone.load() && isVideoDone.load();}); if (audioRenderer_) { OH_AudioRenderer_Stop(audioRenderer_); } @@ -284,6 +286,9 @@ void Player::VideoDecOutputThread() { std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); lastPushTime = std::chrono::system_clock::now(); } + std::unique_lock lock(doneMutex); + isVideoDone = ture; + lock.unlock(); StartRelease(); } @@ -313,6 +318,7 @@ void Player::AudioDecInputThread() { } void Player::AudioDecOutputThread() { + isAudioDone = false; while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(audioDecContext_->outputMutex); @@ -352,5 +358,8 @@ void Player::AudioDecOutputThread() { }); } AVCODEC_SAMPLE_LOGI("Out buffer end"); + std::unique_lock lock(doneMutex); + isAudioDone = ture; + lock.unlock(); 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 a45ee8d..b8f17c6 100644 --- a/entry/src/main/cpp/sample/player/Player.h +++ b/entry/src/main/cpp/sample/player/Player.h @@ -61,8 +61,11 @@ private: std::unique_ptr demuxer_ = nullptr; std::mutex mutex_; + std::mutex doneMutex; std::atomic isStarted_{false}; std::atomic isReleased_{false}; + std::atomic isAudioDone{true}; + std::atomic isVideoDone{false}; std::unique_ptr videoDecInputThread_ = nullptr; std::unique_ptr videoDecOutputThread_ = nullptr; std::unique_ptr audioDecInputThread_ = nullptr; -- Gitee From 0ac105b243b69ac895a7170554ae4b36a6366c6e Mon Sep 17 00:00:00 2001 From: ziyugao Date: Fri, 3 Jan 2025 16:06:42 +0800 Subject: [PATCH 09/18] fixbug Signed-off-by: ziyugao --- entry/src/main/cpp/sample/player/Player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index c473961..f87a84d 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -287,7 +287,7 @@ void Player::VideoDecOutputThread() { lastPushTime = std::chrono::system_clock::now(); } std::unique_lock lock(doneMutex); - isVideoDone = ture; + isVideoDone = true; lock.unlock(); StartRelease(); } @@ -359,7 +359,7 @@ void Player::AudioDecOutputThread() { } AVCODEC_SAMPLE_LOGI("Out buffer end"); std::unique_lock lock(doneMutex); - isAudioDone = ture; + isAudioDone = true; lock.unlock(); StartRelease(); } \ No newline at end of file -- Gitee From 2d8bdbdc824185b0bae73e28d08d5fee3ec3ba68 Mon Sep 17 00:00:00 2001 From: 134******51 Date: Fri, 3 Jan 2025 08:07:18 +0000 Subject: [PATCH 10/18] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=20entry/src/m?= =?UTF-8?q?ain/cpp/sample/recorder/audiorecord.cpp=20=E4=B8=BA=20entry/src?= =?UTF-8?q?/main/cpp/sample/recorder/AudioRecord.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/cpp/sample/recorder/{audiorecord.cpp => AudioRecord.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename entry/src/main/cpp/sample/recorder/{audiorecord.cpp => AudioRecord.cpp} (100%) diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.cpp b/entry/src/main/cpp/sample/recorder/AudioRecord.cpp similarity index 100% rename from entry/src/main/cpp/sample/recorder/audiorecord.cpp rename to entry/src/main/cpp/sample/recorder/AudioRecord.cpp -- Gitee From 70d37b1b2bdf35aeb19bcbc7386668d3c8099f4c Mon Sep 17 00:00:00 2001 From: 134******51 Date: Fri, 3 Jan 2025 08:07:29 +0000 Subject: [PATCH 11/18] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=20entry/src/m?= =?UTF-8?q?ain/cpp/sample/recorder/audiorecord.h=20=E4=B8=BA=20entry/src/m?= =?UTF-8?q?ain/cpp/sample/recorder/AudioRecord.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/cpp/sample/recorder/{audiorecord.h => AudioRecord.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename entry/src/main/cpp/sample/recorder/{audiorecord.h => AudioRecord.h} (100%) diff --git a/entry/src/main/cpp/sample/recorder/audiorecord.h b/entry/src/main/cpp/sample/recorder/AudioRecord.h similarity index 100% rename from entry/src/main/cpp/sample/recorder/audiorecord.h rename to entry/src/main/cpp/sample/recorder/AudioRecord.h -- Gitee From 528334ecebb9489342244fb64966367577d1e64e Mon Sep 17 00:00:00 2001 From: ziyugao Date: Fri, 3 Jan 2025 17:18:58 +0800 Subject: [PATCH 12/18] fixbug Signed-off-by: ziyugao --- entry/src/main/cpp/sample/player/Player.cpp | 263 ++++++++++++++------ entry/src/main/cpp/sample/player/Player.h | 45 ++-- 2 files changed, 208 insertions(+), 100 deletions(-) diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index f87a84d..edd5a41 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -1,22 +1,9 @@ -/* - * 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 "Player.h" +#include #include -#include "AVCodecSampleLog.h" -#include "dfx/error/AVCodecSampleError.h" +#include +#include "av_codec_sample_log.h" +#include "dfx/error/av_codec_sample_error.h" #undef LOG_TAG #define LOG_TAG "player" @@ -24,14 +11,26 @@ namespace { constexpr int BALANCE_VALUE = 5; using namespace std::chrono_literals; +static const int MS_TO_S = 1000; +constexpr int64_t WAIT_TIME_US_THRESHOLD_WARNING = -1 * 40 * 1000; // warning threshold 40ms +constexpr int64_t WAIT_TIME_US_THRESHOLD = 1 * 1000 * 1000; // max sleep time 1s +constexpr int64_t SINK_TIME_US_THRESHOLD = 100000; // max sink time 100ms +constexpr int32_t BYTES_PER_SAMPLE_2 = 2; // 2 bytes per sample +constexpr double VSYNC_TIME = 1000 / 60; // frame time +constexpr double LIP_SYNC_BALANCE_VALUE = 2; // the balance value of sync sound and picture } // namespace -Player::~Player() { Player::StartRelease(); } +Player::~Player() +{ + Player::StartRelease(); +} -int32_t Player::CreateAudioDecoder() { +int32_t Player::CreateAudioDecoder() +{ AVCODEC_SAMPLE_LOGW("audio mime:%{public}s", sampleInfo_.audioCodecMime.c_str()); int32_t ret = audioDecoder_->Create(sampleInfo_.audioCodecMime); if (ret != AVCODEC_SAMPLE_ERR_OK) { + isAudioDone.store(true); AVCODEC_SAMPLE_LOGE("Create audio decoder failed, mime:%{public}s", sampleInfo_.audioCodecMime.c_str()); } else { audioDecContext_ = new CodecUserData; @@ -39,20 +38,20 @@ int32_t Player::CreateAudioDecoder() { CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Audio Decoder config failed"); OH_AudioStreamBuilder_Create(&builder_, AUDIOSTREAM_TYPE_RENDERER); OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL); - // Set the audio sample rate + // 设置音频采样率 OH_AudioStreamBuilder_SetSamplingRate(builder_, sampleInfo_.audioSampleRate); - // Set the audio channel + // 设置音频声道 OH_AudioStreamBuilder_SetChannelCount(builder_, sampleInfo_.audioChannelCount); - // Set the audio sample format + // 设置音频采样格式 OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S16LE); - // Sets the encoding type of the audio stream + // 设置音频流的编码类型 OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_RAW); - // Set the working scenario for the output audio stream + // 设置输出音频流的工作场景 OH_AudioStreamBuilder_SetRendererInfo(builder_, AUDIOSTREAM_USAGE_MUSIC); AVCODEC_SAMPLE_LOGW("Init audioSampleRate: %{public}d, ChannelCount: %{public}d", sampleInfo_.audioSampleRate, sampleInfo_.audioChannelCount); OH_AudioRenderer_Callbacks callbacks; - // Configure the callback function + // 配置回调函数 #ifndef DEBUG_DECODE callbacks.OH_AudioRenderer_OnWriteData = SampleCallback::OnRenderWriteData; #else @@ -61,17 +60,19 @@ int32_t Player::CreateAudioDecoder() { callbacks.OH_AudioRenderer_OnStreamEvent = SampleCallback::OnRenderStreamEvent; callbacks.OH_AudioRenderer_OnInterruptEvent = SampleCallback::OnRenderInterruptEvent; callbacks.OH_AudioRenderer_OnError = SampleCallback::OnRenderError; - // Set the callback for the output audio stream + // 设置输出音频流的回调 OH_AudioStreamBuilder_SetRendererCallback(builder_, callbacks, audioDecContext_); OH_AudioStreamBuilder_GenerateRenderer(builder_, &audioRenderer_); } return AVCODEC_SAMPLE_ERR_OK; } -int32_t Player::CreateVideoDecoder() { +int32_t Player::CreateVideoDecoder() +{ AVCODEC_SAMPLE_LOGW("video mime:%{public}s", sampleInfo_.videoCodecMime.c_str()); int32_t ret = videoDecoder_->Create(sampleInfo_.videoCodecMime); - if (ret != AVCODEC_SAMPLE_ERR_OK) { + if (ret != AVCODEC_SAMPLE_ERR_OK) {\ + isVideoDone.store(true); AVCODEC_SAMPLE_LOGW("Create video decoder failed, mime:%{public}s", sampleInfo_.videoCodecMime.c_str()); } else { videoDecContext_ = new CodecUserData; @@ -82,33 +83,35 @@ int32_t Player::CreateVideoDecoder() { return AVCODEC_SAMPLE_ERR_OK; } -int32_t Player::Init(SampleInfo &sampleInfo) { +int32_t Player::Init(SampleInfo &sampleInfo) +{ std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(demuxer_ == nullptr && videoDecoder_ == nullptr && audioDecoder_ == nullptr, - AVCODEC_SAMPLE_ERR_ERROR, "Already started."); - + AVCODEC_SAMPLE_ERR_ERROR, "Already started."); + sampleInfo_ = sampleInfo; - + videoDecoder_ = std::make_unique(); audioDecoder_ = std::make_unique(); demuxer_ = std::make_unique(); - + int32_t ret = demuxer_->Create(sampleInfo_); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Create demuxer failed"); - + ret = CreateAudioDecoder(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Create audio decoder failed"); - + ret = CreateVideoDecoder(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Create video decoder failed"); - + isReleased_ = false; AVCODEC_SAMPLE_LOGI("Succeed"); return AVCODEC_SAMPLE_ERR_OK; } -int32_t Player::Start() { +int32_t Player::Start() +{ std::lock_guard lock(mutex_); int32_t ret; CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); @@ -133,32 +136,33 @@ int32_t Player::Start() { audioDecInputThread_ = std::make_unique(&Player::AudioDecInputThread, this); audioDecOutputThread_ = std::make_unique(&Player::AudioDecOutputThread, this); #ifdef DEBUG_DECODE - // for debug The decoded data is written to the sandbox address, and the physical address is - // /data/app/el2/100/base/com.example.avcodecsample/haps/entry/files/ + // for debug 解码数据写入沙箱地址,物理地址为/data/app/el2/100/base/com.example.avcodecsample/haps/entry/files/ audioOutputFile_.open("/data/storage/el2/base/haps/entry/files/audio_decode_out.pcm", - std::ios::out | std::ios::binary); + std::ios::out | std::ios::binary); #endif if (audioDecInputThread_ == nullptr || audioDecOutputThread_ == nullptr) { AVCODEC_SAMPLE_LOGE("Create thread failed"); StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } - } - // Clear the queue - while (audioDecContext_ && !audioDecContext_->renderQueue.empty()) { - audioDecContext_->renderQueue.pop(); - } - if (audioRenderer_) { - OH_AudioRenderer_Start(audioRenderer_); + + // 清空队列 + while (audioDecContext_ && !audioDecContext_->renderQueue.empty()) { + audioDecContext_->renderQueue.pop(); + } + if (audioRenderer_) { + OH_AudioRenderer_Start(audioRenderer_); + } } AVCODEC_SAMPLE_LOGI("Succeed"); doneCond_.notify_all(); return AVCODEC_SAMPLE_ERR_OK; } -void Player::StartRelease() { +void Player::StartRelease() +{ std::unique_lock lock(doneMutex); - doneCond_.wait(lock, [this]() {return isAudioDone.load() && isVideoDone.load();}); + doneCond_.wait(lock, [this]() { return isAudioDone.load() && isVideoDone.load();}); if (audioRenderer_) { OH_AudioRenderer_Stop(audioRenderer_); } @@ -168,7 +172,8 @@ void Player::StartRelease() { } } -void Player::ReleaseThread() { +void Player::ReleaseThread() +{ if (videoDecInputThread_ && videoDecInputThread_->joinable()) { videoDecInputThread_->detach(); videoDecInputThread_.reset(); @@ -187,11 +192,14 @@ void Player::ReleaseThread() { } } -void Player::Release() { +void Player::Release() +{ std::lock_guard lock(mutex_); isStarted_ = false; + isAudioDone = false; + isVideoDone = false; - // Clear the queue + // 清空队列 while (audioDecContext_ && !audioDecContext_->renderQueue.empty()) { audioDecContext_->renderQueue.pop(); } @@ -205,7 +213,7 @@ void Player::Release() { } #endif ReleaseThread(); - + if (demuxer_ != nullptr) { demuxer_->Release(); demuxer_.reset(); @@ -226,15 +234,18 @@ void Player::Release() { delete audioDecContext_; audioDecContext_ = nullptr; } - OH_AudioStreamBuilder_Destroy(builder_); - builder_ = nullptr; + if(builder_ != nullptr) { + OH_AudioStreamBuilder_Destroy(builder_); + builder_ = nullptr; + } doneCond_.notify_all(); - // Trigger the callback + // 触发回调 sampleInfo_.playDoneCallback(sampleInfo_.playDoneCallbackData); AVCODEC_SAMPLE_LOGI("Succeed"); } -void Player::VideoDecInputThread() { +void Player::VideoDecInputThread() +{ while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder input thread out"); std::unique_lock lock(videoDecContext_->inputMutex); @@ -248,26 +259,28 @@ void Player::VideoDecInputThread() { videoDecContext_->inputBufferInfoQueue.pop(); videoDecContext_->inputFrameCount++; lock.unlock(); - + demuxer_->ReadSample(demuxer_->GetVideoTrackId(), reinterpret_cast(bufferInfo.buffer), - bufferInfo.attr); + bufferInfo.attr); int32_t ret = videoDecoder_->PushInputBuffer(bufferInfo); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Push data failed, thread out"); - + CHECK_AND_BREAK_LOG(!(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS), "Catch EOS, thread out"); } } -void Player::VideoDecOutputThread() { - sampleInfo_.frameInterval = MICROSECOND / sampleInfo_.frameRate; +void Player::VideoDecOutputThread() +{ + sampleInfo_.frameInterval = MICROSECOND_TO_S / sampleInfo_.frameRate; + int64_t PER_SINK_TIME_THRESHOLD = MS_TO_S / sampleInfo_.frameRate * MS_TO_S; // max per sink time while (true) { thread_local auto lastPushTime = std::chrono::system_clock::now(); - CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); + CHECK_AND_BREAK_LOG(isStarted_, "VD Decoder output thread out"); std::unique_lock lock(videoDecContext_->outputMutex); bool condRet = videoDecContext_->outputCond.wait_for( lock, 5s, [this]() { return !isStarted_ || !videoDecContext_->outputBufferInfoQueue.empty(); }); - CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); + CHECK_AND_BREAK_LOG(isStarted_, "VD Decoder output thread out"); CHECK_AND_CONTINUE_LOG(!videoDecContext_->outputBufferInfoQueue.empty(), "Buffer queue is empty, continue, cond ret: %{public}d", condRet); @@ -279,20 +292,89 @@ void Player::VideoDecOutputThread() { videoDecContext_->outputFrameCount, bufferInfo.attr.size, bufferInfo.attr.flags, bufferInfo.attr.pts); lock.unlock(); - - int32_t ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true); - CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); - - std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); - lastPushTime = std::chrono::system_clock::now(); + + if(!audioDecContext_){ + int32_t ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true, GetCurrentTime()); + CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); + + std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); + lastPushTime = std::chrono::system_clock::now(); + }else { + // get audio render position + int64_t framePosition = 0; + int64_t timestamp = 0; + int32_t ret = OH_AudioRenderer_GetTimestamp(audioRenderer_, CLOCK_MONOTONIC, &framePosition, ×tamp); + AVCODEC_SAMPLE_LOGI("VD framePosition: %{public}li, nowTimeStamp: %{public}li", framePosition, nowTimeStamp); + audioTimeStamp = timestamp; // ns + // audio render getTimeStamp error, render it + if (ret != AUDIOSTREAM_SUCCESS || (timestamp == 0) || (framePosition == 0)) { + // first frame, render without wait + ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true, GetCurrentTime()); + CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); + std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); + lastPushTime = std::chrono::system_clock::now(); + continue; + } + // after seek, audio render flush, framePosition = 0, then writtenSampleCnt = 0 + int64_t latency = (writtenSampleCnt - framePosition) * 1000 * 1000 / sampleInfo_.audioSampleRate; + AVCODEC_SAMPLE_LOGI("VD latency: %{public}li writtenSampleCnt: %{public}li", latency, writtenSampleCnt); + + nowTimeStamp = GetCurrentTime(); + int64_t anchordiff = (nowTimeStamp - audioTimeStamp) / 1000; + + int64_t audioPlayedTime = audioBufferPts - latency + anchordiff; // us, audio buffer accelerate render time + int64_t videoPlayedTime = bufferInfo.attr.pts; // us, video buffer expected render time + + // audio render timestamp and now timestamp diff + int64_t waitTimeUs = videoPlayedTime - audioPlayedTime; // us + + AVCODEC_SAMPLE_LOGI("VD bufferInfo.bufferIndex: %{public}li", bufferInfo.bufferIndex); + AVCODEC_SAMPLE_LOGI( + "VD audioPlayedTime: %{public}li, videoPlayedTime: %{public}li, nowTimeStamp_:{public}ld, " + "audioTimeStamp_ :{public}ld, waitTimeUs :{public}ld, anchordiff :%{public}ld", + audioPlayedTime, videoPlayedTime, nowTimeStamp, audioTimeStamp, waitTimeUs, anchordiff); + + bool dropFrame = false; + + // video buffer is too late, drop it + if (waitTimeUs < WAIT_TIME_US_THRESHOLD_WARNING) { + dropFrame = true; + AVCODEC_SAMPLE_LOGI("VD buffer is too late"); + } else { + AVCODEC_SAMPLE_LOGE("VD buffer is too early waitTimeUs:%{public}ld", waitTimeUs); + // [0, ), render it wait waitTimeUs, max 1s + // [-40, 0), render it + if (waitTimeUs > WAIT_TIME_US_THRESHOLD) { + waitTimeUs = WAIT_TIME_US_THRESHOLD; + } + // per frame render time reduced by 33ms + if (waitTimeUs > sampleInfo_.frameInterval + PER_SINK_TIME_THRESHOLD) { + waitTimeUs = sampleInfo_.frameInterval + PER_SINK_TIME_THRESHOLD; + AVCODEC_SAMPLE_LOGE("VD buffer is too early and reduced 33ms, waitTimeUs: %{public}ld", waitTimeUs); + } + } + + if (static_cast(waitTimeUs) > VSYNC_TIME * LIP_SYNC_BALANCE_VALUE) { + std::this_thread::sleep_for(std::chrono::microseconds( + static_cast(static_cast(waitTimeUs)-VSYNC_TIME * LIP_SYNC_BALANCE_VALUE))); + } + + ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, !dropFrame, VSYNC_TIME * LIP_SYNC_BALANCE_VALUE * 1000 + GetCurrentTime()); + CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread"); + } } + + writtenSampleCnt = 0; + audioBufferPts = 0; std::unique_lock lock(doneMutex); - isVideoDone = true; + isVideoDone.store(true); lock.unlock(); + doneCond_.notify_all(); StartRelease(); } -void Player::AudioDecInputThread() { +void Player::AudioDecInputThread() +{ while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder input thread out"); std::unique_lock lock(audioDecContext_->inputMutex); @@ -308,17 +390,17 @@ void Player::AudioDecInputThread() { lock.unlock(); demuxer_->ReadSample(demuxer_->GetAudioTrackId(), reinterpret_cast(bufferInfo.buffer), - bufferInfo.attr); + bufferInfo.attr); int32_t ret = audioDecoder_->PushInputBuffer(bufferInfo); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Push data failed, thread out"); - + CHECK_AND_BREAK_LOG(!(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS), "Catch EOS, thread out"); } } -void Player::AudioDecOutputThread() { - isAudioDone = false; +void Player::AudioDecOutputThread() +{ while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(audioDecContext_->outputMutex); @@ -336,14 +418,13 @@ void Player::AudioDecOutputThread() { audioDecContext_->outputFrameCount, bufferInfo.attr.size, bufferInfo.attr.flags, bufferInfo.attr.pts); uint8_t *source = OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)); - // Put the decoded PMC data into the queue + // 将解码后的PMC数据放入队列中 for (int i = 0; i < bufferInfo.attr.size; i++) { audioDecContext_->renderQueue.push(*(source + i)); } #ifdef DEBUG_DECODE if (audioOutputFile_.is_open()) { - audioOutputFile_.write( - (const char *)OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)), + audioOutputFile_.write((const char*)OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)), bufferInfo.attr.size); } #endif @@ -351,15 +432,31 @@ void Player::AudioDecOutputThread() { int32_t ret = audioDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); + + // SAMPLE_S16LE 2 bytes per frame + // if set speed, cnt / speed + writtenSampleCnt += (bufferInfo.attr.size / sampleInfo_.audioChannelCount / BYTES_PER_SAMPLE_2); + AVCODEC_SAMPLE_LOGI("writtenSampleCnt_: %ld, bufferInfo.attr.size: %i, sampleInfo_.audioChannelCount: %i", + writtenSampleCnt, bufferInfo.attr.size, sampleInfo_.audioChannelCount); + audioBufferPts = bufferInfo.attr.pts; std::unique_lock lockRender(audioDecContext_->renderMutex); - audioDecContext_->renderCond.wait_for(lockRender, 20ms, [this, bufferInfo]() { - return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; - }); + audioDecContext_->renderCond.wait_for(lockRender, 20ms, + [this, bufferInfo]() { + return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; + }); } AVCODEC_SAMPLE_LOGI("Out buffer end"); std::unique_lock lock(doneMutex); isAudioDone = true; lock.unlock(); + doneCond_.notify_all(); StartRelease(); -} \ No newline at end of file +} + +int64_t Player::GetCurrentTime() +{ + auto now = std::chrono::steady_clock::now(); + auto now_ns = std::chrono::time_point_cast(now); + return now_ns.time_since_epoch().count(); +} diff --git a/entry/src/main/cpp/sample/player/Player.h b/entry/src/main/cpp/sample/player/Player.h index b8f17c6..4d89627 100644 --- a/entry/src/main/cpp/sample/player/Player.h +++ b/entry/src/main/cpp/sample/player/Player.h @@ -1,5 +1,8 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 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 @@ -25,19 +28,20 @@ #include #include #include -#include "VideoDecoder.h" -#include "AudioDecoder.h" +#include "video_decoder.h" +#include "audio_decoder.h" #include "multimedia/player_framework/native_avbuffer.h" -#include "Demuxer.h" -#include "SampleInfo.h" -#include "PluginManager.h" +#include "demuxer.h" +#include "sample_info.h" +#include "plugin_manager.h" class Player { public: Player(){}; ~Player(); - - static Player &GetInstance() { + + static Player& GetInstance() + { static Player player; return player; } @@ -55,31 +59,38 @@ private: void ReleaseThread(); int32_t CreateAudioDecoder(); int32_t CreateVideoDecoder(); + int64_t GetCurrentTime(); std::unique_ptr videoDecoder_ = nullptr; std::shared_ptr audioDecoder_ = nullptr; std::unique_ptr demuxer_ = nullptr; - + std::mutex mutex_; - std::mutex doneMutex; - std::atomic isStarted_{false}; - std::atomic isReleased_{false}; - std::atomic isAudioDone{true}; - std::atomic isVideoDone{false}; + std::atomic isStarted_ { false }; + std::atomic isReleased_ { false }; + std::atomic isAudioDone { false }; + std::atomic isVideoDone { false }; std::unique_ptr videoDecInputThread_ = nullptr; std::unique_ptr videoDecOutputThread_ = nullptr; std::unique_ptr audioDecInputThread_ = nullptr; std::unique_ptr audioDecOutputThread_ = nullptr; std::condition_variable doneCond_; + std::mutex doneMutex; SampleInfo sampleInfo_; CodecUserData *videoDecContext_ = nullptr; CodecUserData *audioDecContext_ = nullptr; - OH_AudioStreamBuilder *builder_ = nullptr; - OH_AudioRenderer *audioRenderer_ = nullptr; + OH_AudioStreamBuilder* builder_ = nullptr; + OH_AudioRenderer* audioRenderer_ = nullptr; + + int64_t nowTimeStamp = 0; + int64_t audioTimeStamp = 0; + int64_t writtenSampleCnt = 0; + int64_t audioBufferPts = 0; #ifdef DEBUG_DECODE std::ofstream audioOutputFile_; // for debug #endif - static constexpr int64_t MICROSECOND = 1000000; + static constexpr int64_t MICROSECOND_TO_S = 1000000; + static constexpr int64_t NANO_TO_S = 1000000000; }; #endif // VIDEO_CODEC_PLAYER_H \ No newline at end of file -- Gitee From 56881fb8596bbd5ffaa86a4acb4a26af388a47ae Mon Sep 17 00:00:00 2001 From: 134******51 Date: Fri, 3 Jan 2025 09:26:33 +0000 Subject: [PATCH 13/18] Revert "fixbug" This reverts commit 528334ecebb9489342244fb64966367577d1e64e. --- entry/src/main/cpp/sample/player/Player.cpp | 263 ++++++-------------- entry/src/main/cpp/sample/player/Player.h | 45 ++-- 2 files changed, 100 insertions(+), 208 deletions(-) diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index edd5a41..f87a84d 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -1,9 +1,22 @@ +/* + * 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 "Player.h" -#include #include -#include -#include "av_codec_sample_log.h" -#include "dfx/error/av_codec_sample_error.h" +#include "AVCodecSampleLog.h" +#include "dfx/error/AVCodecSampleError.h" #undef LOG_TAG #define LOG_TAG "player" @@ -11,26 +24,14 @@ namespace { constexpr int BALANCE_VALUE = 5; using namespace std::chrono_literals; -static const int MS_TO_S = 1000; -constexpr int64_t WAIT_TIME_US_THRESHOLD_WARNING = -1 * 40 * 1000; // warning threshold 40ms -constexpr int64_t WAIT_TIME_US_THRESHOLD = 1 * 1000 * 1000; // max sleep time 1s -constexpr int64_t SINK_TIME_US_THRESHOLD = 100000; // max sink time 100ms -constexpr int32_t BYTES_PER_SAMPLE_2 = 2; // 2 bytes per sample -constexpr double VSYNC_TIME = 1000 / 60; // frame time -constexpr double LIP_SYNC_BALANCE_VALUE = 2; // the balance value of sync sound and picture } // namespace -Player::~Player() -{ - Player::StartRelease(); -} +Player::~Player() { Player::StartRelease(); } -int32_t Player::CreateAudioDecoder() -{ +int32_t Player::CreateAudioDecoder() { AVCODEC_SAMPLE_LOGW("audio mime:%{public}s", sampleInfo_.audioCodecMime.c_str()); int32_t ret = audioDecoder_->Create(sampleInfo_.audioCodecMime); if (ret != AVCODEC_SAMPLE_ERR_OK) { - isAudioDone.store(true); AVCODEC_SAMPLE_LOGE("Create audio decoder failed, mime:%{public}s", sampleInfo_.audioCodecMime.c_str()); } else { audioDecContext_ = new CodecUserData; @@ -38,20 +39,20 @@ int32_t Player::CreateAudioDecoder() CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Audio Decoder config failed"); OH_AudioStreamBuilder_Create(&builder_, AUDIOSTREAM_TYPE_RENDERER); OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL); - // 设置音频采样率 + // Set the audio sample rate OH_AudioStreamBuilder_SetSamplingRate(builder_, sampleInfo_.audioSampleRate); - // 设置音频声道 + // Set the audio channel OH_AudioStreamBuilder_SetChannelCount(builder_, sampleInfo_.audioChannelCount); - // 设置音频采样格式 + // Set the audio sample format OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S16LE); - // 设置音频流的编码类型 + // Sets the encoding type of the audio stream OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_RAW); - // 设置输出音频流的工作场景 + // Set the working scenario for the output audio stream OH_AudioStreamBuilder_SetRendererInfo(builder_, AUDIOSTREAM_USAGE_MUSIC); AVCODEC_SAMPLE_LOGW("Init audioSampleRate: %{public}d, ChannelCount: %{public}d", sampleInfo_.audioSampleRate, sampleInfo_.audioChannelCount); OH_AudioRenderer_Callbacks callbacks; - // 配置回调函数 + // Configure the callback function #ifndef DEBUG_DECODE callbacks.OH_AudioRenderer_OnWriteData = SampleCallback::OnRenderWriteData; #else @@ -60,19 +61,17 @@ int32_t Player::CreateAudioDecoder() callbacks.OH_AudioRenderer_OnStreamEvent = SampleCallback::OnRenderStreamEvent; callbacks.OH_AudioRenderer_OnInterruptEvent = SampleCallback::OnRenderInterruptEvent; callbacks.OH_AudioRenderer_OnError = SampleCallback::OnRenderError; - // 设置输出音频流的回调 + // Set the callback for the output audio stream OH_AudioStreamBuilder_SetRendererCallback(builder_, callbacks, audioDecContext_); OH_AudioStreamBuilder_GenerateRenderer(builder_, &audioRenderer_); } return AVCODEC_SAMPLE_ERR_OK; } -int32_t Player::CreateVideoDecoder() -{ +int32_t Player::CreateVideoDecoder() { AVCODEC_SAMPLE_LOGW("video mime:%{public}s", sampleInfo_.videoCodecMime.c_str()); int32_t ret = videoDecoder_->Create(sampleInfo_.videoCodecMime); - if (ret != AVCODEC_SAMPLE_ERR_OK) {\ - isVideoDone.store(true); + if (ret != AVCODEC_SAMPLE_ERR_OK) { AVCODEC_SAMPLE_LOGW("Create video decoder failed, mime:%{public}s", sampleInfo_.videoCodecMime.c_str()); } else { videoDecContext_ = new CodecUserData; @@ -83,35 +82,33 @@ int32_t Player::CreateVideoDecoder() return AVCODEC_SAMPLE_ERR_OK; } -int32_t Player::Init(SampleInfo &sampleInfo) -{ +int32_t Player::Init(SampleInfo &sampleInfo) { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(demuxer_ == nullptr && videoDecoder_ == nullptr && audioDecoder_ == nullptr, - AVCODEC_SAMPLE_ERR_ERROR, "Already started."); - + AVCODEC_SAMPLE_ERR_ERROR, "Already started."); + sampleInfo_ = sampleInfo; - + videoDecoder_ = std::make_unique(); audioDecoder_ = std::make_unique(); demuxer_ = std::make_unique(); - + int32_t ret = demuxer_->Create(sampleInfo_); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Create demuxer failed"); - + ret = CreateAudioDecoder(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Create audio decoder failed"); - + ret = CreateVideoDecoder(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Create video decoder failed"); - + isReleased_ = false; AVCODEC_SAMPLE_LOGI("Succeed"); return AVCODEC_SAMPLE_ERR_OK; } -int32_t Player::Start() -{ +int32_t Player::Start() { std::lock_guard lock(mutex_); int32_t ret; CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); @@ -136,33 +133,32 @@ int32_t Player::Start() audioDecInputThread_ = std::make_unique(&Player::AudioDecInputThread, this); audioDecOutputThread_ = std::make_unique(&Player::AudioDecOutputThread, this); #ifdef DEBUG_DECODE - // for debug 解码数据写入沙箱地址,物理地址为/data/app/el2/100/base/com.example.avcodecsample/haps/entry/files/ + // for debug The decoded data is written to the sandbox address, and the physical address is + // /data/app/el2/100/base/com.example.avcodecsample/haps/entry/files/ audioOutputFile_.open("/data/storage/el2/base/haps/entry/files/audio_decode_out.pcm", - std::ios::out | std::ios::binary); + std::ios::out | std::ios::binary); #endif if (audioDecInputThread_ == nullptr || audioDecOutputThread_ == nullptr) { AVCODEC_SAMPLE_LOGE("Create thread failed"); StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } - - // 清空队列 - while (audioDecContext_ && !audioDecContext_->renderQueue.empty()) { - audioDecContext_->renderQueue.pop(); - } - if (audioRenderer_) { - OH_AudioRenderer_Start(audioRenderer_); - } + } + // Clear the queue + while (audioDecContext_ && !audioDecContext_->renderQueue.empty()) { + audioDecContext_->renderQueue.pop(); + } + if (audioRenderer_) { + OH_AudioRenderer_Start(audioRenderer_); } AVCODEC_SAMPLE_LOGI("Succeed"); doneCond_.notify_all(); return AVCODEC_SAMPLE_ERR_OK; } -void Player::StartRelease() -{ +void Player::StartRelease() { std::unique_lock lock(doneMutex); - doneCond_.wait(lock, [this]() { return isAudioDone.load() && isVideoDone.load();}); + doneCond_.wait(lock, [this]() {return isAudioDone.load() && isVideoDone.load();}); if (audioRenderer_) { OH_AudioRenderer_Stop(audioRenderer_); } @@ -172,8 +168,7 @@ void Player::StartRelease() } } -void Player::ReleaseThread() -{ +void Player::ReleaseThread() { if (videoDecInputThread_ && videoDecInputThread_->joinable()) { videoDecInputThread_->detach(); videoDecInputThread_.reset(); @@ -192,14 +187,11 @@ void Player::ReleaseThread() } } -void Player::Release() -{ +void Player::Release() { std::lock_guard lock(mutex_); isStarted_ = false; - isAudioDone = false; - isVideoDone = false; - // 清空队列 + // Clear the queue while (audioDecContext_ && !audioDecContext_->renderQueue.empty()) { audioDecContext_->renderQueue.pop(); } @@ -213,7 +205,7 @@ void Player::Release() } #endif ReleaseThread(); - + if (demuxer_ != nullptr) { demuxer_->Release(); demuxer_.reset(); @@ -234,18 +226,15 @@ void Player::Release() delete audioDecContext_; audioDecContext_ = nullptr; } - if(builder_ != nullptr) { - OH_AudioStreamBuilder_Destroy(builder_); - builder_ = nullptr; - } + OH_AudioStreamBuilder_Destroy(builder_); + builder_ = nullptr; doneCond_.notify_all(); - // 触发回调 + // Trigger the callback sampleInfo_.playDoneCallback(sampleInfo_.playDoneCallbackData); AVCODEC_SAMPLE_LOGI("Succeed"); } -void Player::VideoDecInputThread() -{ +void Player::VideoDecInputThread() { while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder input thread out"); std::unique_lock lock(videoDecContext_->inputMutex); @@ -259,28 +248,26 @@ void Player::VideoDecInputThread() videoDecContext_->inputBufferInfoQueue.pop(); videoDecContext_->inputFrameCount++; lock.unlock(); - + demuxer_->ReadSample(demuxer_->GetVideoTrackId(), reinterpret_cast(bufferInfo.buffer), - bufferInfo.attr); + bufferInfo.attr); int32_t ret = videoDecoder_->PushInputBuffer(bufferInfo); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Push data failed, thread out"); - + CHECK_AND_BREAK_LOG(!(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS), "Catch EOS, thread out"); } } -void Player::VideoDecOutputThread() -{ - sampleInfo_.frameInterval = MICROSECOND_TO_S / sampleInfo_.frameRate; - int64_t PER_SINK_TIME_THRESHOLD = MS_TO_S / sampleInfo_.frameRate * MS_TO_S; // max per sink time +void Player::VideoDecOutputThread() { + sampleInfo_.frameInterval = MICROSECOND / sampleInfo_.frameRate; while (true) { thread_local auto lastPushTime = std::chrono::system_clock::now(); - CHECK_AND_BREAK_LOG(isStarted_, "VD Decoder output thread out"); + CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(videoDecContext_->outputMutex); bool condRet = videoDecContext_->outputCond.wait_for( lock, 5s, [this]() { return !isStarted_ || !videoDecContext_->outputBufferInfoQueue.empty(); }); - CHECK_AND_BREAK_LOG(isStarted_, "VD Decoder output thread out"); + CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); CHECK_AND_CONTINUE_LOG(!videoDecContext_->outputBufferInfoQueue.empty(), "Buffer queue is empty, continue, cond ret: %{public}d", condRet); @@ -292,89 +279,20 @@ void Player::VideoDecOutputThread() videoDecContext_->outputFrameCount, bufferInfo.attr.size, bufferInfo.attr.flags, bufferInfo.attr.pts); lock.unlock(); - - if(!audioDecContext_){ - int32_t ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true, GetCurrentTime()); - CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); - - std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); - lastPushTime = std::chrono::system_clock::now(); - }else { - // get audio render position - int64_t framePosition = 0; - int64_t timestamp = 0; - int32_t ret = OH_AudioRenderer_GetTimestamp(audioRenderer_, CLOCK_MONOTONIC, &framePosition, ×tamp); - AVCODEC_SAMPLE_LOGI("VD framePosition: %{public}li, nowTimeStamp: %{public}li", framePosition, nowTimeStamp); - audioTimeStamp = timestamp; // ns - // audio render getTimeStamp error, render it - if (ret != AUDIOSTREAM_SUCCESS || (timestamp == 0) || (framePosition == 0)) { - // first frame, render without wait - ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true, GetCurrentTime()); - CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); - std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); - lastPushTime = std::chrono::system_clock::now(); - continue; - } - // after seek, audio render flush, framePosition = 0, then writtenSampleCnt = 0 - int64_t latency = (writtenSampleCnt - framePosition) * 1000 * 1000 / sampleInfo_.audioSampleRate; - AVCODEC_SAMPLE_LOGI("VD latency: %{public}li writtenSampleCnt: %{public}li", latency, writtenSampleCnt); - - nowTimeStamp = GetCurrentTime(); - int64_t anchordiff = (nowTimeStamp - audioTimeStamp) / 1000; - - int64_t audioPlayedTime = audioBufferPts - latency + anchordiff; // us, audio buffer accelerate render time - int64_t videoPlayedTime = bufferInfo.attr.pts; // us, video buffer expected render time - - // audio render timestamp and now timestamp diff - int64_t waitTimeUs = videoPlayedTime - audioPlayedTime; // us - - AVCODEC_SAMPLE_LOGI("VD bufferInfo.bufferIndex: %{public}li", bufferInfo.bufferIndex); - AVCODEC_SAMPLE_LOGI( - "VD audioPlayedTime: %{public}li, videoPlayedTime: %{public}li, nowTimeStamp_:{public}ld, " - "audioTimeStamp_ :{public}ld, waitTimeUs :{public}ld, anchordiff :%{public}ld", - audioPlayedTime, videoPlayedTime, nowTimeStamp, audioTimeStamp, waitTimeUs, anchordiff); - - bool dropFrame = false; - - // video buffer is too late, drop it - if (waitTimeUs < WAIT_TIME_US_THRESHOLD_WARNING) { - dropFrame = true; - AVCODEC_SAMPLE_LOGI("VD buffer is too late"); - } else { - AVCODEC_SAMPLE_LOGE("VD buffer is too early waitTimeUs:%{public}ld", waitTimeUs); - // [0, ), render it wait waitTimeUs, max 1s - // [-40, 0), render it - if (waitTimeUs > WAIT_TIME_US_THRESHOLD) { - waitTimeUs = WAIT_TIME_US_THRESHOLD; - } - // per frame render time reduced by 33ms - if (waitTimeUs > sampleInfo_.frameInterval + PER_SINK_TIME_THRESHOLD) { - waitTimeUs = sampleInfo_.frameInterval + PER_SINK_TIME_THRESHOLD; - AVCODEC_SAMPLE_LOGE("VD buffer is too early and reduced 33ms, waitTimeUs: %{public}ld", waitTimeUs); - } - } - - if (static_cast(waitTimeUs) > VSYNC_TIME * LIP_SYNC_BALANCE_VALUE) { - std::this_thread::sleep_for(std::chrono::microseconds( - static_cast(static_cast(waitTimeUs)-VSYNC_TIME * LIP_SYNC_BALANCE_VALUE))); - } - - ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, !dropFrame, VSYNC_TIME * LIP_SYNC_BALANCE_VALUE * 1000 + GetCurrentTime()); - CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread"); - } + + int32_t ret = videoDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true); + CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); + + std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); + lastPushTime = std::chrono::system_clock::now(); } - - writtenSampleCnt = 0; - audioBufferPts = 0; std::unique_lock lock(doneMutex); - isVideoDone.store(true); + isVideoDone = true; lock.unlock(); - doneCond_.notify_all(); StartRelease(); } -void Player::AudioDecInputThread() -{ +void Player::AudioDecInputThread() { while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder input thread out"); std::unique_lock lock(audioDecContext_->inputMutex); @@ -390,17 +308,17 @@ void Player::AudioDecInputThread() lock.unlock(); demuxer_->ReadSample(demuxer_->GetAudioTrackId(), reinterpret_cast(bufferInfo.buffer), - bufferInfo.attr); + bufferInfo.attr); int32_t ret = audioDecoder_->PushInputBuffer(bufferInfo); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Push data failed, thread out"); - + CHECK_AND_BREAK_LOG(!(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS), "Catch EOS, thread out"); } } -void Player::AudioDecOutputThread() -{ +void Player::AudioDecOutputThread() { + isAudioDone = false; while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(audioDecContext_->outputMutex); @@ -418,13 +336,14 @@ void Player::AudioDecOutputThread() audioDecContext_->outputFrameCount, bufferInfo.attr.size, bufferInfo.attr.flags, bufferInfo.attr.pts); uint8_t *source = OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)); - // 将解码后的PMC数据放入队列中 + // Put the decoded PMC data into the queue for (int i = 0; i < bufferInfo.attr.size; i++) { audioDecContext_->renderQueue.push(*(source + i)); } #ifdef DEBUG_DECODE if (audioOutputFile_.is_open()) { - audioOutputFile_.write((const char*)OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)), + audioOutputFile_.write( + (const char *)OH_AVBuffer_GetAddr(reinterpret_cast(bufferInfo.buffer)), bufferInfo.attr.size); } #endif @@ -432,31 +351,15 @@ void Player::AudioDecOutputThread() int32_t ret = audioDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); - - // SAMPLE_S16LE 2 bytes per frame - // if set speed, cnt / speed - writtenSampleCnt += (bufferInfo.attr.size / sampleInfo_.audioChannelCount / BYTES_PER_SAMPLE_2); - AVCODEC_SAMPLE_LOGI("writtenSampleCnt_: %ld, bufferInfo.attr.size: %i, sampleInfo_.audioChannelCount: %i", - writtenSampleCnt, bufferInfo.attr.size, sampleInfo_.audioChannelCount); - audioBufferPts = bufferInfo.attr.pts; std::unique_lock lockRender(audioDecContext_->renderMutex); - audioDecContext_->renderCond.wait_for(lockRender, 20ms, - [this, bufferInfo]() { - return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; - }); + audioDecContext_->renderCond.wait_for(lockRender, 20ms, [this, bufferInfo]() { + return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; + }); } AVCODEC_SAMPLE_LOGI("Out buffer end"); std::unique_lock lock(doneMutex); isAudioDone = true; lock.unlock(); - doneCond_.notify_all(); StartRelease(); -} - -int64_t Player::GetCurrentTime() -{ - auto now = std::chrono::steady_clock::now(); - auto now_ns = std::chrono::time_point_cast(now); - return now_ns.time_since_epoch().count(); -} +} \ 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 4d89627..b8f17c6 100644 --- a/entry/src/main/cpp/sample/player/Player.h +++ b/entry/src/main/cpp/sample/player/Player.h @@ -1,8 +1,5 @@ /* - * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. - */ -/* - * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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 @@ -28,20 +25,19 @@ #include #include #include -#include "video_decoder.h" -#include "audio_decoder.h" +#include "VideoDecoder.h" +#include "AudioDecoder.h" #include "multimedia/player_framework/native_avbuffer.h" -#include "demuxer.h" -#include "sample_info.h" -#include "plugin_manager.h" +#include "Demuxer.h" +#include "SampleInfo.h" +#include "PluginManager.h" class Player { public: Player(){}; ~Player(); - - static Player& GetInstance() - { + + static Player &GetInstance() { static Player player; return player; } @@ -59,38 +55,31 @@ private: void ReleaseThread(); int32_t CreateAudioDecoder(); int32_t CreateVideoDecoder(); - int64_t GetCurrentTime(); 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 }; - std::atomic isAudioDone { false }; - std::atomic isVideoDone { false }; + std::mutex doneMutex; + std::atomic isStarted_{false}; + std::atomic isReleased_{false}; + std::atomic isAudioDone{true}; + std::atomic isVideoDone{false}; std::unique_ptr videoDecInputThread_ = nullptr; std::unique_ptr videoDecOutputThread_ = nullptr; std::unique_ptr audioDecInputThread_ = nullptr; std::unique_ptr audioDecOutputThread_ = nullptr; std::condition_variable doneCond_; - std::mutex doneMutex; SampleInfo sampleInfo_; CodecUserData *videoDecContext_ = nullptr; CodecUserData *audioDecContext_ = nullptr; - OH_AudioStreamBuilder* builder_ = nullptr; - OH_AudioRenderer* audioRenderer_ = nullptr; - - int64_t nowTimeStamp = 0; - int64_t audioTimeStamp = 0; - int64_t writtenSampleCnt = 0; - int64_t audioBufferPts = 0; + OH_AudioStreamBuilder *builder_ = nullptr; + OH_AudioRenderer *audioRenderer_ = nullptr; #ifdef DEBUG_DECODE std::ofstream audioOutputFile_; // for debug #endif - static constexpr int64_t MICROSECOND_TO_S = 1000000; - static constexpr int64_t NANO_TO_S = 1000000000; + static constexpr int64_t MICROSECOND = 1000000; }; #endif // VIDEO_CODEC_PLAYER_H \ No newline at end of file -- Gitee From c0ac89ab5297b1b36afd6c3ff83606d0d66d2d38 Mon Sep 17 00:00:00 2001 From: ziyugao Date: Mon, 6 Jan 2025 20:21:37 +0800 Subject: [PATCH 14/18] add bugfix Signed-off-by: ziyugao --- entry/src/main/cpp/sample/player/Player.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index f87a84d..4dd1805 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -23,6 +23,7 @@ namespace { constexpr int BALANCE_VALUE = 5; +constexpr int SAMPLE_PER_FRAME = 1024; using namespace std::chrono_literals; } // namespace @@ -319,6 +320,7 @@ void Player::AudioDecInputThread() { void Player::AudioDecOutputThread() { isAudioDone = false; + int32_t timePerFrame = 1000 * SAMPLE_PER_FRAME / sampleInfo_.audioSampleRate; while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(audioDecContext_->outputMutex); @@ -351,9 +353,10 @@ void Player::AudioDecOutputThread() { int32_t ret = audioDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); - std::unique_lock lockRender(audioDecContext_->renderMutex); - audioDecContext_->renderCond.wait_for(lockRender, 20ms, [this, bufferInfo]() { + + std::chrono::duration durationInMs(timePerFrame); //trans into chrono::duration + audioDecContext_->renderCond.wait_for(lockRender, durationInMs, [this, bufferInfo]() { return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; }); } -- Gitee From 9e83ea1f279609d9e77f93980fc911efbca957cb Mon Sep 17 00:00:00 2001 From: ziyugao Date: Tue, 7 Jan 2025 11:29:29 +0800 Subject: [PATCH 15/18] add bugfix Signed-off-by: ziyugao --- entry/src/main/ets/pages/Index.ets | 9 --------- 1 file changed, 9 deletions(-) diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index a1ba7aa..11fe591 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -285,15 +285,6 @@ struct Player { Button($r('app.string.record')) .onClick(() => { this.isShow = true; - atManager.requestPermissionsFromUser(context, ['ohos.permission.MICROPHONE', 'ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA']).then((data) => { - console.info('data: ' + JSON.stringify(data)); - console.info('result : ' + data.authResults[0]); - if (data.authResults[0] !== 0) { - return; - } - }).catch((err: BusinessError) => { - console.error('data:' + JSON.stringify(err)); - }) }) .bindSheet($$this.isShow, this.Authorized, { height: 210, -- Gitee From 88a367f7bab73a3569614b3d4a490c467279f4f5 Mon Sep 17 00:00:00 2001 From: ziyugao Date: Tue, 7 Jan 2025 16:10:41 +0800 Subject: [PATCH 16/18] add bugfix Signed-off-by: ziyugao --- .vscode/settings.json | 64 ++++++++++++++++++++ entry/src/main/cpp/common/SampleCallback.cpp | 5 +- entry/src/main/cpp/sample/player/Player.cpp | 10 ++- entry/src/main/cpp/sample/player/Player.h | 1 + 4 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..101ff1e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,64 @@ +{ + "files.associations": { + "algorithm": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "deque": "cpp", + "exception": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "span": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocinfo": "cpp", + "xlocnum": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xutility": "cpp" + } +} \ No newline at end of file diff --git a/entry/src/main/cpp/common/SampleCallback.cpp b/entry/src/main/cpp/common/SampleCallback.cpp index a47b6ae..a6db8c2 100644 --- a/entry/src/main/cpp/common/SampleCallback.cpp +++ b/entry/src/main/cpp/common/SampleCallback.cpp @@ -18,17 +18,18 @@ namespace { constexpr int LIMIT_LOGD_FREQUENCY = 50; +constexpr int BALANCE_VALUE = 2; } // Custom write data function int32_t SampleCallback::OnRenderWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length) { (void)renderer; - (void)length; CodecUserData *codecUserData = static_cast(userData); // Write the data to be played to the buffer by length uint8_t *dest = (uint8_t *)buffer; size_t index = 0; + codecUserData->renderFrameBytes = length; std::unique_lock lock(codecUserData->outputMutex); // Retrieve the length of the data to be played from the queue while (!codecUserData->renderQueue.empty() && index < length) { @@ -39,7 +40,7 @@ int32_t SampleCallback::OnRenderWriteData(OH_AudioRenderer *renderer, void *user "renderReadSize: %{public}u", length, codecUserData->outputFrameCount, (unsigned int)codecUserData->renderQueue.size(), (unsigned int)index); - if (codecUserData->renderQueue.size() < length) { + if (codecUserData->renderQueue.size() < BALANCE_VALUE * codecUserData->renderFrameBytes) { codecUserData->renderCond.notify_all(); } return 0; diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index 4dd1805..cf82863 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -22,8 +22,7 @@ #define LOG_TAG "player" namespace { -constexpr int BALANCE_VALUE = 5; -constexpr int SAMPLE_PER_FRAME = 1024; +constexpr int BALANCE_VALUE = 2; using namespace std::chrono_literals; } // namespace @@ -320,7 +319,7 @@ void Player::AudioDecInputThread() { void Player::AudioDecOutputThread() { isAudioDone = false; - int32_t timePerFrame = 1000 * SAMPLE_PER_FRAME / sampleInfo_.audioSampleRate; + while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(audioDecContext_->outputMutex); @@ -355,9 +354,8 @@ void Player::AudioDecOutputThread() { CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); std::unique_lock lockRender(audioDecContext_->renderMutex); - std::chrono::duration durationInMs(timePerFrame); //trans into chrono::duration - audioDecContext_->renderCond.wait_for(lockRender, durationInMs, [this, bufferInfo]() { - return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; + audioDecContext_->renderCond.wait_for(lockRender, 1s, [this, bufferInfo]() { + return audioDecContext_->renderQueue.size() < BALANCE_VALUE * audioDecContext_->renderFrameBytes; }); } AVCODEC_SAMPLE_LOGI("Out buffer end"); diff --git a/entry/src/main/cpp/sample/player/Player.h b/entry/src/main/cpp/sample/player/Player.h index b8f17c6..b7f23cb 100644 --- a/entry/src/main/cpp/sample/player/Player.h +++ b/entry/src/main/cpp/sample/player/Player.h @@ -80,6 +80,7 @@ private: std::ofstream audioOutputFile_; // for debug #endif static constexpr int64_t MICROSECOND = 1000000; + uint32_t renderFrameBytes = 0; }; #endif // VIDEO_CODEC_PLAYER_H \ No newline at end of file -- Gitee From 5bdb34478a049baba3ae831b51e4f99abcbadda4 Mon Sep 17 00:00:00 2001 From: ziyugao Date: Tue, 7 Jan 2025 16:58:27 +0800 Subject: [PATCH 17/18] add bugfix Signed-off-by: ziyugao --- entry/src/main/cpp/common/SampleInfo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/entry/src/main/cpp/common/SampleInfo.h b/entry/src/main/cpp/common/SampleInfo.h index 4c2639a..2b15ea8 100644 --- a/entry/src/main/cpp/common/SampleInfo.h +++ b/entry/src/main/cpp/common/SampleInfo.h @@ -103,6 +103,7 @@ public: std::queue outputBufferInfoQueue; std::queue renderQueue; + uint32_t renderFrameBytes = 0; }; #endif // AVCODEC_SAMPLE_INFO_H \ No newline at end of file -- Gitee From 7edcb8a8ec20d680720675f93f5876aaa4029de7 Mon Sep 17 00:00:00 2001 From: ziyugao Date: Wed, 8 Jan 2025 15:52:53 +0800 Subject: [PATCH 18/18] add bugfix Signed-off-by: ziyugao --- entry/src/main/cpp/sample/recorder/Recorder.cpp | 5 ++--- entry/src/main/cpp/sample/recorder/Recorder.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/entry/src/main/cpp/sample/recorder/Recorder.cpp b/entry/src/main/cpp/sample/recorder/Recorder.cpp index 9b70ded..7e2b146 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.cpp +++ b/entry/src/main/cpp/sample/recorder/Recorder.cpp @@ -17,7 +17,6 @@ #include #include "AVCodecSampleLog.h" #include "dfx/error/AVCodecSampleError.h" -#include "audiorecord.h" #undef LOG_TAG #define LOG_TAG "recorder" @@ -64,7 +63,7 @@ int32_t Recorder::Init(SampleInfo &sampleInfo) { int32_t Recorder::Start() { std::lock_guard lock(mutex_); - audioRecord_->AudioCapturerStart(muxer_); + CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(encContext_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, @@ -82,7 +81,7 @@ int32_t Recorder::Start() { StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } - + audioRecord_->AudioCapturerStart(muxer_); AVCODEC_SAMPLE_LOGI("Succeed"); return AVCODEC_SAMPLE_ERR_OK; } diff --git a/entry/src/main/cpp/sample/recorder/Recorder.h b/entry/src/main/cpp/sample/recorder/Recorder.h index 4fc69df..fac2ad3 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.h +++ b/entry/src/main/cpp/sample/recorder/Recorder.h @@ -25,7 +25,7 @@ #include "VideoEncoder.h" #include "Muxer.h" #include "SampleInfo.h" -#include "audiorecord.h" +#include "AudioRecord.h" class Recorder { public: -- Gitee