blob: f4b931d6cee5871e3b6c45166b7f0f5aef45f073 [file] [log] [blame]
Andrew Top2a796462018-06-29 09:04:04 -07001// Copyright 2018 The Cobalt Authors. All Rights Reserved.
Mike Fleming3933d922018-04-02 10:53:08 -07002//
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// This file contains the explicit specialization of the AudioDecoderImpl class
16// for the value 'FFMPEG'.
17
18#include "starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.h"
19
20#include "starboard/audio_sink.h"
Kaido Kertb6855992020-06-22 16:39:13 -070021#include "starboard/common/format_string.h"
Chad Duffinac9ac062019-07-23 10:06:45 -070022#include "starboard/common/log.h"
23#include "starboard/common/string.h"
Mike Fleming3933d922018-04-02 10:53:08 -070024#include "starboard/memory.h"
25#include "starboard/shared/starboard/media/media_util.h"
26
27namespace starboard {
28namespace shared {
29namespace ffmpeg {
30
31namespace {
32
33SbMediaAudioSampleType GetSupportedSampleType() {
34 if (SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32)) {
35 return kSbMediaAudioSampleTypeFloat32;
36 }
37 return kSbMediaAudioSampleTypeInt16Deprecated;
38}
39
40AVCodecID GetFfmpegCodecIdByMediaCodec(SbMediaAudioCodec audio_codec) {
41 switch (audio_codec) {
42 case kSbMediaAudioCodecAac:
43 return AV_CODEC_ID_AAC;
Kaido Kertf585e262020-06-08 11:42:28 -070044#if SB_API_VERSION >= 12 || SB_HAS(AC3_AUDIO)
Andrew Top61a84952019-04-30 15:07:33 -070045 case kSbMediaAudioCodecAc3:
Kaido Kert612c0202020-01-22 10:28:42 -080046 return kSbHasAc3Audio ? AV_CODEC_ID_AC3 : AV_CODEC_ID_NONE;
Andrew Top61a84952019-04-30 15:07:33 -070047 case kSbMediaAudioCodecEac3:
Kaido Kert612c0202020-01-22 10:28:42 -080048 return kSbHasAc3Audio ? AV_CODEC_ID_EAC3 : AV_CODEC_ID_NONE;
Kaido Kertf585e262020-06-08 11:42:28 -070049#endif // SB_API_VERSION >= 12 ||
Kaido Kert612c0202020-01-22 10:28:42 -080050 // SB_HAS(AC3_AUDIO)
Mike Fleming3933d922018-04-02 10:53:08 -070051 case kSbMediaAudioCodecOpus:
52 return AV_CODEC_ID_OPUS;
53 default:
54 return AV_CODEC_ID_NONE;
55 }
56}
57
58const bool g_registered =
59 FFMPEGDispatch::RegisterSpecialization(FFMPEG,
60 LIBAVCODEC_VERSION_MAJOR,
61 LIBAVFORMAT_VERSION_MAJOR,
62 LIBAVUTIL_VERSION_MAJOR);
63
64} // namespace
65
66AudioDecoderImpl<FFMPEG>::AudioDecoderImpl(
67 SbMediaAudioCodec audio_codec,
Chad Duffinac9ac062019-07-23 10:06:45 -070068 const SbMediaAudioSampleInfo& audio_sample_info)
Mike Fleming3933d922018-04-02 10:53:08 -070069 : audio_codec_(audio_codec),
70 codec_context_(NULL),
71 av_frame_(NULL),
72 stream_ended_(false),
Chad Duffinac9ac062019-07-23 10:06:45 -070073 audio_sample_info_(audio_sample_info) {
Mike Fleming3933d922018-04-02 10:53:08 -070074 SB_DCHECK(g_registered) << "Decoder Specialization registration failed.";
75 SB_DCHECK(GetFfmpegCodecIdByMediaCodec(audio_codec) != AV_CODEC_ID_NONE)
76 << "Unsupported audio codec " << audio_codec;
77 ffmpeg_ = FFMPEGDispatch::GetInstance();
78 SB_DCHECK(ffmpeg_);
79 if ((ffmpeg_->specialization_version()) == FFMPEG) {
80 InitializeCodec();
81 }
82}
83
84AudioDecoderImpl<FFMPEG>::~AudioDecoderImpl() {
85 TeardownCodec();
86}
87
88// static
89AudioDecoder* AudioDecoderImpl<FFMPEG>::Create(
90 SbMediaAudioCodec audio_codec,
Chad Duffinac9ac062019-07-23 10:06:45 -070091 const SbMediaAudioSampleInfo& audio_sample_info) {
92 return new AudioDecoderImpl<FFMPEG>(audio_codec, audio_sample_info);
Mike Fleming3933d922018-04-02 10:53:08 -070093}
94
95void AudioDecoderImpl<FFMPEG>::Initialize(const OutputCB& output_cb,
96 const ErrorCB& error_cb) {
97 SB_DCHECK(BelongsToCurrentThread());
98 SB_DCHECK(output_cb);
99 SB_DCHECK(!output_cb_);
100 SB_DCHECK(error_cb);
101 SB_DCHECK(!error_cb_);
102
103 output_cb_ = output_cb;
104 error_cb_ = error_cb;
105}
106
107void AudioDecoderImpl<FFMPEG>::Decode(
108 const scoped_refptr<InputBuffer>& input_buffer,
109 const ConsumedCB& consumed_cb) {
110 SB_DCHECK(BelongsToCurrentThread());
111 SB_DCHECK(input_buffer);
112 SB_DCHECK(output_cb_);
113 SB_CHECK(codec_context_ != NULL);
114
115 Schedule(consumed_cb);
116
117 if (stream_ended_) {
118 SB_LOG(ERROR) << "Decode() is called after WriteEndOfStream() is called.";
119 return;
120 }
121
122 AVPacket packet;
123 ffmpeg_->av_init_packet(&packet);
124 packet.data = const_cast<uint8_t*>(input_buffer->data());
125 packet.size = input_buffer->size();
126
Kaido Kert612c0202020-01-22 10:28:42 -0800127#if LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
Mike Fleming3933d922018-04-02 10:53:08 -0700128 ffmpeg_->avcodec_get_frame_defaults(av_frame_);
Kaido Kert612c0202020-01-22 10:28:42 -0800129#endif // LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
Mike Fleming3933d922018-04-02 10:53:08 -0700130 int frame_decoded = 0;
131 int result = ffmpeg_->avcodec_decode_audio4(codec_context_, av_frame_,
132 &frame_decoded, &packet);
133 if (result != input_buffer->size()) {
134 // TODO: Consider fill it with silence.
135 SB_DLOG(WARNING) << "avcodec_decode_audio4() failed with result: " << result
136 << " with input buffer size: " << input_buffer->size()
137 << " and frame decoded: " << frame_decoded;
Andrew Top8b6b16e2018-07-25 17:44:41 -0700138 error_cb_(
139 kSbPlayerErrorDecode,
140 FormatString("avcodec_decode_audio4() failed with result %d.", result));
Mike Fleming3933d922018-04-02 10:53:08 -0700141 return;
142 }
143
144 if (frame_decoded != 1) {
145 // TODO: Adjust timestamp accordingly when decoding result is shifted.
146 SB_DCHECK(frame_decoded == 0);
147 SB_DLOG(WARNING) << "avcodec_decode_audio4() returns with 0 frames decoded";
148 return;
149 }
150
151 int decoded_audio_size = ffmpeg_->av_samples_get_buffer_size(
152 NULL, codec_context_->channels, av_frame_->nb_samples,
153 codec_context_->sample_fmt, 1);
Chad Duffinac9ac062019-07-23 10:06:45 -0700154 audio_sample_info_.samples_per_second = codec_context_->sample_rate;
Mike Fleming3933d922018-04-02 10:53:08 -0700155
156 if (decoded_audio_size > 0) {
157 scoped_refptr<DecodedAudio> decoded_audio = new DecodedAudio(
158 codec_context_->channels, GetSampleType(), GetStorageType(),
159 input_buffer->timestamp(),
160 codec_context_->channels * av_frame_->nb_samples *
161 starboard::media::GetBytesPerSample(GetSampleType()));
162 if (GetStorageType() == kSbMediaAudioFrameStorageTypeInterleaved) {
163 SbMemoryCopy(decoded_audio->buffer(), *av_frame_->extended_data,
164 decoded_audio->size());
165 } else {
166 SB_DCHECK(GetStorageType() == kSbMediaAudioFrameStorageTypePlanar);
167 const int per_channel_size_in_bytes =
168 decoded_audio->size() / decoded_audio->channels();
169 for (int i = 0; i < decoded_audio->channels(); ++i) {
170 SbMemoryCopy(decoded_audio->buffer() + per_channel_size_in_bytes * i,
171 av_frame_->extended_data[i], per_channel_size_in_bytes);
172 }
173 }
174 decoded_audios_.push(decoded_audio);
175 Schedule(output_cb_);
176 } else {
177 // TODO: Consider fill it with silence.
178 SB_LOG(ERROR) << "Decoded audio frame is empty.";
179 }
180}
181
182void AudioDecoderImpl<FFMPEG>::WriteEndOfStream() {
183 SB_DCHECK(BelongsToCurrentThread());
184 SB_DCHECK(output_cb_);
185
186 // AAC has no dependent frames so we needn't flush the decoder. Set the flag
187 // to ensure that Decode() is not called when the stream is ended.
188 stream_ended_ = true;
189 // Put EOS into the queue.
190 decoded_audios_.push(new DecodedAudio);
191
192 Schedule(output_cb_);
193}
194
195scoped_refptr<AudioDecoderImpl<FFMPEG>::DecodedAudio>
Andrew Top63c7ad42019-11-25 16:10:13 -0800196AudioDecoderImpl<FFMPEG>::Read(int* samples_per_second) {
Mike Fleming3933d922018-04-02 10:53:08 -0700197 SB_DCHECK(BelongsToCurrentThread());
198 SB_DCHECK(output_cb_);
199 SB_DCHECK(!decoded_audios_.empty());
200
201 scoped_refptr<DecodedAudio> result;
202 if (!decoded_audios_.empty()) {
203 result = decoded_audios_.front();
204 decoded_audios_.pop();
205 }
Andrew Top63c7ad42019-11-25 16:10:13 -0800206 *samples_per_second = audio_sample_info_.samples_per_second;
Mike Fleming3933d922018-04-02 10:53:08 -0700207 return result;
208}
209
210void AudioDecoderImpl<FFMPEG>::Reset() {
211 SB_DCHECK(BelongsToCurrentThread());
212
213 stream_ended_ = false;
214 while (!decoded_audios_.empty()) {
215 decoded_audios_.pop();
216 }
217
218 CancelPendingJobs();
219}
220
221bool AudioDecoderImpl<FFMPEG>::is_valid() const {
222 return (ffmpeg_ != NULL) && ffmpeg_->is_valid() && (codec_context_ != NULL);
223}
224
225SbMediaAudioSampleType AudioDecoderImpl<FFMPEG>::GetSampleType() const {
226 SB_DCHECK(BelongsToCurrentThread());
227
228 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16 ||
229 codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P) {
230 return kSbMediaAudioSampleTypeInt16Deprecated;
231 } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT ||
232 codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) {
233 return kSbMediaAudioSampleTypeFloat32;
234 }
235
236 SB_NOTREACHED();
237
238 return kSbMediaAudioSampleTypeFloat32;
239}
240
241SbMediaAudioFrameStorageType AudioDecoderImpl<FFMPEG>::GetStorageType() const {
242 SB_DCHECK(BelongsToCurrentThread());
243
244 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16 ||
245 codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
246 return kSbMediaAudioFrameStorageTypeInterleaved;
247 }
248 if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P ||
249 codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) {
250 return kSbMediaAudioFrameStorageTypePlanar;
251 }
252
253 SB_NOTREACHED();
254 return kSbMediaAudioFrameStorageTypeInterleaved;
255}
256
Mike Fleming3933d922018-04-02 10:53:08 -0700257void AudioDecoderImpl<FFMPEG>::InitializeCodec() {
258 codec_context_ = ffmpeg_->avcodec_alloc_context3(NULL);
259
260 if (codec_context_ == NULL) {
261 SB_LOG(ERROR) << "Unable to allocate ffmpeg codec context";
262 return;
263 }
264
265 codec_context_->codec_type = AVMEDIA_TYPE_AUDIO;
266 codec_context_->codec_id = GetFfmpegCodecIdByMediaCodec(audio_codec_);
267 // Request_sample_fmt is set by us, but sample_fmt is set by the decoder.
268 if (GetSupportedSampleType() == kSbMediaAudioSampleTypeInt16Deprecated) {
269 codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16;
270 } else {
271 codec_context_->request_sample_fmt = AV_SAMPLE_FMT_FLT;
272 }
273
Chad Duffinac9ac062019-07-23 10:06:45 -0700274 codec_context_->channels = audio_sample_info_.number_of_channels;
275 codec_context_->sample_rate = audio_sample_info_.samples_per_second;
Mike Fleming3933d922018-04-02 10:53:08 -0700276 codec_context_->extradata = NULL;
277 codec_context_->extradata_size = 0;
278
279 if (codec_context_->codec_id == AV_CODEC_ID_OPUS &&
Chad Duffinac9ac062019-07-23 10:06:45 -0700280 audio_sample_info_.audio_specific_config_size > 0) {
Mike Fleming3933d922018-04-02 10:53:08 -0700281 // AV_INPUT_BUFFER_PADDING_SIZE is not defined in ancient avcodec.h. Use a
282 // large enough padding here explicitly.
283 const int kAvInputBufferPaddingSize = 256;
Chad Duffinac9ac062019-07-23 10:06:45 -0700284 codec_context_->extradata_size =
285 audio_sample_info_.audio_specific_config_size;
Mike Fleming3933d922018-04-02 10:53:08 -0700286 codec_context_->extradata = static_cast<uint8_t*>(ffmpeg_->av_malloc(
287 codec_context_->extradata_size + kAvInputBufferPaddingSize));
288 SB_DCHECK(codec_context_->extradata);
Chad Duffinac9ac062019-07-23 10:06:45 -0700289 SbMemoryCopy(codec_context_->extradata,
290 audio_sample_info_.audio_specific_config,
Mike Fleming3933d922018-04-02 10:53:08 -0700291 codec_context_->extradata_size);
292 SbMemorySet(codec_context_->extradata + codec_context_->extradata_size, 0,
293 kAvInputBufferPaddingSize);
294 }
295
296 AVCodec* codec = ffmpeg_->avcodec_find_decoder(codec_context_->codec_id);
297
298 if (codec == NULL) {
299 SB_LOG(ERROR) << "Unable to allocate ffmpeg codec context";
300 TeardownCodec();
301 return;
302 }
303
304 int rv = ffmpeg_->OpenCodec(codec_context_, codec);
305 if (rv < 0) {
306 SB_LOG(ERROR) << "Unable to open codec";
307 TeardownCodec();
308 return;
309 }
310
Kaido Kert612c0202020-01-22 10:28:42 -0800311#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
Mike Fleming3933d922018-04-02 10:53:08 -0700312 av_frame_ = ffmpeg_->av_frame_alloc();
Kaido Kert612c0202020-01-22 10:28:42 -0800313#else // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
Mike Fleming3933d922018-04-02 10:53:08 -0700314 av_frame_ = ffmpeg_->avcodec_alloc_frame();
Kaido Kert612c0202020-01-22 10:28:42 -0800315#endif // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
Mike Fleming3933d922018-04-02 10:53:08 -0700316 if (av_frame_ == NULL) {
317 SB_LOG(ERROR) << "Unable to allocate audio frame";
318 TeardownCodec();
319 }
320}
321
322void AudioDecoderImpl<FFMPEG>::TeardownCodec() {
323 if (codec_context_) {
324 ffmpeg_->CloseCodec(codec_context_);
Kaido Kert612c0202020-01-22 10:28:42 -0800325 ffmpeg_->FreeContext(&codec_context_);
Mike Fleming3933d922018-04-02 10:53:08 -0700326 }
Kaido Kert612c0202020-01-22 10:28:42 -0800327 ffmpeg_->FreeFrame(&av_frame_);
Mike Fleming3933d922018-04-02 10:53:08 -0700328}
329
330} // namespace ffmpeg
331} // namespace shared
332} // namespace starboard