1 /*
2  * Copyright (c) 2023-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_decoder_inner_demo.h"
17 #include <unistd.h>
18 #include <string>
19 #include <string_view>
20 #include <iostream>
21 #include <unistd.h>
22 #include <chrono>
23 #include "securec.h"
24 #include "demo_log.h"
25 #include "meta/audio_types.h"
26 #include "inner_api/native/avcodec_audio_codec.h"
27 #include "avcodec_errors.h"
28 
29 using namespace OHOS::Media;
30 using namespace OHOS::MediaAVCodec;
31 using namespace OHOS::MediaAVCodec::InnerAudioDemo;
32 
33 namespace {
34 enum class MusicClass { MP3, AAC_LC, AAC_HE, AAC_HE2, AAC_LOAS, M4A, WAV, APE, FLAC, OGG, AVS3DA, AVS3GP, TS };
35 
36 constexpr std::string_view INPUT_FILE_PATH = "/data/test/media/mp3_2c_44100hz_60k.dat";
37 constexpr std::string_view OUTPUT_PCM_FILE_PATH = "/data/test/media/mp3_2c_44100hz_60k.pcm";
38 
39 constexpr int32_t INPUT_FRAME_BYTES = 2 * 1024 * 4;
40 constexpr int32_t TIME_OUT_MS = 8;
41 
42 typedef enum OH_AVCodecBufferFlags {
43     AVCODEC_BUFFER_FLAGS_NONE = 0,
44     /* Indicates that the Buffer is an End-of-Stream frame */
45     AVCODEC_BUFFER_FLAGS_EOS = 1 << 0,
46     /* Indicates that the Buffer contains keyframes */
47     AVCODEC_BUFFER_FLAGS_SYNC_FRAME = 1 << 1,
48     /* Indicates that the data contained in the Buffer is only part of a frame */
49     AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME = 1 << 2,
50     /* Indicates that the Buffer contains Codec-Specific-Data */
51     AVCODEC_BUFFER_FLAGS_CODEC_DATA = 1 << 3,
52 } OH_AVCodecBufferFlags;
53 } // namespace
54 
GetFileSize(const std::string & filePath)55 static int32_t GetFileSize(const std::string &filePath)
56 {
57     std::ifstream file(filePath, std::ios::binary | std::ios::ate);
58     if (!file) {
59         std::cerr << "Failed to open file:" << filePath << std::endl;
60         return -1;
61     }
62 
63     std::streampos fileSize = file.tellg(); // 获取文件大小
64     file.close();
65 
66     return (int32_t)fileSize;
67 }
68 
AudioCodecConsumerListener(AudioDecInnerAvBufferDemo * demo)69 AudioCodecConsumerListener::AudioCodecConsumerListener(AudioDecInnerAvBufferDemo *demo)
70 {
71     demo_ = demo;
72 }
73 
OnBufferAvailable()74 void AudioCodecConsumerListener::OnBufferAvailable()
75 {
76     demo_->OutputFunc();
77 }
78 
RunCase()79 void AudioDecInnerAvBufferDemo::RunCase()
80 {
81     innerBufferQueue_ = Media::AVBufferQueue::Create(4, Media::MemoryType::SHARED_MEMORY, "InnerDemo");  // 4
82 
83     audiocodec_ = AudioCodecFactory::CreateByName("OH.Media.Codec.Decoder.Audio.Mpeg");
84     if (audiocodec_ == nullptr) {
85         std::cout << "codec == nullptr" << std::endl;
86         return;
87     }
88     auto meta = std::make_shared<Media::Meta>();
89     meta->Set<Tag::AUDIO_CHANNEL_COUNT>(2);    // CHANNEL_COUNT is 2
90     meta->Set<Tag::AUDIO_CHANNEL_LAYOUT>(Media::Plugins::AudioChannelLayout::STEREO);
91     meta->Set<Tag::AUDIO_SAMPLE_FORMAT>(Media::Plugins::AudioSampleFormat::SAMPLE_S16LE);
92     meta->Set<Tag::AUDIO_SAMPLE_RATE>(44100);    // SAMPLE_RATE is 44100
93     meta->Set<Tag::MEDIA_BITRATE>(60000);    // BITRATE is 60000
94     audiocodec_->Configure(meta);
95 
96     audiocodec_->SetOutputBufferQueue(innerBufferQueue_->GetProducer());
97     audiocodec_->Prepare();
98 
99     implConsumer_ = innerBufferQueue_->GetConsumer();
100     sptr<Media::IConsumerListener> comsumerListener = new AudioCodecConsumerListener(this);
101     implConsumer_->SetBufferAvailableListener(comsumerListener);
102     mediaCodecProducer_ = audiocodec_->GetInputBufferQueue();
103 
104     audiocodec_->Start();
105     isRunning_.store(true);
106 
107     fileSize_ = GetFileSize(INPUT_FILE_PATH.data());
108     inputFile_ = std::make_unique<std::ifstream>(INPUT_FILE_PATH, std::ios::binary);
109     outputFile_ = std::make_unique<std::ofstream>(OUTPUT_PCM_FILE_PATH, std::ios::binary);
110     InputFunc();
111     inputFile_->close();
112     outputFile_->close();
113     return;
114 }
115 
GetInputBufferSize()116 int32_t AudioDecInnerAvBufferDemo::GetInputBufferSize()
117 {
118     int32_t capacity = 0;
119     DEMO_CHECK_AND_RETURN_RET_LOG(audiocodec_ != nullptr, capacity, "audiocodec_ is nullptr");
120     std::shared_ptr<Media::Meta> bufferConfig = std::make_shared<Media::Meta>();
121     DEMO_CHECK_AND_RETURN_RET_LOG(bufferConfig != nullptr, capacity, "bufferConfig is nullptr");
122     int32_t ret = audiocodec_->GetOutputFormat(bufferConfig);
123     DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, capacity, "GetOutputFormat fail");
124     DEMO_CHECK_AND_RETURN_RET_LOG(bufferConfig->Get<Media::Tag::AUDIO_MAX_INPUT_SIZE>(capacity),
125         capacity, "get max input buffer size fail");
126     return capacity;
127 }
128 
InputFunc()129 void AudioDecInnerAvBufferDemo::InputFunc()
130 {
131     DEMO_CHECK_AND_RETURN_LOG(inputFile_ != nullptr && inputFile_->is_open(), "Fatal: open file fail");
132     int32_t sumReadSize = 0;
133     Media::Status ret;
134     int64_t size;
135     int64_t pts;
136     Media::AVBufferConfig avBufferConfig;
137     avBufferConfig.size = GetInputBufferSize();
138     while (isRunning_) {
139         std::shared_ptr<AVBuffer> inputBuffer = nullptr;
140         DEMO_CHECK_AND_BREAK_LOG(mediaCodecProducer_ != nullptr, "mediaCodecProducer_ is nullptr");
141         ret = mediaCodecProducer_->RequestBuffer(inputBuffer, avBufferConfig, TIME_OUT_MS);
142         if (ret != Media::Status::OK) {
143             std::cout << "produceInputBuffer RequestBuffer fail,ret=" << (int32_t)ret << std::endl;
144             break;
145         }
146         DEMO_CHECK_AND_BREAK_LOG(inputBuffer != nullptr, "buffer is nullptr");
147         inputFile_->read(reinterpret_cast<char *>(&size), sizeof(size));
148         if (inputFile_->eof() || inputFile_->gcount() == 0 || size == 0) {
149             inputBuffer->memory_->SetSize(1);
150             inputBuffer->flag_ = AVCODEC_BUFFER_FLAGS_EOS;
151             sumReadSize += 0;
152             mediaCodecProducer_->PushBuffer(inputBuffer, true);
153             sumReadSize += inputFile_->gcount();
154             std::cout << "InputFunc, INPUT_FRAME_BYTES:" << INPUT_FRAME_BYTES << " flag:" << inputBuffer->flag_
155                       << " sumReadSize:" << sumReadSize << " fileSize_:" << fileSize_
156                       << " process:" << 100 * sumReadSize / fileSize_ << "%" << std::endl;    // 100
157             std::cout << "end buffer\n";
158             break;
159         }
160         DEMO_CHECK_AND_BREAK_LOG(inputFile_->gcount() == sizeof(size), "Fatal: read size fail");
161         sumReadSize += inputFile_->gcount();
162         inputFile_->read(reinterpret_cast<char *>(&pts), sizeof(pts));
163         DEMO_CHECK_AND_BREAK_LOG(inputFile_->gcount() == sizeof(pts), "Fatal: read pts fail");
164         sumReadSize += inputFile_->gcount();
165         inputFile_->read(reinterpret_cast<char *>(inputBuffer->memory_->GetAddr()), size);
166         DEMO_CHECK_AND_BREAK_LOG(inputFile_->gcount() == size, "Fatal: read buffer fail");
167         inputBuffer->memory_->SetSize(size);
168         inputBuffer->flag_ = AVCODEC_BUFFER_FLAGS_NONE;
169         sumReadSize += inputFile_->gcount();
170         mediaCodecProducer_->PushBuffer(inputBuffer, true);
171         std::cout << "InputFunc, INPUT_FRAME_BYTES:" << INPUT_FRAME_BYTES << " flag:" << inputBuffer->flag_
172                   << " sumReadSize:" << sumReadSize << " fileSize_:" << fileSize_
173                   << " process:" << 100 * sumReadSize / fileSize_ << "%" << std::endl;   // 100
174     }
175 }
176 
OutputFunc()177 void AudioDecInnerAvBufferDemo::OutputFunc()
178 {
179     bufferConsumerAvailableCount_++;
180     Media::Status ret = Media::Status::OK;
181     while (isRunning_ && (bufferConsumerAvailableCount_ > 0)) {
182         std::cout << "/**********ImplConsumerOutputBuffer while**********/" << std::endl;
183         std::shared_ptr<AVBuffer> outputBuffer;
184         ret = implConsumer_->AcquireBuffer(outputBuffer);
185         if (ret != Media::Status::OK) {
186             std::cout << "Consumer AcquireBuffer fail,ret=" << (int32_t)ret << std::endl;
187             break;
188         }
189         if (outputBuffer == nullptr) {
190             std::cout << "OutputFunc OH_AVBuffer is nullptr" << std::endl;
191             continue;
192         }
193         outputFile_->write(reinterpret_cast<char *>(outputBuffer->memory_->GetAddr()),
194                            outputBuffer->memory_->GetSize());
195         if (outputBuffer->flag_ == AVCODEC_BUFFER_FLAGS_EOS || outputBuffer->memory_->GetSize() == 0) {
196             std::cout << "out eos" << std::endl;
197             isRunning_.store(false);
198         }
199         implConsumer_->ReleaseBuffer(outputBuffer);
200         bufferConsumerAvailableCount_--;
201     }
202 }
203