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 }