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/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 | 21 |
22 namespace media { | 22 namespace media { |
23 | 23 |
24 // Helper structure for managing multiple decoded audio frames per packet. | 24 // Helper structure for managing multiple decoded audio frames per packet. |
25 struct QueuedAudioBuffer { | 25 struct QueuedAudioBuffer { |
26 AudioDecoder::Status status; | 26 AudioDecoder::Status status; |
27 scoped_refptr<DataBuffer> buffer; | 27 scoped_refptr<DataBuffer> buffer; |
28 }; | 28 }; |
29 | 29 |
30 // Returns true if the decode result was end of stream. | 30 // Returns true if the decode result was end of stream. |
31 static inline bool IsEndOfStream(int result, int decoded_size, | 31 static inline bool end_of_stream(int result, int decoded_size, |
scherkus (not reviewing)
2013/06/22 00:09:28
revert this change
| |
32 const scoped_refptr<DecoderBuffer>& input) { | 32 const scoped_refptr<DecoderBuffer>& input) { |
33 // Three conditions to meet to declare end of stream for this decoder: | 33 // Three conditions to meet to declare end of stream for this decoder: |
34 // 1. FFmpeg didn't read anything. | 34 // 1. FFmpeg didn't read anything. |
35 // 2. FFmpeg didn't output anything. | 35 // 2. FFmpeg didn't output anything. |
36 // 3. An end of stream buffer is received. | 36 // 3. An end of stream buffer is received. |
37 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); | 37 return result == 0 && decoded_size == 0 && input->end_of_stream(); |
38 } | 38 } |
39 | 39 |
40 FFmpegAudioDecoder::FFmpegAudioDecoder( | 40 FFmpegAudioDecoder::FFmpegAudioDecoder( |
41 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 41 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
42 : message_loop_(message_loop), | 42 : message_loop_(message_loop), |
43 weak_factory_(this), | 43 weak_factory_(this), |
44 demuxer_stream_(NULL), | 44 demuxer_stream_(NULL), |
45 codec_context_(NULL), | 45 codec_context_(NULL), |
46 bits_per_channel_(0), | 46 bits_per_channel_(0), |
47 channel_layout_(CHANNEL_LAYOUT_NONE), | 47 channel_layout_(CHANNEL_LAYOUT_NONE), |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 queued_audio_.front().status, queued_audio_.front().buffer); | 177 queued_audio_.front().status, queued_audio_.front().buffer); |
178 queued_audio_.pop_front(); | 178 queued_audio_.pop_front(); |
179 return; | 179 return; |
180 } | 180 } |
181 | 181 |
182 DCHECK_EQ(status, DemuxerStream::kOk); | 182 DCHECK_EQ(status, DemuxerStream::kOk); |
183 DCHECK(input.get()); | 183 DCHECK(input.get()); |
184 | 184 |
185 // Make sure we are notified if http://crbug.com/49709 returns. Issue also | 185 // Make sure we are notified if http://crbug.com/49709 returns. Issue also |
186 // occurs with some damaged files. | 186 // occurs with some damaged files. |
187 if (!input->IsEndOfStream() && input->GetTimestamp() == kNoTimestamp() && | 187 if (!input->end_of_stream() && input->timestamp() == kNoTimestamp() && |
188 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { | 188 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) { |
189 DVLOG(1) << "Received a buffer without timestamps!"; | 189 DVLOG(1) << "Received a buffer without timestamps!"; |
190 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 190 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
191 return; | 191 return; |
192 } | 192 } |
193 | 193 |
194 bool is_vorbis = codec_context_->codec_id == AV_CODEC_ID_VORBIS; | 194 bool is_vorbis = codec_context_->codec_id == AV_CODEC_ID_VORBIS; |
195 if (!input->IsEndOfStream()) { | 195 if (!input->end_of_stream()) { |
196 if (last_input_timestamp_ == kNoTimestamp()) { | 196 if (last_input_timestamp_ == kNoTimestamp()) { |
197 if (is_vorbis && (input->GetTimestamp() < base::TimeDelta())) { | 197 if (is_vorbis && (input->timestamp() < base::TimeDelta())) { |
198 // Dropping frames for negative timestamps as outlined in section A.2 | 198 // Dropping frames for negative timestamps as outlined in section A.2 |
199 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html | 199 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
200 int frames_to_drop = floor( | 200 int frames_to_drop = floor( |
201 0.5 + -input->GetTimestamp().InSecondsF() * samples_per_second_); | 201 0.5 + -input->timestamp().InSecondsF() * samples_per_second_); |
202 output_bytes_to_drop_ = bytes_per_frame_ * frames_to_drop; | 202 output_bytes_to_drop_ = bytes_per_frame_ * frames_to_drop; |
203 } else { | 203 } else { |
204 last_input_timestamp_ = input->GetTimestamp(); | 204 last_input_timestamp_ = input->timestamp(); |
205 } | 205 } |
206 } else if (input->GetTimestamp() != kNoTimestamp()) { | 206 } else if (input->timestamp() != kNoTimestamp()) { |
207 if (input->GetTimestamp() < last_input_timestamp_) { | 207 if (input->timestamp() < last_input_timestamp_) { |
208 base::TimeDelta diff = input->GetTimestamp() - last_input_timestamp_; | 208 base::TimeDelta diff = input->timestamp() - last_input_timestamp_; |
209 DVLOG(1) << "Input timestamps are not monotonically increasing! " | 209 DVLOG(1) << "Input timestamps are not monotonically increasing! " |
210 << " ts " << input->GetTimestamp().InMicroseconds() << " us" | 210 << " ts " << input->timestamp().InMicroseconds() << " us" |
211 << " diff " << diff.InMicroseconds() << " us"; | 211 << " diff " << diff.InMicroseconds() << " us"; |
212 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 212 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
213 return; | 213 return; |
214 } | 214 } |
215 | 215 |
216 last_input_timestamp_ = input->GetTimestamp(); | 216 last_input_timestamp_ = input->timestamp(); |
217 } | 217 } |
218 } | 218 } |
219 | 219 |
220 RunDecodeLoop(input, false); | 220 RunDecodeLoop(input, false); |
221 | 221 |
222 // We exhausted the provided packet, but it wasn't enough for a frame. Ask | 222 // We exhausted the provided packet, but it wasn't enough for a frame. Ask |
223 // for more data in order to fulfill this read. | 223 // for more data in order to fulfill this read. |
224 if (queued_audio_.empty()) { | 224 if (queued_audio_.empty()) { |
225 ReadFromDemuxerStream(); | 225 ReadFromDemuxerStream(); |
226 return; | 226 return; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); | 334 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); |
335 last_input_timestamp_ = kNoTimestamp(); | 335 last_input_timestamp_ = kNoTimestamp(); |
336 output_bytes_to_drop_ = 0; | 336 output_bytes_to_drop_ = 0; |
337 } | 337 } |
338 | 338 |
339 void FFmpegAudioDecoder::RunDecodeLoop( | 339 void FFmpegAudioDecoder::RunDecodeLoop( |
340 const scoped_refptr<DecoderBuffer>& input, | 340 const scoped_refptr<DecoderBuffer>& input, |
341 bool skip_eos_append) { | 341 bool skip_eos_append) { |
342 AVPacket packet; | 342 AVPacket packet; |
343 av_init_packet(&packet); | 343 av_init_packet(&packet); |
344 if (input->IsEndOfStream()) { | 344 if (input->end_of_stream()) { |
345 packet.data = NULL; | 345 packet.data = NULL; |
346 packet.size = 0; | 346 packet.size = 0; |
347 } else { | 347 } else { |
348 packet.data = const_cast<uint8*>(input->GetData()); | 348 packet.data = const_cast<uint8*>(input->data()); |
349 packet.size = input->GetDataSize(); | 349 packet.size = input->data_size(); |
350 } | 350 } |
351 | 351 |
352 // Each audio packet may contain several frames, so we must call the decoder | 352 // Each audio packet may contain several frames, so we must call the decoder |
353 // until we've exhausted the packet. Regardless of the packet size we always | 353 // until we've exhausted the packet. Regardless of the packet size we always |
354 // want to hand it to the decoder at least once, otherwise we would end up | 354 // want to hand it to the decoder at least once, otherwise we would end up |
355 // skipping end of stream packets since they have a size of zero. | 355 // skipping end of stream packets since they have a size of zero. |
356 do { | 356 do { |
357 // Reset frame to default values. | 357 // Reset frame to default values. |
358 avcodec_get_frame_defaults(av_frame_); | 358 avcodec_get_frame_defaults(av_frame_); |
359 | 359 |
360 int frame_decoded = 0; | 360 int frame_decoded = 0; |
361 int result = avcodec_decode_audio4( | 361 int result = avcodec_decode_audio4( |
362 codec_context_, av_frame_, &frame_decoded, &packet); | 362 codec_context_, av_frame_, &frame_decoded, &packet); |
363 | 363 |
364 if (result < 0) { | 364 if (result < 0) { |
365 DCHECK(!input->IsEndOfStream()) | 365 DCHECK(!input->end_of_stream()) |
366 << "End of stream buffer produced an error! " | 366 << "End of stream buffer produced an error! " |
367 << "This is quite possibly a bug in the audio decoder not handling " | 367 << "This is quite possibly a bug in the audio decoder not handling " |
368 << "end of stream AVPackets correctly."; | 368 << "end of stream AVPackets correctly."; |
369 | 369 |
370 DLOG(ERROR) | 370 DLOG(ERROR) |
371 << "Error decoding an audio frame with timestamp: " | 371 << "Error decoding an audio frame with timestamp: " |
372 << input->GetTimestamp().InMicroseconds() << " us, duration: " | 372 << input->timestamp().InMicroseconds() << " us, duration: " |
373 << input->GetDuration().InMicroseconds() << " us, packet size: " | 373 << input->duration().InMicroseconds() << " us, packet size: " |
374 << input->GetDataSize() << " bytes"; | 374 << input->data_size() << " bytes"; |
375 | 375 |
376 // TODO(dalecurtis): We should return a kDecodeError here instead: | 376 // TODO(dalecurtis): We should return a kDecodeError here instead: |
377 // http://crbug.com/145276 | 377 // http://crbug.com/145276 |
378 break; | 378 break; |
379 } | 379 } |
380 | 380 |
381 // Update packet size and data pointer in case we need to call the decoder | 381 // Update packet size and data pointer in case we need to call the decoder |
382 // with the remaining bytes from this packet. | 382 // with the remaining bytes from this packet. |
383 packet.size -= result; | 383 packet.size -= result; |
384 packet.data += result; | 384 packet.data += result; |
385 | 385 |
386 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && | 386 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() && |
387 !input->IsEndOfStream()) { | 387 !input->end_of_stream()) { |
388 DCHECK(input->GetTimestamp() != kNoTimestamp()); | 388 DCHECK(input->timestamp() != kNoTimestamp()); |
389 if (output_bytes_to_drop_ > 0) { | 389 if (output_bytes_to_drop_ > 0) { |
390 // Currently Vorbis is the only codec that causes us to drop samples. | 390 // Currently Vorbis is the only codec that causes us to drop samples. |
391 // If we have to drop samples it always means the timeline starts at 0. | 391 // If we have to drop samples it always means the timeline starts at 0. |
392 DCHECK_EQ(codec_context_->codec_id, AV_CODEC_ID_VORBIS); | 392 DCHECK_EQ(codec_context_->codec_id, AV_CODEC_ID_VORBIS); |
393 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | 393 output_timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); |
394 } else { | 394 } else { |
395 output_timestamp_helper_->SetBaseTimestamp(input->GetTimestamp()); | 395 output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); |
396 } | 396 } |
397 } | 397 } |
398 | 398 |
399 int decoded_audio_size = 0; | 399 int decoded_audio_size = 0; |
400 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS | 400 #ifdef CHROMIUM_NO_AVFRAME_CHANNELS |
401 int channels = av_get_channel_layout_nb_channels( | 401 int channels = av_get_channel_layout_nb_channels( |
402 av_frame_->channel_layout); | 402 av_frame_->channel_layout); |
403 #else | 403 #else |
404 int channels = av_frame_->channels; | 404 int channels = av_frame_->channels; |
405 #endif | 405 #endif |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
478 output->writable_data()); | 478 output->writable_data()); |
479 } else { | 479 } else { |
480 output = DataBuffer::CopyFrom( | 480 output = DataBuffer::CopyFrom( |
481 av_frame_->extended_data[0] + start_sample * bytes_per_frame_, | 481 av_frame_->extended_data[0] + start_sample * bytes_per_frame_, |
482 decoded_audio_size); | 482 decoded_audio_size); |
483 } | 483 } |
484 output->set_timestamp(output_timestamp_helper_->GetTimestamp()); | 484 output->set_timestamp(output_timestamp_helper_->GetTimestamp()); |
485 output->set_duration( | 485 output->set_duration( |
486 output_timestamp_helper_->GetDuration(decoded_audio_size)); | 486 output_timestamp_helper_->GetDuration(decoded_audio_size)); |
487 output_timestamp_helper_->AddBytes(decoded_audio_size); | 487 output_timestamp_helper_->AddBytes(decoded_audio_size); |
488 } else if (IsEndOfStream(result, decoded_audio_size, input) && | 488 } else if (end_of_stream(result, decoded_audio_size, input) && |
489 !skip_eos_append) { | 489 !skip_eos_append) { |
490 DCHECK_EQ(packet.size, 0); | 490 DCHECK_EQ(packet.size, 0); |
491 output = DataBuffer::CreateEOSBuffer(); | 491 output = DataBuffer::CreateEOSBuffer(); |
492 } | 492 } |
493 | 493 |
494 if (output.get()) { | 494 if (output.get()) { |
495 QueuedAudioBuffer queue_entry = { kOk, output }; | 495 QueuedAudioBuffer queue_entry = { kOk, output }; |
496 queued_audio_.push_back(queue_entry); | 496 queued_audio_.push_back(queue_entry); |
497 } | 497 } |
498 | 498 |
499 // Decoding finished successfully, update statistics. | 499 // Decoding finished successfully, update statistics. |
500 if (result > 0) { | 500 if (result > 0) { |
501 PipelineStatistics statistics; | 501 PipelineStatistics statistics; |
502 statistics.audio_bytes_decoded = result; | 502 statistics.audio_bytes_decoded = result; |
503 statistics_cb_.Run(statistics); | 503 statistics_cb_.Run(statistics); |
504 } | 504 } |
505 } while (packet.size > 0); | 505 } while (packet.size > 0); |
506 } | 506 } |
507 | 507 |
508 } // namespace media | 508 } // namespace media |
OLD | NEW |