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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
52 const base::Callback<MessageLoop*()>& message_loop_cb) | 52 const base::Callback<MessageLoop*()>& message_loop_cb) |
53 : message_loop_factory_cb_(message_loop_cb), | 53 : message_loop_factory_cb_(message_loop_cb), |
54 message_loop_(NULL), | 54 message_loop_(NULL), |
55 state_(kUninitialized), | 55 state_(kUninitialized), |
56 codec_context_(NULL), | 56 codec_context_(NULL), |
57 av_frame_(NULL), | 57 av_frame_(NULL), |
58 frame_rate_numerator_(0), | 58 frame_rate_numerator_(0), |
59 frame_rate_denominator_(0) { | 59 frame_rate_denominator_(0) { |
60 } | 60 } |
61 | 61 |
62 int FFmpegVideoDecoder::AllocBuffer(VideoFrame **ptr) | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
no doco, no unittest, single call-site ==> inline
| |
63 { | |
64 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); | |
65 int w = codec_context_->width; | |
66 int h = codec_context_->height; | |
67 int ret, strides[4]; | |
68 avcodec_align_dimensions(codec_context_, &w, &h); | |
69 if ((ret = av_image_check_size(w, h, 0, NULL)) < 0) | |
70 return ret; | |
71 if ((ret = av_image_fill_linesizes(strides, codec_context_->pix_fmt, w)) < 0) | |
72 return ret; | |
73 VideoFrame *buf = new VideoFrame::VideoFrame(format, codec_context_->width, | |
74 codec_context_->height, | |
75 kNoTimestamp(), kNoTimestamp()); | |
76 if ((ret = buf->AllocateAlignedWithStrides(strides, h)) < 0) { | |
77 free(buf); | |
78 return ret; | |
79 } | |
80 *ptr = buf; | |
81 return 0; | |
82 } | |
83 | |
84 int FFmpegVideoDecoder::GetVideoBuffer(AVFrame *frame) | |
85 { | |
86 VideoFrame *buf; | |
87 int ret = AllocBuffer(&buf); | |
88 if (ret < 0) | |
89 return ret; | |
90 | |
91 buf->AddRef(); | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
AddRef() is almost never the right thing to call.
| |
92 frame->opaque = buf; | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
This sort of ascii-art alignment isn't adding anyt
| |
93 frame->type = FF_BUFFER_TYPE_USER; | |
94 frame->pkt_pts = codec_context_->pkt ? codec_context_->pkt->pts : AV_NOP TS_VALUE; | |
95 frame->width = codec_context_->width; | |
96 frame->height = codec_context_->height; | |
97 frame->format = codec_context_->pix_fmt; | |
98 | |
99 for (int i = 0; i < (buf->format() == media::VideoFrame::RGB32 ? 1 : 3); i++) { | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
I think you're assuming either RGB32 or YV12/YV16.
| |
100 frame->base[i] = | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
Un-style-ish. Repeat buf->data(i)
| |
101 frame->data[i] = buf->data(i); | |
102 frame->linesize[i] = buf->stride(i); | |
103 } | |
104 | |
105 return 0; | |
106 } | |
107 | |
108 static int c_GetVideoBuffer(AVCodecContext *s, AVFrame *frame) | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
the "c_" prefix is un-style-ish.
| |
109 { | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
opening braces go on previous line (here and elsew
| |
110 FFmpegVideoDecoder *vd = (FFmpegVideoDecoder *) s->opaque; | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
This isn't used until l.114, so it can be done the
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
use static_cast<>() instead of c-style casts
(here
| |
111 if (!(s->flags & CODEC_FLAG_EMU_EDGE)) { | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
When will this be true?
(can you drop the "then" c
| |
112 return avcodec_default_get_buffer(s, frame); | |
113 } else { | |
114 return vd->GetVideoBuffer(frame); | |
115 } | |
116 } | |
117 | |
118 static void c_ReleaseVideoBuffer(AVCodecContext *s, AVFrame *frame) | |
119 { | |
120 if (!(s->flags & CODEC_FLAG_EMU_EDGE)) { | |
121 avcodec_default_release_buffer(s, frame); | |
122 } else { | |
123 VideoFrame *buf = (media::VideoFrame *) frame->opaque; | |
124 buf->Release(); | |
125 memset(frame->data, 0, sizeof(frame->data)); | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
why? (also, do you really mean to only set the fir
| |
126 frame->opaque = NULL; | |
127 } | |
128 } | |
129 | |
62 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, | 130 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, |
63 const PipelineStatusCB& status_cb, | 131 const PipelineStatusCB& status_cb, |
64 const StatisticsCB& statistics_cb) { | 132 const StatisticsCB& statistics_cb) { |
65 if (!message_loop_) { | 133 if (!message_loop_) { |
66 message_loop_ = message_loop_factory_cb_.Run(); | 134 message_loop_ = message_loop_factory_cb_.Run(); |
67 message_loop_factory_cb_.Reset(); | 135 message_loop_factory_cb_.Reset(); |
68 | 136 |
69 message_loop_->PostTask(FROM_HERE, base::Bind( | 137 message_loop_->PostTask(FROM_HERE, base::Bind( |
70 &FFmpegVideoDecoder::Initialize, this, | 138 &FFmpegVideoDecoder::Initialize, this, |
71 stream, status_cb, statistics_cb)); | 139 stream, status_cb, statistics_cb)); |
(...skipping 23 matching lines...) Expand all Loading... | |
95 | 163 |
96 // Initialize AVCodecContext structure. | 164 // Initialize AVCodecContext structure. |
97 codec_context_ = avcodec_alloc_context(); | 165 codec_context_ = avcodec_alloc_context(); |
98 VideoDecoderConfigToAVCodecContext(config, codec_context_); | 166 VideoDecoderConfigToAVCodecContext(config, codec_context_); |
99 | 167 |
100 // Enable motion vector search (potentially slow), strong deblocking filter | 168 // Enable motion vector search (potentially slow), strong deblocking filter |
101 // for damaged macroblocks, and set our error detection sensitivity. | 169 // for damaged macroblocks, and set our error detection sensitivity. |
102 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; | 170 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; |
103 codec_context_->err_recognition = AV_EF_CAREFUL; | 171 codec_context_->err_recognition = AV_EF_CAREFUL; |
104 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); | 172 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); |
173 codec_context_->opaque = this; | |
174 codec_context_->flags |= CODEC_FLAG_EMU_EDGE; | |
175 codec_context_->get_buffer = c_GetVideoBuffer; | |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
Depending on ffmpeg dispatches these callbacks, it
| |
176 codec_context_->release_buffer = c_ReleaseVideoBuffer; | |
105 | 177 |
106 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); | 178 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); |
107 if (!codec) { | 179 if (!codec) { |
108 status_cb.Run(PIPELINE_ERROR_DECODE); | 180 status_cb.Run(PIPELINE_ERROR_DECODE); |
109 return; | 181 return; |
110 } | 182 } |
111 | 183 |
112 if (avcodec_open2(codec_context_, codec, NULL) < 0) { | 184 if (avcodec_open2(codec_context_, codec, NULL) < 0) { |
113 status_cb.Run(PIPELINE_ERROR_DECODE); | 185 status_cb.Run(PIPELINE_ERROR_DECODE); |
114 return; | 186 return; |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 // The decoder is in a bad state and not decoding correctly. | 421 // The decoder is in a bad state and not decoding correctly. |
350 // Checking for NULL avoids a crash in CopyPlane(). | 422 // Checking for NULL avoids a crash in CopyPlane(). |
351 if (!av_frame_->data[VideoFrame::kYPlane] || | 423 if (!av_frame_->data[VideoFrame::kYPlane] || |
352 !av_frame_->data[VideoFrame::kUPlane] || | 424 !av_frame_->data[VideoFrame::kUPlane] || |
353 !av_frame_->data[VideoFrame::kVPlane]) { | 425 !av_frame_->data[VideoFrame::kVPlane]) { |
354 LOG(ERROR) << "Video frame was produced yet has invalid frame data."; | 426 LOG(ERROR) << "Video frame was produced yet has invalid frame data."; |
355 *video_frame = NULL; | 427 *video_frame = NULL; |
356 return false; | 428 return false; |
357 } | 429 } |
358 | 430 |
359 // We've got a frame! Make sure we have a place to store it. | 431 if (!(codec_context_->flags & CODEC_FLAG_EMU_EDGE)) { |
Ami GONE FROM CHROMIUM
2012/05/26 22:52:34
Drop this test here and elsewhere?
| |
360 *video_frame = AllocateVideoFrame(); | 432 // We've got a frame! Make sure we have a place to store it. |
361 if (!(*video_frame)) { | 433 *video_frame = AllocateVideoFrame(); |
362 LOG(ERROR) << "Failed to allocate video frame"; | 434 if (!(*video_frame)) { |
363 return false; | 435 LOG(ERROR) << "Failed to allocate video frame"; |
436 return false; | |
437 } | |
438 } else { | |
439 *video_frame = (media::VideoFrame *) av_frame_->opaque; | |
364 } | 440 } |
365 | 441 |
366 // Determine timestamp and calculate the duration based on the repeat picture | 442 // Determine timestamp and calculate the duration based on the repeat picture |
367 // count. According to FFmpeg docs, the total duration can be calculated as | 443 // count. According to FFmpeg docs, the total duration can be calculated as |
368 // follows: | 444 // follows: |
369 // fps = 1 / time_base | 445 // fps = 1 / time_base |
370 // | 446 // |
371 // duration = (1 / fps) + (repeat_pict) / (2 * fps) | 447 // duration = (1 / fps) + (repeat_pict) / (2 * fps) |
372 // = (2 + repeat_pict) / (2 * fps) | 448 // = (2 + repeat_pict) / (2 * fps) |
373 // = (2 + repeat_pict) / (2 * (1 / time_base)) | 449 // = (2 + repeat_pict) / (2 * (1 / time_base)) |
374 DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check. | 450 DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check. |
375 AVRational doubled_time_base; | 451 AVRational doubled_time_base; |
376 doubled_time_base.num = frame_rate_denominator_; | 452 doubled_time_base.num = frame_rate_denominator_; |
377 doubled_time_base.den = frame_rate_numerator_ * 2; | 453 doubled_time_base.den = frame_rate_numerator_ * 2; |
378 | 454 |
379 (*video_frame)->SetTimestamp( | 455 (*video_frame)->SetTimestamp( |
380 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); | 456 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); |
381 (*video_frame)->SetDuration( | 457 (*video_frame)->SetDuration( |
382 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); | 458 ConvertFromTimeBase(doubled_time_base, 2 + av_frame_->repeat_pict)); |
383 | 459 |
384 // Copy the frame data since FFmpeg reuses internal buffers for AVFrame | 460 if (!(codec_context_->flags & CODEC_FLAG_EMU_EDGE)) { |
385 // output, meaning the data is only valid until the next | 461 // Copy the frame data since FFmpeg reuses internal buffers for AVFrame |
386 // avcodec_decode_video() call. | 462 // output, meaning the data is only valid until the next |
387 int y_rows = codec_context_->height; | 463 // avcodec_decode_video() call. |
388 int uv_rows = codec_context_->height; | 464 int y_rows = codec_context_->height; |
389 if (codec_context_->pix_fmt == PIX_FMT_YUV420P) { | 465 int uv_rows = codec_context_->height; |
390 uv_rows /= 2; | 466 if (codec_context_->pix_fmt == PIX_FMT_YUV420P) { |
467 uv_rows /= 2; | |
468 } | |
469 | |
470 CopyYPlane(av_frame_->data[0], av_frame_->linesize[0], y_rows, *video_frame) ; | |
471 CopyUPlane(av_frame_->data[1], av_frame_->linesize[1], uv_rows, *video_frame ); | |
472 CopyVPlane(av_frame_->data[2], av_frame_->linesize[2], uv_rows, *video_frame ); | |
391 } | 473 } |
392 | 474 |
393 CopyYPlane(av_frame_->data[0], av_frame_->linesize[0], y_rows, *video_frame); | |
394 CopyUPlane(av_frame_->data[1], av_frame_->linesize[1], uv_rows, *video_frame); | |
395 CopyVPlane(av_frame_->data[2], av_frame_->linesize[2], uv_rows, *video_frame); | |
396 | |
397 return true; | 475 return true; |
398 } | 476 } |
399 | 477 |
400 void FFmpegVideoDecoder::DeliverFrame( | 478 void FFmpegVideoDecoder::DeliverFrame( |
401 const scoped_refptr<VideoFrame>& video_frame) { | 479 const scoped_refptr<VideoFrame>& video_frame) { |
402 // Reset the callback before running to protect against reentrancy. | 480 // Reset the callback before running to protect against reentrancy. |
403 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | 481 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); |
404 } | 482 } |
405 | 483 |
406 void FFmpegVideoDecoder::ReleaseFFmpegResources() { | 484 void FFmpegVideoDecoder::ReleaseFFmpegResources() { |
(...skipping 12 matching lines...) Expand all Loading... | |
419 scoped_refptr<VideoFrame> FFmpegVideoDecoder::AllocateVideoFrame() { | 497 scoped_refptr<VideoFrame> FFmpegVideoDecoder::AllocateVideoFrame() { |
420 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); | 498 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context_->pix_fmt); |
421 size_t width = codec_context_->width; | 499 size_t width = codec_context_->width; |
422 size_t height = codec_context_->height; | 500 size_t height = codec_context_->height; |
423 | 501 |
424 return VideoFrame::CreateFrame(format, width, height, | 502 return VideoFrame::CreateFrame(format, width, height, |
425 kNoTimestamp(), kNoTimestamp()); | 503 kNoTimestamp(), kNoTimestamp()); |
426 } | 504 } |
427 | 505 |
428 } // namespace media | 506 } // namespace media |
OLD | NEW |