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_encoder_inner_demo.h"
17 #include <iostream>
18 #include <unistd.h>
19 #include "avcodec_codec_name.h"
20 #include "avcodec_common.h"
21 #include "avcodec_errors.h"
22 #include "demo_log.h"
23 #include "media_description.h"
24 #include "securec.h"
25 #include "ffmpeg_converter.h"
26 
27 extern "C" {
28 #include "libavcodec/avcodec.h"
29 #include "libavformat/avformat.h"
30 #include "libavutil/imgutils.h"
31 #include "libavutil/samplefmt.h"
32 #include "libavutil/timestamp.h"
33 }
34 
35 using namespace OHOS;
36 using namespace OHOS::MediaAVCodec;
37 using namespace OHOS::MediaAVCodec::InnerAudioDemo;
38 using namespace std;
39 namespace {
40 constexpr uint32_t CHANNEL_COUNT = 2;
41 constexpr uint32_t SAMPLE_RATE = 44100;
42 constexpr uint32_t BITS_RATE = 199000; // for aac encoding
43 constexpr uint32_t BITS_PER_CODED_SAMPLE = AudioSampleFormat::SAMPLE_F32P;
44 constexpr uint32_t DEFAULT_SAMPLE_FORMAT = AudioSampleFormat::SAMPLE_F32P;
45 constexpr uint32_t DEFAULT_CHANNEL_LAYOUT_COUNT = AudioChannelLayout::STEREO;
46 constexpr uint32_t DEFAULT_SLEEP_TIME = 30;
47 } // namespace
48 
RunCase()49 void AEnInnerDemo::RunCase()
50 {
51     DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
52 
53     Format format;
54     format.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, CHANNEL_COUNT);
55     format.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, SAMPLE_RATE);
56     format.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, BITS_RATE);
57     format.PutIntValue(MediaDescriptionKey::MD_KEY_BITS_PER_CODED_SAMPLE, BITS_PER_CODED_SAMPLE);
58     format.PutIntValue(MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT, DEFAULT_SAMPLE_FORMAT);
59     format.PutLongValue(MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT, DEFAULT_CHANNEL_LAYOUT_COUNT);
60     DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
61 
62     DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
63     sleep(DEFAULT_SLEEP_TIME);
64     DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
65     DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
66 }
67 
CreateDec()68 int32_t AEnInnerDemo::CreateDec()
69 {
70     audioEn_ = AudioEncoderFactory::CreateByName((AVCodecCodecName::AUDIO_ENCODER_AAC_NAME).data());
71     DEMO_CHECK_AND_RETURN_RET_LOG(audioEn_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
72 
73     signal_ = make_shared<AEnSignal>();
74 
75     cb_ = make_unique<AEnDemoCallback>(signal_);
76     DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
77     DEMO_CHECK_AND_RETURN_RET_LOG(audioEn_->SetCallback(cb_) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN,
78                                   "Fatal: SetCallback fail");
79 
80     return AVCS_ERR_OK;
81 }
82 
Configure(const Format & format)83 int32_t AEnInnerDemo::Configure(const Format &format)
84 {
85     return audioEn_->Configure(format);
86 }
87 
Start()88 int32_t AEnInnerDemo::Start()
89 {
90     isRunning_.store(true);
91 
92     inputLoop_ = make_unique<thread>(&AEnInnerDemo::InputFunc, this);
93     DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
94 
95     outputLoop_ = make_unique<thread>(&AEnInnerDemo::OutputFunc, this);
96     DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
97 
98     return audioEn_->Start();
99 }
100 
Stop()101 int32_t AEnInnerDemo::Stop()
102 {
103     isRunning_.store(false);
104 
105     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
106         {
107             unique_lock<mutex> lock(signal_->inMutex_);
108             signal_->inQueue_.push(0);
109             signal_->inCond_.notify_all();
110         }
111         inputLoop_->join();
112         inputLoop_.reset();
113     }
114 
115     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
116         {
117             unique_lock<mutex> lock(signal_->outMutex_);
118             signal_->outQueue_.push(0);
119             signal_->outCond_.notify_all();
120         }
121         outputLoop_->join();
122         outputLoop_.reset();
123     }
124 
125     return audioEn_->Stop();
126 }
127 
Flush()128 int32_t AEnInnerDemo::Flush()
129 {
130     return audioEn_->Flush();
131 }
132 
Reset()133 int32_t AEnInnerDemo::Reset()
134 {
135     return audioEn_->Reset();
136 }
137 
Release()138 int32_t AEnInnerDemo::Release()
139 {
140     return audioEn_->Release();
141 }
142 
InputFunc()143 void AEnInnerDemo::InputFunc()
144 {
145     const char *filePath = "/data/test/media/aac_2c_44100hz_199k.pcm";
146     int frameBytes = 2 * 1024 * 4;
147     std::ifstream inputFile(filePath, std::ios::binary);
148     if (!inputFile.is_open()) {
149         std::cout << "open file " << filePath << " failed" << std::endl;
150         return;
151     }
152 
153     while (isRunning_.load()) {
154         std::unique_lock<std::mutex> lock(signal_->inMutex_);
155         signal_->inCond_.wait(lock, [this]() { return signal_->inQueue_.size() > 0; });
156         if (!isRunning_.load()) {
157             break;
158         }
159 
160         uint32_t index = signal_->inQueue_.front();
161         std::shared_ptr<AVSharedMemory> buffer = signal_->inBufferQueue_.front();
162         if (buffer == nullptr) {
163             isRunning_.store(false);
164             std::cout << "buffer is null:" << index << "\n";
165             break;
166         }
167         inputFile.read(reinterpret_cast<char *>(buffer->GetBase()), frameBytes);
168         int readBytes = inputFile.gcount();
169         AVCodecBufferInfo attr;
170         AVCodecBufferFlag flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE;
171         if (inputFile.eof() || readBytes == 0) {
172             flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS;
173             (void)audioEn_->QueueInputBuffer(index, attr, flag);
174             signal_->inQueue_.pop();
175             signal_->inBufferQueue_.pop();
176             std::cout << "end buffer\n";
177             break;
178         }
179         auto result = audioEn_->QueueInputBuffer(index, attr, flag);
180         signal_->inQueue_.pop();
181         signal_->inBufferQueue_.pop();
182         if (result != AVCS_ERR_OK) {
183             std::cout << "QueueInputBuffer error:\n";
184             isRunning_ = false;
185             break;
186         }
187     }
188 }
189 
OutputFunc()190 void AEnInnerDemo::OutputFunc()
191 {
192     std::ofstream outputFile("/data/test/media/encode.aac", std::ios::binary);
193     while (isRunning_.load()) {
194         unique_lock<mutex> lock(signal_->outMutex_);
195         signal_->outCond_.wait(lock, [this]() { return signal_->outQueue_.size() > 0; });
196 
197         if (!isRunning_.load()) {
198             break;
199         }
200 
201         uint32_t index = signal_->outQueue_.front();
202         auto buffer = signal_->outBufferQueue_.front();
203         if (buffer == nullptr) {
204             cout << "get output buffer failed" << endl;
205             isRunning_.store(false);
206             break;
207         }
208         auto attr = signal_->sizeQueue_.front();
209         outputFile.write(reinterpret_cast<char *>(buffer->GetBase()), attr.size);
210         cout << "output write size = " << attr.size << endl;
211         if (audioEn_->ReleaseOutputBuffer(index) != AVCS_ERR_OK) {
212             cout << "Fatal: ReleaseOutputBuffer fail" << endl;
213             break;
214         }
215 
216         signal_->outQueue_.pop();
217         signal_->sizeQueue_.pop();
218         signal_->outBufferQueue_.pop();
219     }
220 }
221 
AEnDemoCallback(shared_ptr<AEnSignal> signal)222 AEnDemoCallback::AEnDemoCallback(shared_ptr<AEnSignal> signal) : signal_(signal) {}
223 
OnError(AVCodecErrorType errorType,int32_t errorCode)224 void AEnDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
225 {
226     cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl;
227 }
228 
OnOutputFormatChanged(const Format & format)229 void AEnDemoCallback::OnOutputFormatChanged(const Format &format)
230 {
231     (void)format;
232     cout << "OnOutputFormatChanged received" << endl;
233 }
234 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)235 void AEnDemoCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
236 {
237     cout << "OnInputBufferAvailable received, index:" << index << endl;
238     unique_lock<mutex> lock(signal_->inMutex_);
239     signal_->inQueue_.push(index);
240     signal_->inBufferQueue_.push(buffer);
241     signal_->inCond_.notify_all();
242 }
243 
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)244 void AEnDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
245                                               std::shared_ptr<AVSharedMemory> buffer)
246 {
247     (void)info;
248     (void)flag;
249     cout << "OnOutputBufferAvailable received, index:" << index << endl;
250     unique_lock<mutex> lock(signal_->outMutex_);
251     signal_->outQueue_.push(index);
252     signal_->sizeQueue_.push(info);
253     signal_->outBufferQueue_.push(buffer);
254     cout << "**********out info size = " << info.size << endl;
255     signal_->outCond_.notify_all();
256 }