1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "avcodec_audio_flac_encoder_demo.h"
17 #include <iostream>
18 #include <unistd.h>
19 #include "securec.h"
20 #include "avcodec_common.h"
21 #include "avcodec_errors.h"
22 #include "media_description.h"
23 #include "native_avformat.h"
24 #include "demo_log.h"
25 #include "avcodec_codec_name.h"
26 #include "ffmpeg_converter.h"
27 
28 using namespace OHOS;
29 using namespace OHOS::MediaAVCodec;
30 using namespace OHOS::MediaAVCodec::AudioFlacDemo;
31 using namespace std;
32 namespace {
33 constexpr uint32_t CHANNEL_COUNT = 2;
34 constexpr uint32_t SAMPLE_RATE = 44100;
35 constexpr uint32_t BITS_RATE = 261000;
36 constexpr uint32_t BITS_PER_CODED_SAMPLE = AudioSampleFormat::SAMPLE_S16LE;
37 constexpr uint32_t FRAME_DURATION_US = 33000;
38 constexpr uint32_t CHANNEL_LAYOUT = AudioChannelLayout::STEREO;
39 constexpr int32_t SAMPLE_FORMAT = AudioSampleFormat::SAMPLE_S16LE;
40 constexpr int32_t COMPLIANCE_LEVEL = 0;
41 constexpr int32_t DEFAULT_FRAME_BYTES = 1152;
42 static std::map<uint32_t, uint32_t> FRAME_BYTES_MAP = {{8000, 576}, {16000, 1152}, {22050, 2304}, {24000, 2304},
43                                                        {32000, 2304}, {44100, 4608}, {48000, 4608}, {88200, 8192},
44                                                        {96000, 8192}};
45 
46 constexpr string_view INPUT_FILE_PATH = "/data/test/media/flac_2c_44100hz_261k.pcm";
47 constexpr string_view OUTPUT_FILE_PATH = "/data/test/media/flac_encoder_test.flac";
48 } // namespace
49 
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)50 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
51 {
52     (void)codec;
53     (void)errorCode;
54     (void)userData;
55     cout << "Error received, errorCode:" << errorCode << endl;
56 }
57 
OnOutputFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)58 static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
59 {
60     (void)codec;
61     (void)format;
62     (void)userData;
63     cout << "OnOutputFormatChanged received" << endl;
64 }
65 
OnInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)66 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
67 {
68     (void)codec;
69     AEncSignal *signal = static_cast<AEncSignal *>(userData);
70     unique_lock<mutex> lock(signal->inMutex_);
71     signal->inQueue_.push(index);
72     signal->inBufferQueue_.push(data);
73     signal->inCond_.notify_all();
74 }
75 
OnOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)76 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
77                                     void *userData)
78 {
79     (void)codec;
80     AEncSignal *signal = static_cast<AEncSignal *>(userData);
81     unique_lock<mutex> lock(signal->outMutex_);
82     signal->outQueue_.push(index);
83     signal->outBufferQueue_.push(data);
84     if (attr) {
85         signal->attrQueue_.push(*attr);
86     } else {
87         cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl;
88     }
89     signal->outCond_.notify_all();
90 }
91 
RunCase()92 void AEncFlacDemo::RunCase()
93 {
94     DEMO_CHECK_AND_RETURN_LOG(CreateEnc() == AVCS_ERR_OK, "Fatal: CreateEnc fail");
95 
96     OH_AVFormat *format = OH_AVFormat_Create();
97     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), CHANNEL_COUNT);
98     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), SAMPLE_RATE);
99     OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_BITRATE.data(), BITS_RATE);
100     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_BITS_PER_CODED_SAMPLE.data(), BITS_PER_CODED_SAMPLE);
101     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), SAMPLE_FORMAT);
102     OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CHANNEL_LAYOUT);
103     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_COMPLIANCE_LEVEL.data(), COMPLIANCE_LEVEL);
104 
105     DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
106 
107     DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
108 
109     {
110         unique_lock<mutex> lock(signal_->startMutex_);
111         signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); });
112     }
113 
114     DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
115     DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
116 }
117 
AEncFlacDemo()118 AEncFlacDemo::AEncFlacDemo() : isRunning_(false), audioEnc_(nullptr), signal_(nullptr), frameCount_(0)
119 {
120     inputFile_ = std::make_unique<std::ifstream>(INPUT_FILE_PATH, std::ios::binary);
121     outputFile_ = std::make_unique<std::ofstream>(OUTPUT_FILE_PATH, std::ios::binary);
122 }
123 
~AEncFlacDemo()124 AEncFlacDemo::~AEncFlacDemo()
125 {
126     if (signal_) {
127         delete signal_;
128         signal_ = nullptr;
129     }
130 }
131 
CreateEnc()132 int32_t AEncFlacDemo::CreateEnc()
133 {
134     audioEnc_ = OH_AudioEncoder_CreateByName((AVCodecCodecName::AUDIO_ENCODER_FLAC_NAME).data());
135     DEMO_CHECK_AND_RETURN_RET_LOG(audioEnc_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
136 
137     signal_ = new AEncSignal();
138     DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
139 
140     cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
141     int32_t ret = OH_AudioEncoder_SetCallback(audioEnc_, cb_, signal_);
142     DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
143 
144     return AVCS_ERR_OK;
145 }
146 
Configure(OH_AVFormat * format)147 int32_t AEncFlacDemo::Configure(OH_AVFormat *format)
148 {
149     return OH_AudioEncoder_Configure(audioEnc_, format);
150 }
151 
Start()152 int32_t AEncFlacDemo::Start()
153 {
154     isRunning_.store(true);
155 
156     inputLoop_ = make_unique<thread>(&AEncFlacDemo::InputFunc, this);
157     DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
158 
159     outputLoop_ = make_unique<thread>(&AEncFlacDemo::OutputFunc, this);
160     DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
161 
162     return OH_AudioEncoder_Start(audioEnc_);
163 }
164 
Stop()165 int32_t AEncFlacDemo::Stop()
166 {
167     isRunning_.store(false);
168 
169     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
170         {
171             unique_lock<mutex> lock(signal_->inMutex_);
172             signal_->inCond_.notify_all();
173         }
174         inputLoop_->join();
175         inputLoop_ = nullptr;
176         while (!signal_->inQueue_.empty()) {
177             signal_->inQueue_.pop();
178         }
179         while (!signal_->inBufferQueue_.empty()) {
180             signal_->inBufferQueue_.pop();
181         }
182     }
183 
184     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
185         {
186             unique_lock<mutex> lock(signal_->outMutex_);
187             signal_->outCond_.notify_all();
188         }
189         outputLoop_->join();
190         outputLoop_ = nullptr;
191         while (!signal_->outQueue_.empty()) {
192             signal_->outQueue_.pop();
193         }
194         while (!signal_->attrQueue_.empty()) {
195             signal_->attrQueue_.pop();
196         }
197         while (!signal_->outBufferQueue_.empty()) {
198             signal_->outBufferQueue_.pop();
199         }
200     }
201 
202     return OH_AudioEncoder_Stop(audioEnc_);
203 }
204 
Flush()205 int32_t AEncFlacDemo::Flush()
206 {
207     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
208         {
209             unique_lock<mutex> lock(signal_->inMutex_);
210             signal_->inCond_.notify_all();
211         }
212         inputLoop_->join();
213         inputLoop_ = nullptr;
214         while (!signal_->inQueue_.empty()) {
215             signal_->inQueue_.pop();
216         }
217         while (!signal_->inBufferQueue_.empty()) {
218             signal_->inBufferQueue_.pop();
219         }
220         std::cout << "clear input buffer!\n";
221     }
222 
223     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
224         {
225             unique_lock<mutex> lock(signal_->outMutex_);
226             signal_->outCond_.notify_all();
227         }
228         outputLoop_->join();
229         outputLoop_ = nullptr;
230         while (!signal_->outQueue_.empty()) {
231             signal_->outQueue_.pop();
232         }
233         while (!signal_->attrQueue_.empty()) {
234             signal_->attrQueue_.pop();
235         }
236         while (!signal_->outBufferQueue_.empty()) {
237             signal_->outBufferQueue_.pop();
238         }
239         std::cout << "clear output buffer!\n";
240     }
241     return OH_AudioEncoder_Flush(audioEnc_);
242 }
243 
Reset()244 int32_t AEncFlacDemo::Reset()
245 {
246     return OH_AudioEncoder_Reset(audioEnc_);
247 }
248 
Release()249 int32_t AEncFlacDemo::Release()
250 {
251     return OH_AudioEncoder_Destroy(audioEnc_);
252 }
253 
HandleEOS(const uint32_t & index)254 void AEncFlacDemo::HandleEOS(const uint32_t &index)
255 {
256     OH_AVCodecBufferAttr info;
257     info.size = 0;
258     info.offset = 0;
259     info.pts = 0;
260     info.flags = AVCODEC_BUFFER_FLAGS_EOS;
261     OH_AudioEncoder_PushInputData(audioEnc_, index, info);
262     signal_->inQueue_.pop();
263     signal_->inBufferQueue_.pop();
264 }
265 
GetFrameBytes()266 static int32_t GetFrameBytes()
267 {
268     auto bitsPerSamples = (SAMPLE_FORMAT == AudioSampleFormat::SAMPLE_S16LE) ? 2 : 4;
269     auto iter = FRAME_BYTES_MAP.find(SAMPLE_RATE);
270     uint32_t frameSize = DEFAULT_FRAME_BYTES;
271     if (iter != FRAME_BYTES_MAP.end()) {
272         frameSize = iter->second;
273     }
274     int32_t frameBytes = CHANNEL_COUNT * bitsPerSamples * frameSize;
275     return frameBytes;
276 }
277 
InputFunc()278 void AEncFlacDemo::InputFunc()
279 {
280     auto frameBytes = GetFrameBytes();
281     DEMO_CHECK_AND_RETURN_LOG(inputFile_ != nullptr && inputFile_->is_open(), "Fatal: open file fail");
282     while (isRunning_.load()) {
283         unique_lock<mutex> lock(signal_->inMutex_);
284         signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); });
285         if (!isRunning_.load()) {
286             break;
287         }
288         uint32_t index = signal_->inQueue_.front();
289         auto buffer = signal_->inBufferQueue_.front();
290         DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
291         if (!inputFile_->eof()) {
292             inputFile_->read((char *)OH_AVMemory_GetAddr(buffer), frameBytes);
293         } else {
294             HandleEOS(index);
295             break;
296         }
297         DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
298         OH_AVCodecBufferAttr info;
299         info.size = frameBytes;
300         info.offset = 0;
301 
302         int32_t ret = AVCS_ERR_OK;
303         if (isFirstFrame_) {
304             info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
305             ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info);
306             isFirstFrame_ = false;
307         } else {
308             info.flags = AVCODEC_BUFFER_FLAGS_NONE;
309             ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info);
310         }
311 
312         timeStamp_ += FRAME_DURATION_US;
313         signal_->inQueue_.pop();
314         signal_->inBufferQueue_.pop();
315         frameCount_++;
316         if (ret != AVCS_ERR_OK) {
317             cout << "Fatal error, exit" << endl;
318             isRunning_ = false;
319             break;
320         }
321     }
322     inputFile_->close();
323 }
324 
OutputFunc()325 void AEncFlacDemo::OutputFunc()
326 {
327     DEMO_CHECK_AND_RETURN_LOG(outputFile_ != nullptr && outputFile_->is_open(), "Fatal: open output file fail");
328     while (isRunning_.load()) {
329         unique_lock<mutex> lock(signal_->outMutex_);
330         signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); });
331 
332         if (!isRunning_.load()) {
333             cout << "wait to stop, exit" << endl;
334             break;
335         }
336 
337         uint32_t index = signal_->outQueue_.front();
338 
339         OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
340         OH_AVMemory *data = signal_->outBufferQueue_.front();
341         if (data != nullptr) {
342             outputFile_->write(reinterpret_cast<char *>(OH_AVMemory_GetAddr(data)), attr.size);
343         }
344         if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS || attr.size == 0) {
345             cout << "encode eos" << endl;
346             isRunning_.store(false);
347             signal_->startCond_.notify_all();
348         }
349 
350         signal_->outBufferQueue_.pop();
351         signal_->attrQueue_.pop();
352         signal_->outQueue_.pop();
353         if (OH_AudioEncoder_FreeOutputData(audioEnc_, index) != AV_ERR_OK) {
354             cout << "Fatal: FreeOutputData fail" << endl;
355             break;
356         }
357     }
358     outputFile_->close();
359 }
360