| 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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 return decode_threads; | 53 return decode_threads; |
| 54 } | 54 } |
| 55 | 55 |
| 56 FFmpegVideoDecoder::FFmpegVideoDecoder( | 56 FFmpegVideoDecoder::FFmpegVideoDecoder( |
| 57 const base::Callback<MessageLoop*()>& message_loop_cb) | 57 const base::Callback<MessageLoop*()>& message_loop_cb) |
| 58 : message_loop_factory_cb_(message_loop_cb), | 58 : message_loop_factory_cb_(message_loop_cb), |
| 59 message_loop_(NULL), | 59 message_loop_(NULL), |
| 60 state_(kUninitialized), | 60 state_(kUninitialized), |
| 61 codec_context_(NULL), | 61 codec_context_(NULL), |
| 62 av_frame_(NULL), | 62 av_frame_(NULL), |
| 63 frame_rate_numerator_(0), | |
| 64 frame_rate_denominator_(0), | |
| 65 decryptor_(NULL) { | 63 decryptor_(NULL) { |
| 66 } | 64 } |
| 67 | 65 |
| 68 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, | 66 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, |
| 69 AVFrame* frame) { | 67 AVFrame* frame) { |
| 70 // Don't use |codec_context_| here! With threaded decoding, | 68 // Don't use |codec_context_| here! With threaded decoding, |
| 71 // it will contain unsynchronized width/height/pix_fmt values, | 69 // it will contain unsynchronized width/height/pix_fmt values, |
| 72 // whereas |codec_context| contains the current threads's | 70 // whereas |codec_context| contains the current threads's |
| 73 // updated width/height/pix_fmt, which can change for adaptive | 71 // updated width/height/pix_fmt, which can change for adaptive |
| 74 // content. | 72 // content. |
| 75 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context->pix_fmt); | 73 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context->pix_fmt); |
| 76 if (format == VideoFrame::INVALID) | 74 if (format == VideoFrame::INVALID) |
| 77 return AVERROR(EINVAL); | 75 return AVERROR(EINVAL); |
| 78 DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16); | 76 DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16); |
| 79 | 77 |
| 80 int width = codec_context->width; | 78 int width = codec_context->width; |
| 81 int height = codec_context->height; | 79 int height = codec_context->height; |
| 82 int ret; | 80 int ret; |
| 83 if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) | 81 if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) |
| 84 return ret; | 82 return ret; |
| 85 | 83 |
| 86 scoped_refptr<VideoFrame> video_frame = | 84 scoped_refptr<VideoFrame> video_frame = |
| 87 VideoFrame::CreateFrame(format, width, height, | 85 VideoFrame::CreateFrame(format, width, height, kNoTimestamp()); |
| 88 kNoTimestamp(), kNoTimestamp()); | |
| 89 | 86 |
| 90 for (int i = 0; i < 3; i++) { | 87 for (int i = 0; i < 3; i++) { |
| 91 frame->base[i] = video_frame->data(i); | 88 frame->base[i] = video_frame->data(i); |
| 92 frame->data[i] = video_frame->data(i); | 89 frame->data[i] = video_frame->data(i); |
| 93 frame->linesize[i] = video_frame->stride(i); | 90 frame->linesize[i] = video_frame->stride(i); |
| 94 } | 91 } |
| 95 | 92 |
| 96 frame->opaque = video_frame.release(); | 93 frame->opaque = video_frame.release(); |
| 97 frame->type = FF_BUFFER_TYPE_USER; | 94 frame->type = FF_BUFFER_TYPE_USER; |
| 98 frame->pkt_pts = codec_context->pkt ? codec_context->pkt->pts : | 95 frame->pkt_pts = codec_context->pkt ? codec_context->pkt->pts : |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 | 179 |
| 183 if (avcodec_open2(codec_context_, codec, NULL) < 0) { | 180 if (avcodec_open2(codec_context_, codec, NULL) < 0) { |
| 184 status_cb.Run(PIPELINE_ERROR_DECODE); | 181 status_cb.Run(PIPELINE_ERROR_DECODE); |
| 185 return; | 182 return; |
| 186 } | 183 } |
| 187 | 184 |
| 188 // Success! | 185 // Success! |
| 189 state_ = kNormal; | 186 state_ = kNormal; |
| 190 av_frame_ = avcodec_alloc_frame(); | 187 av_frame_ = avcodec_alloc_frame(); |
| 191 natural_size_ = config.natural_size(); | 188 natural_size_ = config.natural_size(); |
| 192 frame_rate_numerator_ = config.frame_rate_numerator(); | |
| 193 frame_rate_denominator_ = config.frame_rate_denominator(); | |
| 194 status_cb.Run(PIPELINE_OK); | 189 status_cb.Run(PIPELINE_OK); |
| 195 } | 190 } |
| 196 | 191 |
| 197 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { | 192 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { |
| 198 // Complete operation asynchronously on different stack of execution as per | 193 // Complete operation asynchronously on different stack of execution as per |
| 199 // the API contract of VideoDecoder::Read() | 194 // the API contract of VideoDecoder::Read() |
| 200 message_loop_->PostTask(FROM_HERE, base::Bind( | 195 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 201 &FFmpegVideoDecoder::DoRead, this, read_cb)); | 196 &FFmpegVideoDecoder::DoRead, this, read_cb)); |
| 202 } | 197 } |
| 203 | 198 |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 *video_frame = NULL; | 493 *video_frame = NULL; |
| 499 return false; | 494 return false; |
| 500 } | 495 } |
| 501 | 496 |
| 502 if (!av_frame_->opaque) { | 497 if (!av_frame_->opaque) { |
| 503 LOG(ERROR) << "VideoFrame object associated with frame data not set."; | 498 LOG(ERROR) << "VideoFrame object associated with frame data not set."; |
| 504 return false; | 499 return false; |
| 505 } | 500 } |
| 506 *video_frame = static_cast<VideoFrame*>(av_frame_->opaque); | 501 *video_frame = static_cast<VideoFrame*>(av_frame_->opaque); |
| 507 | 502 |
| 508 if (frame_rate_numerator_ == 0) { | |
| 509 // A framerate of zero indicates that no timing information was available | |
| 510 // during initial stream demuxing, and that the framerate should be inferred | |
| 511 // from the first frame's duration. | |
| 512 frame_rate_numerator_ = buffer->GetDuration().InMicroseconds(); | |
| 513 frame_rate_denominator_ = base::Time::kMicrosecondsPerSecond; | |
| 514 } | |
| 515 | |
| 516 // Determine timestamp and calculate the duration based on the repeat | |
| 517 // picture count. According to FFmpeg docs, the total duration can be | |
| 518 // calculated as follows: | |
| 519 // fps = 1 / time_base | |
| 520 // | |
| 521 // duration = (1 / fps) + (repeat_pict) / (2 * fps) | |
| 522 // = (2 + repeat_pict) / (2 * fps) | |
| 523 // = (2 + repeat_pict) / (2 * (1 / time_base)) | |
| 524 DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check. | |
| 525 AVRational doubled_time_base; | |
| 526 doubled_time_base.num = frame_rate_denominator_; | |
| 527 doubled_time_base.den = frame_rate_numerator_ * 2; | |
| 528 | |
| 529 (*video_frame)->SetTimestamp( | 503 (*video_frame)->SetTimestamp( |
| 530 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); | 504 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); |
| 531 (*video_frame)->SetDuration( | |
| 532 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); | |
| 533 | 505 |
| 534 return true; | 506 return true; |
| 535 } | 507 } |
| 536 | 508 |
| 537 void FFmpegVideoDecoder::ReleaseFFmpegResources() { | 509 void FFmpegVideoDecoder::ReleaseFFmpegResources() { |
| 538 if (codec_context_) { | 510 if (codec_context_) { |
| 539 av_free(codec_context_->extradata); | 511 av_free(codec_context_->extradata); |
| 540 avcodec_close(codec_context_); | 512 avcodec_close(codec_context_); |
| 541 av_free(codec_context_); | 513 av_free(codec_context_); |
| 542 codec_context_ = NULL; | 514 codec_context_ = NULL; |
| 543 } | 515 } |
| 544 if (av_frame_) { | 516 if (av_frame_) { |
| 545 av_free(av_frame_); | 517 av_free(av_frame_); |
| 546 av_frame_ = NULL; | 518 av_frame_ = NULL; |
| 547 } | 519 } |
| 548 } | 520 } |
| 549 | 521 |
| 550 } // namespace media | 522 } // namespace media |
| OLD | NEW |