OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/filters/ffmpeg_audio_decoder.h" | 5 #include "media/filters/ffmpeg_audio_decoder.h" |
6 | 6 |
7 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
8 #include "base/single_thread_task_runner.h" | 8 #include "base/single_thread_task_runner.h" |
9 #include "media/base/audio_buffer.h" | 9 #include "media/base/audio_buffer.h" |
10 #include "media/base/audio_bus.h" | 10 #include "media/base/audio_bus.h" |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 log_cb_(log_cb) { | 134 log_cb_(log_cb) { |
135 } | 135 } |
136 | 136 |
137 FFmpegAudioDecoder::~FFmpegAudioDecoder() { | 137 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
138 DCHECK_EQ(state_, kUninitialized); | 138 DCHECK_EQ(state_, kUninitialized); |
139 DCHECK(!codec_context_); | 139 DCHECK(!codec_context_); |
140 DCHECK(!av_frame_); | 140 DCHECK(!av_frame_); |
141 } | 141 } |
142 | 142 |
143 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, | 143 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, |
144 const PipelineStatusCB& status_cb, | 144 const PipelineStatusCB& status_cb) { |
145 const OutputCB& output_cb) { | |
146 DCHECK(task_runner_->BelongsToCurrentThread()); | 145 DCHECK(task_runner_->BelongsToCurrentThread()); |
147 DCHECK(!config.is_encrypted()); | 146 DCHECK(!config.is_encrypted()); |
148 | 147 |
149 FFmpegGlue::InitializeFFmpeg(); | 148 FFmpegGlue::InitializeFFmpeg(); |
150 | 149 |
151 config_ = config; | 150 config_ = config; |
152 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 151 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
153 | 152 |
154 if (!config.IsValidConfig() || !ConfigureDecoder()) { | 153 if (!config.IsValidConfig() || !ConfigureDecoder()) { |
155 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 154 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
156 return; | 155 return; |
157 } | 156 } |
158 | 157 |
159 // Success! | 158 // Success! |
160 output_cb_ = BindToCurrentLoop(output_cb); | |
161 state_ = kNormal; | 159 state_ = kNormal; |
162 initialize_cb.Run(PIPELINE_OK); | 160 initialize_cb.Run(PIPELINE_OK); |
163 } | 161 } |
164 | 162 |
165 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 163 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
166 const DecodeCB& decode_cb) { | 164 const DecodeCB& decode_cb) { |
167 DCHECK(task_runner_->BelongsToCurrentThread()); | 165 DCHECK(task_runner_->BelongsToCurrentThread()); |
168 DCHECK(!decode_cb.is_null()); | 166 DCHECK(!decode_cb.is_null()); |
169 CHECK_NE(state_, kUninitialized); | 167 CHECK_NE(state_, kUninitialized); |
170 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); | 168 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); |
171 | 169 |
172 if (state_ == kError) { | 170 if (state_ == kError) { |
173 decode_cb_bound.Run(kDecodeError); | 171 decode_cb_bound.Run(kDecodeError, NULL); |
174 return; | 172 return; |
175 } | 173 } |
176 | 174 |
177 // Do nothing if decoding has finished. | 175 // Return empty frames if decoding has finished. |
178 if (state_ == kDecodeFinished) { | 176 if (state_ == kDecodeFinished) { |
179 decode_cb_bound.Run(kOk); | 177 decode_cb_bound.Run(kOk, AudioBuffer::CreateEOSBuffer()); |
| 178 return; |
| 179 } |
| 180 |
| 181 if (!buffer) { |
| 182 decode_cb_bound.Run(kAborted, NULL); |
180 return; | 183 return; |
181 } | 184 } |
182 | 185 |
183 DecodeBuffer(buffer, decode_cb_bound); | 186 DecodeBuffer(buffer, decode_cb_bound); |
184 } | 187 } |
185 | 188 |
| 189 scoped_refptr<AudioBuffer> FFmpegAudioDecoder::GetDecodeOutput() { |
| 190 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 191 if (queued_audio_.empty()) |
| 192 return NULL; |
| 193 scoped_refptr<AudioBuffer> out = queued_audio_.front(); |
| 194 queued_audio_.pop_front(); |
| 195 return out; |
| 196 } |
| 197 |
186 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { | 198 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { |
187 DCHECK(task_runner_->BelongsToCurrentThread()); | 199 DCHECK(task_runner_->BelongsToCurrentThread()); |
188 | 200 |
189 avcodec_flush_buffers(codec_context_.get()); | 201 avcodec_flush_buffers(codec_context_.get()); |
190 state_ = kNormal; | 202 state_ = kNormal; |
191 ResetTimestampState(); | 203 ResetTimestampState(); |
192 task_runner_->PostTask(FROM_HERE, closure); | 204 task_runner_->PostTask(FROM_HERE, closure); |
193 } | 205 } |
194 | 206 |
195 void FFmpegAudioDecoder::Stop() { | 207 void FFmpegAudioDecoder::Stop() { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 // When avcodec_decode_audio4() returns 0 data. | 250 // When avcodec_decode_audio4() returns 0 data. |
239 // kFlushCodec -> kError: | 251 // kFlushCodec -> kError: |
240 // When avcodec_decode_audio4() errors out. | 252 // When avcodec_decode_audio4() errors out. |
241 // (any state) -> kNormal: | 253 // (any state) -> kNormal: |
242 // Any time Reset() is called. | 254 // Any time Reset() is called. |
243 | 255 |
244 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 256 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
245 // occurs with some damaged files. | 257 // occurs with some damaged files. |
246 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { | 258 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { |
247 DVLOG(1) << "Received a buffer without timestamps!"; | 259 DVLOG(1) << "Received a buffer without timestamps!"; |
248 decode_cb.Run(kDecodeError); | 260 decode_cb.Run(kDecodeError, NULL); |
249 return; | 261 return; |
250 } | 262 } |
251 | 263 |
252 if (!buffer->end_of_stream() && !discard_helper_->initialized() && | 264 if (!buffer->end_of_stream() && !discard_helper_->initialized() && |
253 codec_context_->codec_id == AV_CODEC_ID_VORBIS && | 265 codec_context_->codec_id == AV_CODEC_ID_VORBIS && |
254 buffer->timestamp() < base::TimeDelta()) { | 266 buffer->timestamp() < base::TimeDelta()) { |
255 // Dropping frames for negative timestamps as outlined in section A.2 | 267 // Dropping frames for negative timestamps as outlined in section A.2 |
256 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 268 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
257 const int discard_frames = | 269 const int discard_frames = |
258 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); | 270 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); |
259 discard_helper_->Reset(discard_frames); | 271 discard_helper_->Reset(discard_frames); |
260 } | 272 } |
261 | 273 |
| 274 // Transition to kFlushCodec on the first end of stream buffer. |
| 275 if (state_ == kNormal && buffer->end_of_stream()) { |
| 276 state_ = kFlushCodec; |
| 277 } |
| 278 |
262 if (!FFmpegDecode(buffer)) { | 279 if (!FFmpegDecode(buffer)) { |
263 state_ = kError; | 280 state_ = kError; |
264 decode_cb.Run(kDecodeError); | 281 decode_cb.Run(kDecodeError, NULL); |
265 return; | 282 return; |
266 } | 283 } |
267 | 284 |
268 if (buffer->end_of_stream()) { | 285 if (queued_audio_.empty()) { |
269 state_ = kDecodeFinished; | 286 if (state_ == kFlushCodec) { |
270 output_cb_.Run(AudioBuffer::CreateEOSBuffer()); | 287 DCHECK(buffer->end_of_stream()); |
| 288 state_ = kDecodeFinished; |
| 289 decode_cb.Run(kOk, AudioBuffer::CreateEOSBuffer()); |
| 290 return; |
| 291 } |
| 292 |
| 293 decode_cb.Run(kNotEnoughData, NULL); |
| 294 return; |
271 } | 295 } |
272 | 296 |
273 decode_cb.Run(kOk); | 297 decode_cb.Run(kOk, queued_audio_.front()); |
| 298 queued_audio_.pop_front(); |
274 } | 299 } |
275 | 300 |
276 bool FFmpegAudioDecoder::FFmpegDecode( | 301 bool FFmpegAudioDecoder::FFmpegDecode( |
277 const scoped_refptr<DecoderBuffer>& buffer) { | 302 const scoped_refptr<DecoderBuffer>& buffer) { |
| 303 DCHECK(queued_audio_.empty()); |
| 304 |
278 AVPacket packet; | 305 AVPacket packet; |
279 av_init_packet(&packet); | 306 av_init_packet(&packet); |
280 if (buffer->end_of_stream()) { | 307 if (buffer->end_of_stream()) { |
281 packet.data = NULL; | 308 packet.data = NULL; |
282 packet.size = 0; | 309 packet.size = 0; |
283 } else { | 310 } else { |
284 packet.data = const_cast<uint8*>(buffer->data()); | 311 packet.data = const_cast<uint8*>(buffer->data()); |
285 packet.size = buffer->data_size(); | 312 packet.size = buffer->data_size(); |
286 } | 313 } |
287 | 314 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 << ", Sample Format: " << av_frame_->format << " vs " | 355 << ", Sample Format: " << av_frame_->format << " vs " |
329 << av_sample_format_; | 356 << av_sample_format_; |
330 | 357 |
331 if (config_.codec() == kCodecAAC && | 358 if (config_.codec() == kCodecAAC && |
332 av_frame_->sample_rate == 2 * config_.samples_per_second()) { | 359 av_frame_->sample_rate == 2 * config_.samples_per_second()) { |
333 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used." | 360 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used." |
334 << " Please use mp4a.40.5 instead of mp4a.40.2 in" | 361 << " Please use mp4a.40.5 instead of mp4a.40.2 in" |
335 << " the mimetype."; | 362 << " the mimetype."; |
336 } | 363 } |
337 // This is an unrecoverable error, so bail out. | 364 // This is an unrecoverable error, so bail out. |
| 365 queued_audio_.clear(); |
338 av_frame_unref(av_frame_.get()); | 366 av_frame_unref(av_frame_.get()); |
339 return false; | 367 return false; |
340 } | 368 } |
341 | 369 |
342 // Get the AudioBuffer that the data was decoded into. Adjust the number | 370 // Get the AudioBuffer that the data was decoded into. Adjust the number |
343 // of frames, in case fewer than requested were actually decoded. | 371 // of frames, in case fewer than requested were actually decoded. |
344 output = reinterpret_cast<AudioBuffer*>( | 372 output = reinterpret_cast<AudioBuffer*>( |
345 av_buffer_get_opaque(av_frame_->buf[0])); | 373 av_buffer_get_opaque(av_frame_->buf[0])); |
346 | 374 |
347 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), | 375 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), |
348 output->channel_count()); | 376 output->channel_count()); |
349 const int unread_frames = output->frame_count() - av_frame_->nb_samples; | 377 const int unread_frames = output->frame_count() - av_frame_->nb_samples; |
350 DCHECK_GE(unread_frames, 0); | 378 DCHECK_GE(unread_frames, 0); |
351 if (unread_frames > 0) | 379 if (unread_frames > 0) |
352 output->TrimEnd(unread_frames); | 380 output->TrimEnd(unread_frames); |
353 av_frame_unref(av_frame_.get()); | 381 av_frame_unref(av_frame_.get()); |
354 } | 382 } |
355 | 383 |
356 // WARNING: |av_frame_| no longer has valid data at this point. | 384 // WARNING: |av_frame_| no longer has valid data at this point. |
357 const int decoded_frames = frame_decoded ? output->frame_count() : 0; | 385 const int decoded_frames = frame_decoded ? output->frame_count() : 0; |
358 if (IsEndOfStream(result, decoded_frames, buffer)) { | 386 if (IsEndOfStream(result, decoded_frames, buffer)) { |
359 DCHECK_EQ(packet.size, 0); | 387 DCHECK_EQ(packet.size, 0); |
360 output_cb_.Run(AudioBuffer::CreateEOSBuffer()); | 388 queued_audio_.push_back(AudioBuffer::CreateEOSBuffer()); |
361 } else if (discard_helper_->ProcessBuffers(buffer, output)) { | 389 } else if (discard_helper_->ProcessBuffers(buffer, output)) { |
362 output_cb_.Run(output); | 390 queued_audio_.push_back(output); |
363 } | 391 } |
364 } while (packet.size > 0); | 392 } while (packet.size > 0); |
365 | 393 |
366 return true; | 394 return true; |
367 } | 395 } |
368 | 396 |
369 void FFmpegAudioDecoder::ReleaseFFmpegResources() { | 397 void FFmpegAudioDecoder::ReleaseFFmpegResources() { |
370 codec_context_.reset(); | 398 codec_context_.reset(); |
371 av_frame_.reset(); | 399 av_frame_.reset(); |
372 } | 400 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 | 453 |
426 ResetTimestampState(); | 454 ResetTimestampState(); |
427 return true; | 455 return true; |
428 } | 456 } |
429 | 457 |
430 void FFmpegAudioDecoder::ResetTimestampState() { | 458 void FFmpegAudioDecoder::ResetTimestampState() { |
431 discard_helper_->Reset(config_.codec_delay()); | 459 discard_helper_->Reset(config_.codec_delay()); |
432 } | 460 } |
433 | 461 |
434 } // namespace media | 462 } // namespace media |
OLD | NEW |