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