| 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_proxy.h" | 10 #include "base/message_loop_proxy.h" |
| 11 #include "media/base/audio_decoder_config.h" | 11 #include "media/base/audio_decoder_config.h" |
| 12 #include "media/base/data_buffer.h" | 12 #include "media/base/data_buffer.h" |
| 13 #include "media/base/decoder_buffer.h" | 13 #include "media/base/decoder_buffer.h" |
| 14 #include "media/base/demuxer.h" | 14 #include "media/base/demuxer.h" |
| 15 #include "media/base/pipeline.h" | 15 #include "media/base/pipeline.h" |
| 16 #include "media/ffmpeg/ffmpeg_common.h" | 16 #include "media/ffmpeg/ffmpeg_common.h" |
| 17 #include "media/filters/ffmpeg_glue.h" | 17 #include "media/filters/ffmpeg_glue.h" |
| 18 | 18 |
| 19 namespace media { | 19 namespace media { |
| 20 | 20 |
| 21 // Helper structure for managing multiple decoded audio frames per packet. |
| 22 struct QueuedAudioBuffer { |
| 23 AudioDecoder::Status status; |
| 24 scoped_refptr<Buffer> buffer; |
| 25 }; |
| 26 |
| 21 // Returns true if the decode result was end of stream. | 27 // Returns true if the decode result was end of stream. |
| 22 static inline bool IsEndOfStream(int result, int decoded_size, Buffer* input) { | 28 static inline bool IsEndOfStream(int result, int decoded_size, Buffer* input) { |
| 23 // Three conditions to meet to declare end of stream for this decoder: | 29 // Three conditions to meet to declare end of stream for this decoder: |
| 24 // 1. FFmpeg didn't read anything. | 30 // 1. FFmpeg didn't read anything. |
| 25 // 2. FFmpeg didn't output anything. | 31 // 2. FFmpeg didn't output anything. |
| 26 // 3. An end of stream buffer is received. | 32 // 3. An end of stream buffer is received. |
| 27 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); | 33 return result == 0 && decoded_size == 0 && input->IsEndOfStream(); |
| 28 } | 34 } |
| 29 | 35 |
| 30 FFmpegAudioDecoder::FFmpegAudioDecoder( | 36 FFmpegAudioDecoder::FFmpegAudioDecoder( |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 bytes_per_frame_ = codec_context_->channels * bits_per_channel_ / 8; | 150 bytes_per_frame_ = codec_context_->channels * bits_per_channel_ / 8; |
| 145 status_cb.Run(PIPELINE_OK); | 151 status_cb.Run(PIPELINE_OK); |
| 146 } | 152 } |
| 147 | 153 |
| 148 void FFmpegAudioDecoder::DoReset(const base::Closure& closure) { | 154 void FFmpegAudioDecoder::DoReset(const base::Closure& closure) { |
| 149 avcodec_flush_buffers(codec_context_); | 155 avcodec_flush_buffers(codec_context_); |
| 150 output_timestamp_base_ = kNoTimestamp(); | 156 output_timestamp_base_ = kNoTimestamp(); |
| 151 total_frames_decoded_ = 0; | 157 total_frames_decoded_ = 0; |
| 152 last_input_timestamp_ = kNoTimestamp(); | 158 last_input_timestamp_ = kNoTimestamp(); |
| 153 output_bytes_to_drop_ = 0; | 159 output_bytes_to_drop_ = 0; |
| 160 queued_audio_.clear(); |
| 154 closure.Run(); | 161 closure.Run(); |
| 155 } | 162 } |
| 156 | 163 |
| 157 void FFmpegAudioDecoder::DoRead(const ReadCB& read_cb) { | 164 void FFmpegAudioDecoder::DoRead(const ReadCB& read_cb) { |
| 158 DCHECK(message_loop_->BelongsToCurrentThread()); | 165 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 159 DCHECK(!read_cb.is_null()); | 166 DCHECK(!read_cb.is_null()); |
| 160 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 167 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| 161 | 168 |
| 162 read_cb_ = read_cb; | 169 read_cb_ = read_cb; |
| 163 ReadFromDemuxerStream(); | 170 |
| 171 // If we don't have any queued audio from the last packet we decoded, ask for |
| 172 // more data from the demuxer to satisfy this read. |
| 173 if (queued_audio_.empty()) { |
| 174 ReadFromDemuxerStream(); |
| 175 return; |
| 176 } |
| 177 |
| 178 base::ResetAndReturn(&read_cb_).Run( |
| 179 queued_audio_.front().status, queued_audio_.front().buffer); |
| 180 queued_audio_.pop_front(); |
| 164 } | 181 } |
| 165 | 182 |
| 166 void FFmpegAudioDecoder::DoDecodeBuffer( | 183 void FFmpegAudioDecoder::DoDecodeBuffer( |
| 167 DemuxerStream::Status status, | 184 DemuxerStream::Status status, |
| 168 const scoped_refptr<DecoderBuffer>& input) { | 185 const scoped_refptr<DecoderBuffer>& input) { |
| 169 DCHECK(message_loop_->BelongsToCurrentThread()); | 186 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 170 DCHECK(!read_cb_.is_null()); | 187 DCHECK(!read_cb_.is_null()); |
| 188 DCHECK(queued_audio_.empty()); |
| 171 | 189 |
| 172 if (status != DemuxerStream::kOk) { | 190 if (status != DemuxerStream::kOk) { |
| 173 DCHECK(!input); | 191 DCHECK(!input); |
| 174 // TODO(acolwell): Add support for reinitializing the decoder when | 192 // TODO(acolwell): Add support for reinitializing the decoder when |
| 175 // |status| == kConfigChanged. For now we just trigger a decode error. | 193 // |status| == kConfigChanged. For now we just trigger a decode error. |
| 176 AudioDecoder::Status decoder_status = | 194 AudioDecoder::Status decoder_status = |
| 177 (status == DemuxerStream::kAborted) ? kAborted : kDecodeError; | 195 (status == DemuxerStream::kAborted) ? kAborted : kDecodeError; |
| 178 base::ResetAndReturn(&read_cb_).Run(decoder_status, NULL); | 196 base::ResetAndReturn(&read_cb_).Run(decoder_status, NULL); |
| 179 return; | 197 return; |
| 180 } | 198 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 | 230 |
| 213 last_input_timestamp_ = input->GetTimestamp(); | 231 last_input_timestamp_ = input->GetTimestamp(); |
| 214 } | 232 } |
| 215 } | 233 } |
| 216 | 234 |
| 217 AVPacket packet; | 235 AVPacket packet; |
| 218 av_init_packet(&packet); | 236 av_init_packet(&packet); |
| 219 packet.data = const_cast<uint8*>(input->GetData()); | 237 packet.data = const_cast<uint8*>(input->GetData()); |
| 220 packet.size = input->GetDataSize(); | 238 packet.size = input->GetDataSize(); |
| 221 | 239 |
| 222 PipelineStatistics statistics; | 240 // Each audio packet may contain several frames, so we must call the decoder |
| 223 statistics.audio_bytes_decoded = input->GetDataSize(); | 241 // until we've exhausted the packet. Regardless of the packet size we always |
| 242 // want to hand it to the decoder at least once, otherwise we would end up |
| 243 // skipping end of stream packets since they have a size of zero. |
| 244 do { |
| 245 // Reset frame to default values. |
| 246 avcodec_get_frame_defaults(av_frame_); |
| 224 | 247 |
| 225 // Reset frame to default values. | 248 int frame_decoded = 0; |
| 226 avcodec_get_frame_defaults(av_frame_); | 249 int result = avcodec_decode_audio4( |
| 250 codec_context_, av_frame_, &frame_decoded, &packet); |
| 227 | 251 |
| 228 int frame_decoded = 0; | 252 if (result < 0) { |
| 229 int result = avcodec_decode_audio4( | 253 DCHECK(!input->IsEndOfStream()) |
| 230 codec_context_, av_frame_, &frame_decoded, &packet); | 254 << "End of stream buffer produced an error! " |
| 255 << "This is quite possibly a bug in the audio decoder not handling " |
| 256 << "end of stream AVPackets correctly."; |
| 231 | 257 |
| 232 if (result < 0) { | 258 DLOG(ERROR) |
| 233 DCHECK(!input->IsEndOfStream()) | 259 << "Error decoding an audio frame with timestamp: " |
| 234 << "End of stream buffer produced an error! " | 260 << input->GetTimestamp().InMicroseconds() << " us, duration: " |
| 235 << "This is quite possibly a bug in the audio decoder not handling " | 261 << input->GetDuration().InMicroseconds() << " us, packet size: " |
| 236 << "end of stream AVPackets correctly."; | 262 << input->GetDataSize() << " bytes"; |
| 237 | 263 |
| 238 DLOG(ERROR) << "Error decoding an audio frame with timestamp: " | 264 // TODO(dalecurtis): We should return a kDecodeError here instead: |
| 239 << input->GetTimestamp().InMicroseconds() << " us, duration: " | 265 // http://crbug.com/145276 |
| 240 << input->GetDuration().InMicroseconds() << " us, packet size: " | 266 break; |
| 241 << input->GetDataSize() << " bytes"; | 267 } |
| 242 | 268 |
| 269 // Update packet size and data pointer in case we need to call the decoder |
| 270 // with the remaining bytes from this packet. |
| 271 packet.size -= result; |
| 272 packet.data += result; |
| 273 |
| 274 if (output_timestamp_base_ == kNoTimestamp() && !input->IsEndOfStream()) { |
| 275 DCHECK(input->GetTimestamp() != kNoTimestamp()); |
| 276 if (output_bytes_to_drop_ > 0) { |
| 277 // Currently Vorbis is the only codec that causes us to drop samples. |
| 278 // If we have to drop samples it always means the timeline starts at 0. |
| 279 DCHECK(is_vorbis); |
| 280 output_timestamp_base_ = base::TimeDelta(); |
| 281 } else { |
| 282 output_timestamp_base_ = input->GetTimestamp(); |
| 283 } |
| 284 } |
| 285 |
| 286 const uint8* decoded_audio_data = NULL; |
| 287 int decoded_audio_size = 0; |
| 288 if (frame_decoded) { |
| 289 int output_sample_rate = av_frame_->sample_rate; |
| 290 if (output_sample_rate != samples_per_second_) { |
| 291 DLOG(ERROR) << "Output sample rate (" << output_sample_rate |
| 292 << ") doesn't match expected rate " << samples_per_second_; |
| 293 |
| 294 // This is an unrecoverable error, so bail out. |
| 295 QueuedAudioBuffer queue_entry = { kDecodeError, NULL }; |
| 296 queued_audio_.push_back(queue_entry); |
| 297 break; |
| 298 } |
| 299 |
| 300 decoded_audio_data = av_frame_->data[0]; |
| 301 decoded_audio_size = av_samples_get_buffer_size( |
| 302 NULL, codec_context_->channels, av_frame_->nb_samples, |
| 303 codec_context_->sample_fmt, 1); |
| 304 } |
| 305 |
| 306 scoped_refptr<DataBuffer> output; |
| 307 |
| 308 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { |
| 309 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); |
| 310 decoded_audio_data += dropped_size; |
| 311 decoded_audio_size -= dropped_size; |
| 312 output_bytes_to_drop_ -= dropped_size; |
| 313 } |
| 314 |
| 315 if (decoded_audio_size > 0) { |
| 316 DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) |
| 317 << "Decoder didn't output full frames"; |
| 318 |
| 319 // Copy the audio samples into an output buffer. |
| 320 output = new DataBuffer(decoded_audio_size); |
| 321 output->SetDataSize(decoded_audio_size); |
| 322 uint8* data = output->GetWritableData(); |
| 323 memcpy(data, decoded_audio_data, decoded_audio_size); |
| 324 |
| 325 base::TimeDelta timestamp = GetNextOutputTimestamp(); |
| 326 total_frames_decoded_ += decoded_audio_size / bytes_per_frame_; |
| 327 |
| 328 output->SetTimestamp(timestamp); |
| 329 output->SetDuration(GetNextOutputTimestamp() - timestamp); |
| 330 } else if (IsEndOfStream(result, decoded_audio_size, input)) { |
| 331 DCHECK_EQ(packet.size, 0); |
| 332 // Create an end of stream output buffer. |
| 333 output = new DataBuffer(0); |
| 334 } |
| 335 |
| 336 if (output) { |
| 337 QueuedAudioBuffer queue_entry = { kOk, output }; |
| 338 queued_audio_.push_back(queue_entry); |
| 339 } |
| 340 |
| 341 // Decoding finished successfully, update statistics. |
| 342 if (result > 0) { |
| 343 PipelineStatistics statistics; |
| 344 statistics.audio_bytes_decoded = result; |
| 345 statistics_cb_.Run(statistics); |
| 346 } |
| 347 } while (packet.size > 0); |
| 348 |
| 349 // We exhausted the provided packet, but it wasn't enough for a frame. Ask |
| 350 // for more data in order to fulfill this read. |
| 351 if (queued_audio_.empty()) { |
| 243 ReadFromDemuxerStream(); | 352 ReadFromDemuxerStream(); |
| 244 return; | 353 return; |
| 245 } | 354 } |
| 246 | 355 |
| 247 if (result > 0) | 356 // Execute callback to return the first frame we decoded. |
| 248 DCHECK_EQ(result, input->GetDataSize()); | 357 base::ResetAndReturn(&read_cb_).Run( |
| 249 | 358 queued_audio_.front().status, queued_audio_.front().buffer); |
| 250 if (output_timestamp_base_ == kNoTimestamp() && !input->IsEndOfStream()) { | 359 queued_audio_.pop_front(); |
| 251 DCHECK(input->GetTimestamp() != kNoTimestamp()); | |
| 252 if (output_bytes_to_drop_ > 0) { | |
| 253 // Currently Vorbis is the only codec that causes us to drop samples. | |
| 254 // If we have to drop samples it always means the timeline starts at 0. | |
| 255 DCHECK(is_vorbis); | |
| 256 output_timestamp_base_ = base::TimeDelta(); | |
| 257 } else { | |
| 258 output_timestamp_base_ = input->GetTimestamp(); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 const uint8* decoded_audio_data = NULL; | |
| 263 int decoded_audio_size = 0; | |
| 264 if (frame_decoded) { | |
| 265 int output_sample_rate = av_frame_->sample_rate; | |
| 266 if (output_sample_rate != samples_per_second_) { | |
| 267 DLOG(ERROR) << "Output sample rate (" << output_sample_rate | |
| 268 << ") doesn't match expected rate " << samples_per_second_; | |
| 269 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | |
| 270 return; | |
| 271 } | |
| 272 | |
| 273 decoded_audio_data = av_frame_->data[0]; | |
| 274 decoded_audio_size = av_samples_get_buffer_size( | |
| 275 NULL, codec_context_->channels, av_frame_->nb_samples, | |
| 276 codec_context_->sample_fmt, 1); | |
| 277 } | |
| 278 | |
| 279 scoped_refptr<DataBuffer> output; | |
| 280 | |
| 281 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { | |
| 282 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); | |
| 283 decoded_audio_data += dropped_size; | |
| 284 decoded_audio_size -= dropped_size; | |
| 285 output_bytes_to_drop_ -= dropped_size; | |
| 286 } | |
| 287 | |
| 288 if (decoded_audio_size > 0) { | |
| 289 DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0) | |
| 290 << "Decoder didn't output full frames"; | |
| 291 | |
| 292 // Copy the audio samples into an output buffer. | |
| 293 output = new DataBuffer(decoded_audio_size); | |
| 294 output->SetDataSize(decoded_audio_size); | |
| 295 uint8* data = output->GetWritableData(); | |
| 296 memcpy(data, decoded_audio_data, decoded_audio_size); | |
| 297 | |
| 298 base::TimeDelta timestamp = GetNextOutputTimestamp(); | |
| 299 total_frames_decoded_ += decoded_audio_size / bytes_per_frame_; | |
| 300 | |
| 301 output->SetTimestamp(timestamp); | |
| 302 output->SetDuration(GetNextOutputTimestamp() - timestamp); | |
| 303 } else if (IsEndOfStream(result, decoded_audio_size, input)) { | |
| 304 // Create an end of stream output buffer. | |
| 305 output = new DataBuffer(0); | |
| 306 } | |
| 307 | |
| 308 // Decoding finished successfully, update stats and execute callback. | |
| 309 statistics_cb_.Run(statistics); | |
| 310 | |
| 311 if (!output) { | |
| 312 ReadFromDemuxerStream(); | |
| 313 return; | |
| 314 } | |
| 315 base::ResetAndReturn(&read_cb_).Run(kOk, output); | |
| 316 } | 360 } |
| 317 | 361 |
| 318 void FFmpegAudioDecoder::ReadFromDemuxerStream() { | 362 void FFmpegAudioDecoder::ReadFromDemuxerStream() { |
| 319 DCHECK(!read_cb_.is_null()); | 363 DCHECK(!read_cb_.is_null()); |
| 320 | 364 |
| 321 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); | 365 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); |
| 322 } | 366 } |
| 323 | 367 |
| 324 void FFmpegAudioDecoder::DecodeBuffer( | 368 void FFmpegAudioDecoder::DecodeBuffer( |
| 325 DemuxerStream::Status status, | 369 DemuxerStream::Status status, |
| 326 const scoped_refptr<DecoderBuffer>& buffer) { | 370 const scoped_refptr<DecoderBuffer>& buffer) { |
| 327 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; | 371 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; |
| 328 | 372 |
| 329 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read | 373 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read |
| 330 // callback on the same execution stack so we can get rid of forced task post. | 374 // callback on the same execution stack so we can get rid of forced task post. |
| 331 message_loop_->PostTask(FROM_HERE, base::Bind( | 375 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 332 &FFmpegAudioDecoder::DoDecodeBuffer, this, status, buffer)); | 376 &FFmpegAudioDecoder::DoDecodeBuffer, this, status, buffer)); |
| 333 } | 377 } |
| 334 | 378 |
| 335 base::TimeDelta FFmpegAudioDecoder::GetNextOutputTimestamp() const { | 379 base::TimeDelta FFmpegAudioDecoder::GetNextOutputTimestamp() const { |
| 336 DCHECK(output_timestamp_base_ != kNoTimestamp()); | 380 DCHECK(output_timestamp_base_ != kNoTimestamp()); |
| 337 double decoded_us = (total_frames_decoded_ / samples_per_second_) * | 381 double decoded_us = (total_frames_decoded_ / samples_per_second_) * |
| 338 base::Time::kMicrosecondsPerSecond; | 382 base::Time::kMicrosecondsPerSecond; |
| 339 return output_timestamp_base_ + base::TimeDelta::FromMicroseconds(decoded_us); | 383 return output_timestamp_base_ + base::TimeDelta::FromMicroseconds(decoded_us); |
| 340 } | 384 } |
| 341 } // namespace media | 385 } // namespace media |
| OLD | NEW |