• 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 "audio_ffmpeg_flac_encoder_plugin.h"
17 #include <set>
18 #include "media_description.h"
19 #include "avcodec_errors.h"
20 #include "avcodec_trace.h"
21 #include "avcodec_log.h"
22 #include "avcodec_mime_type.h"
23 #include "avcodec_audio_common.h"
24 #include "ffmpeg_converter.h"
25 
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AvCodec-AudioFFMpegFlacEncoderPlugin"};
28 constexpr int32_t MIN_CHANNELS = 1;
29 constexpr int32_t MAX_CHANNELS = 8;
30 constexpr int32_t MIN_COMPLIANCE_LEVEL = -2;
31 constexpr int32_t MAX_COMPLIANCE_LEVEL = 2;
32 constexpr int32_t MAX_BYTES_PER_SAMPLE = 4;
33 constexpr int32_t SAMPLES = 9216;
34 static const int32_t FLAC_ENCODER_SAMPLE_RATE_TABLE[] = {
35     8000, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000,
36 };
37 static const uint64_t FLAC_CHANNEL_LAYOUT_TABLE[] = {AV_CH_LAYOUT_MONO,    AV_CH_LAYOUT_STEREO,  AV_CH_LAYOUT_SURROUND,
38                                                      AV_CH_LAYOUT_QUAD,    AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_5POINT1,
39                                                      AV_CH_LAYOUT_6POINT1, AV_CH_LAYOUT_7POINT1};
40 const std::map<int32_t, int32_t> BITS_PER_RAW_SAMPLE_MAP = {
41     {OHOS::MediaAVCodec::AudioSampleFormat::SAMPLE_S16LE, 16},
42     {OHOS::MediaAVCodec::AudioSampleFormat::SAMPLE_S24LE, 24},
43     {OHOS::MediaAVCodec::AudioSampleFormat::SAMPLE_S32LE, 32},
44 };
45 static std::set<OHOS::MediaAVCodec::AudioSampleFormat> supportedSampleFormats = {
46     OHOS::MediaAVCodec::AudioSampleFormat::SAMPLE_S16LE,
47     OHOS::MediaAVCodec::AudioSampleFormat::SAMPLE_S32LE,
48 };
49 } // namespace
50 
51 namespace OHOS {
52 namespace MediaAVCodec {
53 constexpr std::string_view AUDIO_CODEC_NAME = "flac";
AudioFFMpegFlacEncoderPlugin()54 AudioFFMpegFlacEncoderPlugin::AudioFFMpegFlacEncoderPlugin() : basePlugin(std::make_unique<AudioFfmpegEncoderPlugin>())
55 {
56     channels = 0;
57 }
58 
~AudioFFMpegFlacEncoderPlugin()59 AudioFFMpegFlacEncoderPlugin::~AudioFFMpegFlacEncoderPlugin()
60 {
61     if (basePlugin != nullptr) {
62         basePlugin->Release();
63         basePlugin.reset();
64     }
65 }
66 
CheckSampleRate(int32_t sampleRate)67 static bool CheckSampleRate(int32_t sampleRate)
68 {
69     for (auto i : FLAC_ENCODER_SAMPLE_RATE_TABLE) {
70         if (i == sampleRate) {
71             return true;
72         }
73     }
74     return false;
75 }
76 
CheckChannelLayout(uint64_t channelLayout)77 static bool CheckChannelLayout(uint64_t channelLayout)
78 {
79     for (auto i : FLAC_CHANNEL_LAYOUT_TABLE) {
80         if (i == channelLayout) {
81             return true;
82         }
83     }
84     return false;
85 }
86 
CheckBitsPerSample(int32_t bitsPerCodedSample)87 static bool CheckBitsPerSample(int32_t bitsPerCodedSample)
88 {
89     for (auto &i : BITS_PER_RAW_SAMPLE_MAP) {
90         if (i.first == bitsPerCodedSample) {
91             return true;
92         }
93     }
94     return false;
95 }
96 
SetContext(const Format & format)97 int32_t AudioFFMpegFlacEncoderPlugin::SetContext(const Format &format)
98 {
99     int32_t complianceLevel;
100     int32_t bitsPerCodedSample;
101     auto avCodecContext = basePlugin->GetCodecContext();
102     format.GetIntValue(MediaDescriptionKey::MD_KEY_COMPLIANCE_LEVEL, complianceLevel);
103     format.GetIntValue(MediaDescriptionKey::MD_KEY_BITS_PER_CODED_SAMPLE, bitsPerCodedSample);
104     avCodecContext->strict_std_compliance = complianceLevel;
105     avCodecContext->bits_per_raw_sample = BITS_PER_RAW_SAMPLE_MAP.at(bitsPerCodedSample);
106     return AVCodecServiceErrCode::AVCS_ERR_OK;
107 }
108 
CheckBitRate(const Format & format) const109 bool AudioFFMpegFlacEncoderPlugin::CheckBitRate(const Format &format) const
110 {
111     if (!format.ContainKey(MediaDescriptionKey::MD_KEY_BITRATE)) {
112         AVCODEC_LOGW("parameter bit_rate not available");
113         return true;
114     }
115     int64_t bitRate;
116     format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, bitRate);
117     if (bitRate < 0) {
118         AVCODEC_LOGE("parameter bit_rate illegal");
119         return false;
120     }
121     return true;
122 }
123 
CheckFormat(const Format & format)124 int32_t AudioFFMpegFlacEncoderPlugin::CheckFormat(const Format &format)
125 {
126     int32_t channelCount;
127     int32_t sampleRate;
128     int32_t bitsPerCodedSample;
129     int32_t complianceLevel;
130     int64_t channelLayout;
131     format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channelCount);
132     format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sampleRate);
133     format.GetIntValue(MediaDescriptionKey::MD_KEY_BITS_PER_CODED_SAMPLE, bitsPerCodedSample);
134     format.GetIntValue(MediaDescriptionKey::MD_KEY_COMPLIANCE_LEVEL, complianceLevel);
135     format.GetLongValue(MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT, channelLayout);
136     auto ffChannelLayout =
137         FFMpegConverter::ConvertOHAudioChannelLayoutToFFMpeg(static_cast<AudioChannelLayout>(channelLayout));
138     if (ffChannelLayout == AV_CH_LAYOUT_NATIVE) {
139         AVCODEC_LOGE("InitContext failed, because ffChannelLayout is AV_CH_LAYOUT_NATIVE");
140         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR;
141     }
142 
143     int32_t sampleFormat;
144     format.GetIntValue(MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT, sampleFormat);
145     if (supportedSampleFormats.find(static_cast<AudioSampleFormat>(sampleFormat)) == supportedSampleFormats.end()) {
146         AVCODEC_LOGE("input sample format not supported");
147         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR;
148     }
149 
150     if (!CheckSampleRate(sampleRate)) {
151         AVCODEC_LOGE("init failed, because sampleRate=%{public}d not in table.", sampleRate);
152         return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_SAMPLE_RATE;
153     } else if (channelCount < MIN_CHANNELS || channelCount > MAX_CHANNELS) {
154         AVCODEC_LOGE("init failed, because channelCount=%{public}d not support.", channelCount);
155         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT;
156     } else if (!CheckBitsPerSample(bitsPerCodedSample)) {
157         AVCODEC_LOGE("init failed, because bitsPerCodedSample=%{public}d not support.", bitsPerCodedSample);
158         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR;
159     } else if (complianceLevel < MIN_COMPLIANCE_LEVEL || complianceLevel > MAX_COMPLIANCE_LEVEL) {
160         AVCODEC_LOGE("init failed, because complianceLevel=%{public}d not support.", complianceLevel);
161         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR;
162     } else if (!CheckChannelLayout(ffChannelLayout)) {
163         AVCODEC_LOGE("init failed, because ffChannelLayout=%{public}" PRId64 "not support.", ffChannelLayout);
164         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR;
165     } else if (!CheckBitRate(format)) {
166         return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR;
167     }
168     channels = channelCount;
169     return AVCodecServiceErrCode::AVCS_ERR_OK;
170 }
171 
SetFormat(const Format & format)172 void AudioFFMpegFlacEncoderPlugin::SetFormat(const Format &format) noexcept
173 {
174     format_ = format;
175     auto context = basePlugin->GetCodecContext();
176     format_.PutIntValue(MediaDescriptionKey::MD_KEY_AUDIO_SAMPLES_PER_FRAME, context->frame_size);
177     format_.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, AVCodecMimeType::MEDIA_MIMETYPE_AUDIO_FLAC);
178 }
179 
Init(const Format & format)180 int32_t AudioFFMpegFlacEncoderPlugin::Init(const Format &format)
181 {
182     int32_t ret = basePlugin->AllocateContext("flac");
183     CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, ret,
184         "init failed, because AllocateContext failed. ret=%{public}d", ret);
185 
186     ret = CheckFormat(format);
187     CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, ret,
188         "init failed, because CheckFormat failed. ret=%{public}d", ret);
189 
190     basePlugin->InitContext(format);
191 
192     ret = SetContext(format);
193     CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, ret,
194         "init failed, because SetContext failed. ret=%{public}d", ret);
195 
196     ret = basePlugin->OpenContext();
197     CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, ret,
198         "init failed, because OpenContext failed. ret=%{public}d", ret);
199 
200     SetFormat(format);
201 
202     ret = basePlugin->InitFrame();
203     CHECK_AND_RETURN_RET_LOG(ret == AVCodecServiceErrCode::AVCS_ERR_OK, ret,
204         "init failed, because InitFrame failed. ret=%{public}d", ret);
205 
206     return AVCodecServiceErrCode::AVCS_ERR_OK;
207 }
208 
ProcessSendData(const std::shared_ptr<AudioBufferInfo> & inputBuffer)209 int32_t AudioFFMpegFlacEncoderPlugin::ProcessSendData(const std::shared_ptr<AudioBufferInfo> &inputBuffer)
210 {
211     return basePlugin->ProcessSendData(inputBuffer);
212 }
213 
ProcessRecieveData(std::shared_ptr<AudioBufferInfo> & outBuffer)214 int32_t AudioFFMpegFlacEncoderPlugin::ProcessRecieveData(std::shared_ptr<AudioBufferInfo> &outBuffer)
215 {
216     return basePlugin->ProcessRecieveData(outBuffer);
217 }
218 
Reset()219 int32_t AudioFFMpegFlacEncoderPlugin::Reset()
220 {
221     return basePlugin->Reset();
222 }
223 
Release()224 int32_t AudioFFMpegFlacEncoderPlugin::Release()
225 {
226     return basePlugin->Release();
227 }
228 
Flush()229 int32_t AudioFFMpegFlacEncoderPlugin::Flush()
230 {
231     return basePlugin->Flush();
232 }
233 
GetInputBufferSize() const234 int32_t AudioFFMpegFlacEncoderPlugin::GetInputBufferSize() const
235 {
236     int32_t inputBufferSize = SAMPLES * channels * MAX_BYTES_PER_SAMPLE;
237     int32_t maxSize = basePlugin->GetMaxInputSize();
238     if (maxSize < 0 || maxSize > inputBufferSize) {
239         maxSize = inputBufferSize;
240     }
241     return maxSize;
242 }
243 
GetOutputBufferSize() const244 int32_t AudioFFMpegFlacEncoderPlugin::GetOutputBufferSize() const
245 {
246     int32_t outputBufferSize = SAMPLES * channels * MAX_BYTES_PER_SAMPLE;
247     return outputBufferSize;
248 }
249 
GetFormat() const250 Format AudioFFMpegFlacEncoderPlugin::GetFormat() const noexcept
251 {
252     return format_;
253 }
254 
GetCodecType() const255 std::string_view AudioFFMpegFlacEncoderPlugin::GetCodecType() const noexcept
256 {
257     return AUDIO_CODEC_NAME;
258 }
259 } // namespace MediaAVCodec
260 } // namespace OHOS