| 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_video_decoder.h" | 5 #include "media/filters/ffmpeg_video_decoder.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 void FFmpegVideoDecoder::ReadFromDemuxerStream() { | 275 void FFmpegVideoDecoder::ReadFromDemuxerStream() { |
| 276 DCHECK_NE(state_, kUninitialized); | 276 DCHECK_NE(state_, kUninitialized); |
| 277 DCHECK_NE(state_, kDecodeFinished); | 277 DCHECK_NE(state_, kDecodeFinished); |
| 278 DCHECK(!read_cb_.is_null()); | 278 DCHECK(!read_cb_.is_null()); |
| 279 | 279 |
| 280 demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecryptOrDecodeBuffer, | 280 demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::DecryptOrDecodeBuffer, |
| 281 this)); | 281 this)); |
| 282 } | 282 } |
| 283 | 283 |
| 284 void FFmpegVideoDecoder::DecryptOrDecodeBuffer( | 284 void FFmpegVideoDecoder::DecryptOrDecodeBuffer( |
| 285 DemuxerStream::Status status, |
| 285 const scoped_refptr<DecoderBuffer>& buffer) { | 286 const scoped_refptr<DecoderBuffer>& buffer) { |
| 287 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; |
| 286 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read | 288 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read |
| 287 // callback on the same execution stack so we can get rid of forced task post. | 289 // callback on the same execution stack so we can get rid of forced task post. |
| 288 message_loop_->PostTask(FROM_HERE, base::Bind( | 290 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 289 &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this, buffer)); | 291 &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this, status, buffer)); |
| 290 } | 292 } |
| 291 | 293 |
| 292 void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer( | 294 void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer( |
| 295 DemuxerStream::Status status, |
| 293 const scoped_refptr<DecoderBuffer>& buffer) { | 296 const scoped_refptr<DecoderBuffer>& buffer) { |
| 294 DCHECK_EQ(MessageLoop::current(), message_loop_); | 297 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 295 DCHECK_NE(state_, kUninitialized); | 298 DCHECK_NE(state_, kUninitialized); |
| 296 DCHECK_NE(state_, kDecodeFinished); | 299 DCHECK_NE(state_, kDecodeFinished); |
| 297 DCHECK(!read_cb_.is_null()); | 300 DCHECK(!read_cb_.is_null()); |
| 298 | 301 |
| 299 if (!reset_cb_.is_null()) { | 302 if (!reset_cb_.is_null()) { |
| 300 DeliverFrame(NULL); | 303 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); |
| 301 DoReset(); | 304 DoReset(); |
| 302 return; | 305 return; |
| 303 } | 306 } |
| 304 | 307 |
| 305 if (!buffer) { | 308 if (status != DemuxerStream::kOk) { |
| 306 DeliverFrame(NULL); | 309 DecoderStatus decoder_status = |
| 310 (status == DemuxerStream::kAborted) ? kOk : kDecodeError; |
| 311 base::ResetAndReturn(&read_cb_).Run(decoder_status, NULL); |
| 307 return; | 312 return; |
| 308 } | 313 } |
| 309 | 314 |
| 315 DCHECK_EQ(status, DemuxerStream::kOk); |
| 316 |
| 310 if (buffer->GetDecryptConfig() && buffer->GetDataSize()) { | 317 if (buffer->GetDecryptConfig() && buffer->GetDataSize()) { |
| 311 decryptor_->Decrypt(buffer, | 318 decryptor_->Decrypt(buffer, |
| 312 base::Bind(&FFmpegVideoDecoder::BufferDecrypted, this)); | 319 base::Bind(&FFmpegVideoDecoder::BufferDecrypted, this)); |
| 313 return; | 320 return; |
| 314 } | 321 } |
| 315 | 322 |
| 316 DecodeBuffer(buffer); | 323 DecodeBuffer(buffer); |
| 317 } | 324 } |
| 318 | 325 |
| 319 void FFmpegVideoDecoder::BufferDecrypted( | 326 void FFmpegVideoDecoder::BufferDecrypted( |
| 320 Decryptor::DecryptStatus decrypt_status, | 327 Decryptor::DecryptStatus decrypt_status, |
| 321 const scoped_refptr<DecoderBuffer>& buffer) { | 328 const scoped_refptr<DecoderBuffer>& buffer) { |
| 322 message_loop_->PostTask(FROM_HERE, base::Bind( | 329 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 323 &FFmpegVideoDecoder::DoBufferDecrypted, this, decrypt_status, buffer)); | 330 &FFmpegVideoDecoder::DoBufferDecrypted, this, decrypt_status, buffer)); |
| 324 } | 331 } |
| 325 | 332 |
| 326 void FFmpegVideoDecoder::DoBufferDecrypted( | 333 void FFmpegVideoDecoder::DoBufferDecrypted( |
| 327 Decryptor::DecryptStatus decrypt_status, | 334 Decryptor::DecryptStatus decrypt_status, |
| 328 const scoped_refptr<DecoderBuffer>& buffer) { | 335 const scoped_refptr<DecoderBuffer>& buffer) { |
| 329 DCHECK_EQ(MessageLoop::current(), message_loop_); | 336 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 330 DCHECK_NE(state_, kUninitialized); | 337 DCHECK_NE(state_, kUninitialized); |
| 331 DCHECK_NE(state_, kDecodeFinished); | 338 DCHECK_NE(state_, kDecodeFinished); |
| 332 DCHECK(!read_cb_.is_null()); | 339 DCHECK(!read_cb_.is_null()); |
| 333 | 340 |
| 334 if (!reset_cb_.is_null()) { | 341 if (!reset_cb_.is_null()) { |
| 335 DeliverFrame(NULL); | 342 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); |
| 336 DoReset(); | 343 DoReset(); |
| 337 return; | 344 return; |
| 338 } | 345 } |
| 339 | 346 |
| 340 if (decrypt_status == Decryptor::kError) { | 347 if (decrypt_status == Decryptor::kError) { |
| 341 state_ = kDecodeFinished; | 348 state_ = kDecodeFinished; |
| 342 base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL); | 349 base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL); |
| 343 return; | 350 return; |
| 344 } | 351 } |
| 345 | 352 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 PipelineStatistics statistics; | 408 PipelineStatistics statistics; |
| 402 statistics.video_bytes_decoded = buffer->GetDataSize(); | 409 statistics.video_bytes_decoded = buffer->GetDataSize(); |
| 403 statistics_cb_.Run(statistics); | 410 statistics_cb_.Run(statistics); |
| 404 } | 411 } |
| 405 | 412 |
| 406 // If we didn't get a frame then we've either completely finished decoding or | 413 // If we didn't get a frame then we've either completely finished decoding or |
| 407 // we need more data. | 414 // we need more data. |
| 408 if (!video_frame) { | 415 if (!video_frame) { |
| 409 if (state_ == kFlushCodec) { | 416 if (state_ == kFlushCodec) { |
| 410 state_ = kDecodeFinished; | 417 state_ = kDecodeFinished; |
| 411 DeliverFrame(VideoFrame::CreateEmptyFrame()); | 418 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
| 412 return; | 419 return; |
| 413 } | 420 } |
| 414 | 421 |
| 415 ReadFromDemuxerStream(); | 422 ReadFromDemuxerStream(); |
| 416 return; | 423 return; |
| 417 } | 424 } |
| 418 | 425 |
| 419 DeliverFrame(video_frame); | 426 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); |
| 420 } | 427 } |
| 421 | 428 |
| 422 bool FFmpegVideoDecoder::Decode( | 429 bool FFmpegVideoDecoder::Decode( |
| 423 const scoped_refptr<DecoderBuffer>& buffer, | 430 const scoped_refptr<DecoderBuffer>& buffer, |
| 424 scoped_refptr<VideoFrame>* video_frame) { | 431 scoped_refptr<VideoFrame>* video_frame) { |
| 425 DCHECK(video_frame); | 432 DCHECK(video_frame); |
| 426 | 433 |
| 427 // Create a packet for input data. | 434 // Create a packet for input data. |
| 428 // Due to FFmpeg API changes we no longer have const read-only pointers. | 435 // Due to FFmpeg API changes we no longer have const read-only pointers. |
| 429 AVPacket packet; | 436 AVPacket packet; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 doubled_time_base.den = frame_rate_numerator_ * 2; | 511 doubled_time_base.den = frame_rate_numerator_ * 2; |
| 505 | 512 |
| 506 (*video_frame)->SetTimestamp( | 513 (*video_frame)->SetTimestamp( |
| 507 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); | 514 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); |
| 508 (*video_frame)->SetDuration( | 515 (*video_frame)->SetDuration( |
| 509 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); | 516 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); |
| 510 | 517 |
| 511 return true; | 518 return true; |
| 512 } | 519 } |
| 513 | 520 |
| 514 void FFmpegVideoDecoder::DeliverFrame( | |
| 515 const scoped_refptr<VideoFrame>& video_frame) { | |
| 516 // Reset the callback before running to protect against reentrancy. | |
| 517 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | |
| 518 } | |
| 519 | |
| 520 void FFmpegVideoDecoder::ReleaseFFmpegResources() { | 521 void FFmpegVideoDecoder::ReleaseFFmpegResources() { |
| 521 if (codec_context_) { | 522 if (codec_context_) { |
| 522 av_free(codec_context_->extradata); | 523 av_free(codec_context_->extradata); |
| 523 avcodec_close(codec_context_); | 524 avcodec_close(codec_context_); |
| 524 av_free(codec_context_); | 525 av_free(codec_context_); |
| 525 codec_context_ = NULL; | 526 codec_context_ = NULL; |
| 526 } | 527 } |
| 527 if (av_frame_) { | 528 if (av_frame_) { |
| 528 av_free(av_frame_); | 529 av_free(av_frame_); |
| 529 av_frame_ = NULL; | 530 av_frame_ = NULL; |
| 530 } | 531 } |
| 531 } | 532 } |
| 532 | 533 |
| 533 } // namespace media | 534 } // namespace media |
| OLD | NEW |