• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }