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_avbuffer_g711mu_encoder_demo.h"
17 #include <unistd.h>
18 #include <chrono>
19 #include <iostream>
20 #include "avcodec_audio_common.h"
21 #include "avcodec_codec_name.h"
22 #include "avcodec_common.h"
23 #include "avcodec_errors.h"
24 #include "demo_log.h"
25 #include "media_description.h"
26 #include "native_avbuffer.h"
27 #include "native_avcodec_base.h"
28 #include "native_avformat.h"
29 #include "native_avmemory.h"
30 #include "securec.h"
31 
32 using namespace OHOS;
33 using namespace OHOS::MediaAVCodec;
34 using namespace OHOS::MediaAVCodec::AudioAvbufferG711muDemo;
35 using namespace std;
36 namespace {
37 constexpr uint32_t CHANNEL_COUNT = 1;
38 constexpr uint32_t SAMPLE_RATE = 8000;
39 constexpr uint32_t FRAME_DURATION_US = 33000;
40 constexpr int32_t SAMPLE_FORMAT = AudioSampleFormat::SAMPLE_S16LE;
41 constexpr int32_t INPUT_FRAME_BYTES = 320;  // 20ms
42 
43 constexpr string_view INPUT_FILE_PATH = "/data/test/media/g711mu_8kHz_10s.pcm";
44 constexpr string_view OUTPUT_FILE_PATH = "/data/test/media/g711mu_8kHz_10s_afterEncode.raw";
45 }  // namespace
46 
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)47 static void OnError(OH_AVCodec* codec, int32_t errorCode, void* userData)
48 {
49     (void)codec;
50     (void)errorCode;
51     (void)userData;
52     cout << "Error received, errorCode:" << errorCode << endl;
53 }
54 
OnOutputFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)55 static void OnOutputFormatChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData)
56 {
57     (void)codec;
58     (void)format;
59     (void)userData;
60     cout << "OnOutputFormatChanged received" << endl;
61 }
62 
OnInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)63 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
64 {
65     (void)codec;
66     AEncSignal* signal = static_cast<AEncSignal*>(userData);
67     unique_lock<mutex> lock(signal->inMutex_);
68     signal->inQueue_.push(index);
69     signal->inBufferQueue_.push(buffer);
70     signal->inCond_.notify_all();
71 }
72 
OnOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVBuffer * buffer,void * userData)73 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData)
74 {
75     (void)codec;
76     AEncSignal* signal = static_cast<AEncSignal*>(userData);
77     unique_lock<mutex> lock(signal->outMutex_);
78     signal->outQueue_.push(index);
79     signal->outBufferQueue_.push(buffer);
80     if (buffer) {
81         cout << "OnOutputBufferAvailable received, index:" << index << ", size:" << buffer->buffer_->memory_->GetSize()
82              << ", flags:" << buffer->buffer_->flag_ << ", pts: " << buffer->buffer_->pts_ << endl;
83     } else {
84         cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl;
85     }
86     signal->outCond_.notify_all();
87 }
88 
RunCase()89 void AEncAvbufferG711muDemo::RunCase()
90 {
91     std::cout << "G711 RunCase enter" << std::endl;
92     DEMO_CHECK_AND_RETURN_LOG(CreateEnc() == AVCS_ERR_OK, "Fatal: CreateEnc fail");
93 
94     OH_AVFormat* format = OH_AVFormat_Create();
95     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), CHANNEL_COUNT);
96     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), SAMPLE_RATE);
97     OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), SAMPLE_FORMAT);
98 
99     DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
100 
101     auto fmt = OH_AudioCodec_GetOutputDescription(audioEnc_);
102     int channels;
103     int sampleRate;
104     int64_t bitRate;
105     int sampleFormat;
106     int64_t channelLayout;
107     int frameSize;
108     OH_AVFormat_GetIntValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), &channels);
109     OH_AVFormat_GetIntValue(fmt, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), &sampleRate);
110     OH_AVFormat_GetLongValue(fmt, MediaDescriptionKey::MD_KEY_BITRATE.data(), &bitRate);
111     OH_AVFormat_GetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT.data(), &sampleFormat);
112     OH_AVFormat_GetLongValue(fmt, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), &channelLayout);
113     OH_AVFormat_GetIntValue(fmt, MediaDescriptionKey::MD_KEY_AUDIO_SAMPLES_PER_FRAME.data(), &frameSize);
114     std::cout << "GetOutputDescription "
115               << "channels: " << channels
116               << ", sampleRate: " << sampleRate
117               << ", bitRate: " << bitRate
118               << ", sampleFormat: " << sampleFormat
119               << ", channelLayout: " << channelLayout
120               << ", frameSize: " << frameSize << std::endl;
121 
122     DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
123     auto start = chrono::steady_clock::now();
124 
125     {
126         unique_lock<mutex> lock(signal_->startMutex_);
127         signal_->startCond_.wait(lock, [this]() { return (!(isRunning_.load())); });
128     }
129 
130     auto end = chrono::steady_clock::now();
131     std::cout << "Encode finished, time = " << std::chrono::duration_cast<chrono::milliseconds>(end - start).count()
132               << " ms" << std::endl;
133     DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
134     DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
135     OH_AVFormat_Destroy(format);
136 }
137 
GetFileSize(const std::string & filePath)138 int32_t AEncAvbufferG711muDemo::GetFileSize(const std::string& filePath)
139 {
140     std::ifstream file(filePath, std::ios::binary | std::ios::ate);
141     if (!file) {
142         std::cerr << "Failed to open file: " << filePath << std::endl;
143         return -1;
144     }
145 
146     std::streampos fileSize = file.tellg();  // 获取文件大小
147     file.close();
148 
149     return (int32_t)fileSize;
150 }
151 
AEncAvbufferG711muDemo()152 AEncAvbufferG711muDemo::AEncAvbufferG711muDemo()
153     : isRunning_(false), audioEnc_(nullptr), signal_(nullptr), frameCount_(0)
154 {
155     fileSize_ = GetFileSize(INPUT_FILE_PATH.data());
156     inputFile_ = std::make_unique<std::ifstream>(INPUT_FILE_PATH, std::ios::binary);
157     outputFile_ = std::make_unique<std::ofstream>(OUTPUT_FILE_PATH, std::ios::binary);
158 }
159 
~AEncAvbufferG711muDemo()160 AEncAvbufferG711muDemo::~AEncAvbufferG711muDemo()
161 {
162     if (signal_) {
163         delete signal_;
164         signal_ = nullptr;
165     }
166 }
167 
CreateEnc()168 int32_t AEncAvbufferG711muDemo::CreateEnc()
169 {
170     audioEnc_ = OH_AudioCodec_CreateByName((AVCodecCodecName::AUDIO_ENCODER_G711MU_NAME).data());
171     DEMO_CHECK_AND_RETURN_RET_LOG(audioEnc_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
172 
173     signal_ = new AEncSignal();
174     DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
175 
176     cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
177     int32_t ret = OH_AudioCodec_RegisterCallback(audioEnc_, cb_, signal_);
178     DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
179 
180     return AVCS_ERR_OK;
181 }
182 
Configure(OH_AVFormat * format)183 int32_t AEncAvbufferG711muDemo::Configure(OH_AVFormat *format)
184 {
185     return OH_AudioCodec_Configure(audioEnc_, format);
186 }
187 
Start()188 int32_t AEncAvbufferG711muDemo::Start()
189 {
190     isRunning_.store(true);
191 
192     inputLoop_ = make_unique<thread>(&AEncAvbufferG711muDemo::InputFunc, this);
193     DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
194 
195     outputLoop_ = make_unique<thread>(&AEncAvbufferG711muDemo::OutputFunc, this);
196     DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
197 
198     return OH_AudioCodec_Start(audioEnc_);
199 }
200 
Stop()201 int32_t AEncAvbufferG711muDemo::Stop()
202 {
203     isRunning_.store(false);
204     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
205         {
206             unique_lock<mutex> lock(signal_->inMutex_);
207             signal_->inCond_.notify_all();
208         }
209         inputLoop_->join();
210         inputLoop_ = nullptr;
211         while (!signal_->inQueue_.empty()) {
212             signal_->inQueue_.pop();
213         }
214         while (!signal_->inBufferQueue_.empty()) {
215             signal_->inBufferQueue_.pop();
216         }
217     }
218 
219     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
220         {
221             unique_lock<mutex> lock(signal_->outMutex_);
222             signal_->outCond_.notify_all();
223         }
224         outputLoop_->join();
225         outputLoop_ = nullptr;
226         while (!signal_->outQueue_.empty()) {
227             signal_->outQueue_.pop();
228         }
229         while (!signal_->outBufferQueue_.empty()) {
230             signal_->outBufferQueue_.pop();
231         }
232     }
233 
234     return OH_AudioCodec_Stop(audioEnc_);
235 }
236 
Flush()237 int32_t AEncAvbufferG711muDemo::Flush()
238 {
239     isRunning_.store(false);
240     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
241         {
242             unique_lock<mutex> lock(signal_->inMutex_);
243             signal_->inCond_.notify_all();
244         }
245         inputLoop_->join();
246         inputLoop_ = nullptr;
247         while (!signal_->inQueue_.empty()) {
248             signal_->inQueue_.pop();
249         }
250         while (!signal_->inBufferQueue_.empty()) {
251             signal_->inBufferQueue_.pop();
252         }
253         std::cout << "clear input buffer!\n";
254     }
255 
256     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
257         {
258             unique_lock<mutex> lock(signal_->outMutex_);
259             signal_->outCond_.notify_all();
260         }
261         outputLoop_->join();
262         outputLoop_ = nullptr;
263         while (!signal_->outQueue_.empty()) {
264             signal_->outQueue_.pop();
265         }
266         while (!signal_->outBufferQueue_.empty()) {
267             signal_->outBufferQueue_.pop();
268         }
269         std::cout << "clear output buffer!\n";
270     }
271     return OH_AudioCodec_Flush(audioEnc_);
272 }
273 
Reset()274 int32_t AEncAvbufferG711muDemo::Reset()
275 {
276     return OH_AudioCodec_Reset(audioEnc_);
277 }
278 
Release()279 int32_t AEncAvbufferG711muDemo::Release()
280 {
281     return OH_AudioCodec_Destroy(audioEnc_);
282 }
283 
HandleEOS(const uint32_t & index)284 void AEncAvbufferG711muDemo::HandleEOS(const uint32_t& index)
285 {
286     OH_AudioCodec_PushInputBuffer(audioEnc_, index);
287     std::cout << "end buffer\n";
288     signal_->inQueue_.pop();
289     signal_->inBufferQueue_.pop();
290 }
291 
InputFunc()292 void AEncAvbufferG711muDemo::InputFunc()
293 {
294     DEMO_CHECK_AND_RETURN_LOG(inputFile_ != nullptr && inputFile_->is_open(), "Fatal: open file fail");
295     while (isRunning_.load()) {
296         if (!isRunning_.load()) {
297             break;
298         }
299         unique_lock<mutex> lock(signal_->inMutex_);
300         signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); });
301         if (!isRunning_.load()) {
302             break;
303         }
304         uint32_t index = signal_->inQueue_.front();
305         auto buffer = signal_->inBufferQueue_.front();
306         DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
307         if (!inputFile_->eof()) {
308             inputFile_->read((char*)OH_AVBuffer_GetAddr(buffer), INPUT_FRAME_BYTES);
309             buffer->buffer_->memory_->SetSize(INPUT_FRAME_BYTES);
310             if (inputFile_->gcount() == 0) {
311                 buffer->buffer_->memory_->SetSize(1);
312                 buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_EOS;
313                 HandleEOS(index);
314                 break;
315             }
316         } else {
317             buffer->buffer_->memory_->SetSize(1);
318             buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_EOS;
319             HandleEOS(index);
320             break;
321         }
322         DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
323 
324         int32_t ret = AVCS_ERR_OK;
325         if (isFirstFrame_) {
326             buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
327             ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index);
328             isFirstFrame_ = false;
329         } else {
330             buffer->buffer_->flag_ = AVCODEC_BUFFER_FLAGS_NONE;
331             ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index);
332         }
333         timeStamp_ += FRAME_DURATION_US;
334         signal_->inQueue_.pop();
335         signal_->inBufferQueue_.pop();
336         frameCount_++;
337         if (ret != AVCS_ERR_OK) {
338             cout << "Fatal error, exit" << endl;
339             break;
340         }
341     }
342     inputFile_->close();
343 }
344 
OutputFunc()345 void AEncAvbufferG711muDemo::OutputFunc()
346 {
347     DEMO_CHECK_AND_RETURN_LOG(outputFile_ != nullptr && outputFile_->is_open(), "Fatal: open output file fail");
348     while (isRunning_.load()) {
349         if (!isRunning_.load()) {
350             cout << "stop, exit" << endl;
351             break;
352         }
353 
354         unique_lock<mutex> lock(signal_->outMutex_);
355         signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); });
356 
357         if (!isRunning_.load()) {
358             cout << "wait to stop, exit" << endl;
359             break;
360         }
361 
362         uint32_t index = signal_->outQueue_.front();
363         OH_AVBuffer* avBuffer = signal_->outBufferQueue_.front();
364         if (avBuffer == nullptr) {
365             cout << "OutputFunc OH_AVBuffer is nullptr" << endl;
366             continue;
367         }
368         if (avBuffer != nullptr) {
369             cout << "OutputFunc write index:" << index << ", size:" << avBuffer->buffer_->memory_->GetSize() << endl;
370             outputFile_->write(reinterpret_cast<char*>(OH_AVBuffer_GetAddr(avBuffer)),
371                 avBuffer->buffer_->memory_->GetSize());
372         }
373         if (avBuffer != nullptr && (avBuffer->buffer_->flag_ == AVCODEC_BUFFER_FLAGS_EOS ||
374             avBuffer->buffer_->memory_->GetSize() == 0)) {
375             cout << "encode eos" << endl;
376             isRunning_.store(false);
377             signal_->startCond_.notify_all();
378         }
379 
380         signal_->outBufferQueue_.pop();
381         signal_->outQueue_.pop();
382         if (OH_AudioCodec_FreeOutputBuffer(audioEnc_, index) != AV_ERR_OK) {
383             cout << "Fatal: FreeOutputData fail" << endl;
384             break;
385         }
386         if (avBuffer->buffer_->flag_ == AVCODEC_BUFFER_FLAGS_EOS) {
387             cout << "G711mu encode eos" << endl;
388             isRunning_.store(false);
389             signal_->startCond_.notify_all();
390         }
391     }
392     outputFile_->close();
393 }