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