Chromium Code Reviews| 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/vpx_video_decoder.h" | 5 #include "media/filters/vpx_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" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/message_loop/message_loop_proxy.h" | 15 #include "base/message_loop/message_loop_proxy.h" |
| 16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/sys_byteorder.h" | 17 #include "base/sys_byteorder.h" |
| 18 #include "media/base/bind_to_loop.h" | 18 #include "media/base/bind_to_loop.h" |
| 19 #include "media/base/decoder_buffer.h" | 19 #include "media/base/decoder_buffer.h" |
| 20 #include "media/base/demuxer_stream.h" | 20 #include "media/base/demuxer_stream.h" |
| 21 #include "media/base/limits.h" | |
| 21 #include "media/base/media_switches.h" | 22 #include "media/base/media_switches.h" |
| 22 #include "media/base/pipeline.h" | 23 #include "media/base/pipeline.h" |
| 23 #include "media/base/video_decoder_config.h" | 24 #include "media/base/video_decoder_config.h" |
| 24 #include "media/base/video_frame.h" | 25 #include "media/base/video_frame.h" |
| 25 #include "media/base/video_util.h" | 26 #include "media/base/video_util.h" |
| 26 | 27 |
| 27 // Include libvpx header files. | 28 // Include libvpx header files. |
| 28 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide | 29 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide |
| 29 // backwards compatibility for legacy applications using the library. | 30 // backwards compatibility for legacy applications using the library. |
| 30 #define VPX_CODEC_DISABLE_COMPAT 1 | 31 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 31 extern "C" { | 32 extern "C" { |
| 32 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" | 33 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" |
| 34 #include "third_party/libvpx/source/libvpx/vpx/vpx_external_frame_buffer.h" | |
| 33 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" | 35 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
| 34 } | 36 } |
| 35 | 37 |
| 36 namespace media { | 38 namespace media { |
| 37 | 39 |
| 38 // Always try to use three threads for video decoding. There is little reason | 40 // Always try to use three threads for video decoding. There is little reason |
| 39 // not to since current day CPUs tend to be multi-core and we measured | 41 // not to since current day CPUs tend to be multi-core and we measured |
| 40 // performance benefits on older machines such as P4s with hyperthreading. | 42 // performance benefits on older machines such as P4s with hyperthreading. |
| 41 static const int kDecodeThreads = 2; | 43 static const int kDecodeThreads = 2; |
| 42 static const int kMaxDecodeThreads = 16; | 44 static const int kMaxDecodeThreads = 16; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 60 } | 62 } |
| 61 | 63 |
| 62 return decode_threads; | 64 return decode_threads; |
| 63 } | 65 } |
| 64 | 66 |
| 65 decode_threads = std::max(decode_threads, 0); | 67 decode_threads = std::max(decode_threads, 0); |
| 66 decode_threads = std::min(decode_threads, kMaxDecodeThreads); | 68 decode_threads = std::min(decode_threads, kMaxDecodeThreads); |
| 67 return decode_threads; | 69 return decode_threads; |
| 68 } | 70 } |
| 69 | 71 |
| 72 // Maximum number of frame buffers allowed to be used by libvpx for VP9 | |
| 73 // decoding. 8 (libvpx reference buffers) + 1 (work buffer) + kMaxVideoFrames ( | |
| 74 // jitter buffers). | |
| 75 static const int kVP9MaxFrameBuffers = 9 + limits::kMaxVideoFrames; | |
|
acolwell GONE FROM CHROMIUM
2013/12/17 19:07:03
Shouldn't libvpx advertise the minimum required nu
vignesh
2013/12/18 18:01:02
Done.
| |
| 76 | |
| 77 // Minimum libvpx decoder ABI version required to support direct rendering. | |
| 78 static const int kLibvpxMinABIExternalBuffers = 6; | |
| 79 | |
| 70 VpxVideoDecoder::VpxVideoDecoder( | 80 VpxVideoDecoder::VpxVideoDecoder( |
| 71 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 81 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
| 72 : message_loop_(message_loop), | 82 : message_loop_(message_loop), |
| 73 weak_factory_(this), | 83 weak_factory_(this), |
| 74 state_(kUninitialized), | 84 state_(kUninitialized), |
| 75 vpx_codec_(NULL), | 85 vpx_codec_(NULL), |
| 76 vpx_codec_alpha_(NULL) { | 86 vpx_codec_alpha_(NULL), |
| 87 frame_buffers_(NULL) { | |
| 77 } | 88 } |
| 78 | 89 |
| 79 VpxVideoDecoder::~VpxVideoDecoder() { | 90 VpxVideoDecoder::~VpxVideoDecoder() { |
| 80 DCHECK_EQ(kUninitialized, state_); | 91 DCHECK_EQ(kUninitialized, state_); |
| 81 CloseDecoder(); | 92 CloseDecoder(); |
| 82 } | 93 } |
| 83 | 94 |
| 84 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, | 95 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| 85 const PipelineStatusCB& status_cb) { | 96 const PipelineStatusCB& status_cb) { |
| 86 DCHECK(message_loop_->BelongsToCurrentThread()); | 97 DCHECK(message_loop_->BelongsToCurrentThread()); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 117 &vpx_config, | 128 &vpx_config, |
| 118 0); | 129 0); |
| 119 if (status != VPX_CODEC_OK) { | 130 if (status != VPX_CODEC_OK) { |
| 120 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; | 131 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; |
| 121 delete context; | 132 delete context; |
| 122 return NULL; | 133 return NULL; |
| 123 } | 134 } |
| 124 return context; | 135 return context; |
| 125 } | 136 } |
| 126 | 137 |
| 138 int32 VpxVideoDecoder::ReallocVP9FrameBuffer(void *user_priv, size_t new_size, | |
| 139 vpx_codec_frame_buffer *fb) { | |
| 140 if (!fb) | |
| 141 return -1; | |
| 142 if (fb->data) | |
| 143 delete[] fb->data; | |
|
acolwell GONE FROM CHROMIUM
2013/12/17 19:07:03
This is not safe. libvpx only knows when it no lon
vignesh
2013/12/18 18:01:02
The way libvpx designed to do this is under the fo
| |
| 144 fb->data = new uint8[new_size]; | |
| 145 if (!fb->data) { | |
| 146 fb->size = 0; | |
| 147 return -1; | |
| 148 } | |
| 149 fb->size = new_size; | |
| 150 return VPX_CODEC_OK; | |
| 151 } | |
| 152 | |
| 127 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { | 153 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { |
| 128 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 154 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 129 bool can_handle = false; | 155 bool can_handle = false; |
| 130 if (config.codec() == kCodecVP9) | 156 if (config.codec() == kCodecVP9) |
| 131 can_handle = true; | 157 can_handle = true; |
| 132 if (!cmd_line->HasSwitch(switches::kDisableVp8AlphaPlayback) && | 158 if (!cmd_line->HasSwitch(switches::kDisableVp8AlphaPlayback) && |
| 133 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { | 159 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { |
| 134 can_handle = true; | 160 can_handle = true; |
| 135 } | 161 } |
| 136 if (!can_handle) | 162 if (!can_handle) |
| 137 return false; | 163 return false; |
| 138 | 164 |
| 139 CloseDecoder(); | 165 CloseDecoder(); |
| 140 | 166 |
| 141 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); | 167 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); |
| 142 if (!vpx_codec_) | 168 if (!vpx_codec_) |
| 143 return false; | 169 return false; |
| 144 | 170 |
| 171 // We use our own buffers for VP9 so that there is no need to copy data after | |
| 172 // decoding. | |
| 173 if (config.codec() == kCodecVP9 && | |
| 174 VPX_DECODER_ABI_VERSION >= kLibvpxMinABIExternalBuffers) { | |
| 175 frame_buffers_ = new vpx_codec_frame_buffer[kVP9MaxFrameBuffers](); | |
| 176 if (vpx_codec_set_frame_buffers(vpx_codec_, | |
| 177 frame_buffers_, | |
| 178 kVP9MaxFrameBuffers, | |
| 179 VpxVideoDecoder::ReallocVP9FrameBuffer, | |
| 180 NULL)) { | |
| 181 LOG(ERROR) << "Failed to configure external buffers."; | |
| 182 return false; | |
| 183 } | |
| 184 } | |
| 185 | |
| 145 if (config.format() == VideoFrame::YV12A) { | 186 if (config.format() == VideoFrame::YV12A) { |
| 146 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); | 187 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); |
| 147 if (!vpx_codec_alpha_) | 188 if (!vpx_codec_alpha_) |
| 148 return false; | 189 return false; |
| 149 } | 190 } |
| 150 | 191 |
| 151 return true; | 192 return true; |
| 152 } | 193 } |
| 153 | 194 |
| 154 void VpxVideoDecoder::CloseDecoder() { | 195 void VpxVideoDecoder::CloseDecoder() { |
| 155 if (vpx_codec_) { | 196 if (vpx_codec_) { |
| 156 vpx_codec_destroy(vpx_codec_); | 197 vpx_codec_destroy(vpx_codec_); |
| 157 delete vpx_codec_; | 198 delete vpx_codec_; |
| 158 vpx_codec_ = NULL; | 199 vpx_codec_ = NULL; |
| 200 if (frame_buffers_) { | |
|
acolwell GONE FROM CHROMIUM
2013/12/17 19:07:03
This is not safe. It assumes that all VideoFrames
vignesh
2013/12/18 18:01:02
Addressing this issue by introducing MemoryPool cl
| |
| 201 for (int i = 0; i < kVP9MaxFrameBuffers; i++) | |
| 202 delete[] frame_buffers_[i].data; | |
| 203 delete[] frame_buffers_; | |
| 204 frame_buffers_ = NULL; | |
| 205 } | |
| 159 } | 206 } |
| 160 if (vpx_codec_alpha_) { | 207 if (vpx_codec_alpha_) { |
| 161 vpx_codec_destroy(vpx_codec_alpha_); | 208 vpx_codec_destroy(vpx_codec_alpha_); |
| 162 delete vpx_codec_alpha_; | 209 delete vpx_codec_alpha_; |
| 163 vpx_codec_alpha_ = NULL; | 210 vpx_codec_alpha_ = NULL; |
| 164 } | 211 } |
| 165 } | 212 } |
| 166 | 213 |
| 167 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 214 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 168 const DecodeCB& decode_cb) { | 215 const DecodeCB& decode_cb) { |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 | 382 |
| 336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, | 383 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, |
| 337 const struct vpx_image* vpx_image_alpha, | 384 const struct vpx_image* vpx_image_alpha, |
| 338 scoped_refptr<VideoFrame>* video_frame) { | 385 scoped_refptr<VideoFrame>* video_frame) { |
| 339 CHECK(vpx_image); | 386 CHECK(vpx_image); |
| 340 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || | 387 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || |
| 341 vpx_image->fmt == VPX_IMG_FMT_YV12); | 388 vpx_image->fmt == VPX_IMG_FMT_YV12); |
| 342 | 389 |
| 343 gfx::Size size(vpx_image->d_w, vpx_image->d_h); | 390 gfx::Size size(vpx_image->d_w, vpx_image->d_h); |
| 344 | 391 |
| 392 if (!vpx_codec_alpha_ && | |
|
acolwell GONE FROM CHROMIUM
2013/12/17 19:07:03
Why isn't alpha included in the 0-copy code path?
vignesh
2013/12/18 18:01:02
libvpx takes in external buffers only for VP9 as o
| |
| 393 VPX_DECODER_ABI_VERSION >= kLibvpxMinABIExternalBuffers) { | |
| 394 *video_frame = VideoFrame::WrapExternalYuvData( | |
| 395 VideoFrame::YV12, | |
| 396 size, gfx::Rect(size), config_.natural_size(), | |
| 397 vpx_image->stride[VPX_PLANE_Y], | |
| 398 vpx_image->stride[VPX_PLANE_U], | |
| 399 vpx_image->stride[VPX_PLANE_V], | |
| 400 vpx_image->planes[VPX_PLANE_Y], | |
| 401 vpx_image->planes[VPX_PLANE_U], | |
| 402 vpx_image->planes[VPX_PLANE_V], | |
| 403 kNoTimestamp(), | |
| 404 base::Closure()); | |
| 405 return; | |
| 406 } | |
| 407 | |
| 345 *video_frame = frame_pool_.CreateFrame( | 408 *video_frame = frame_pool_.CreateFrame( |
| 346 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, | 409 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, |
| 347 size, | 410 size, |
| 348 gfx::Rect(size), | 411 gfx::Rect(size), |
| 349 config_.natural_size(), | 412 config_.natural_size(), |
| 350 kNoTimestamp()); | 413 kNoTimestamp()); |
| 351 | 414 |
| 352 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], | 415 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], |
| 353 vpx_image->stride[VPX_PLANE_Y], | 416 vpx_image->stride[VPX_PLANE_Y], |
| 354 vpx_image->d_h, | 417 vpx_image->d_h, |
| 355 video_frame->get()); | 418 video_frame->get()); |
| 356 CopyUPlane(vpx_image->planes[VPX_PLANE_U], | 419 CopyUPlane(vpx_image->planes[VPX_PLANE_U], |
| 357 vpx_image->stride[VPX_PLANE_U], | 420 vpx_image->stride[VPX_PLANE_U], |
| 358 (vpx_image->d_h + 1) / 2, | 421 (vpx_image->d_h + 1) / 2, |
| 359 video_frame->get()); | 422 video_frame->get()); |
| 360 CopyVPlane(vpx_image->planes[VPX_PLANE_V], | 423 CopyVPlane(vpx_image->planes[VPX_PLANE_V], |
| 361 vpx_image->stride[VPX_PLANE_V], | 424 vpx_image->stride[VPX_PLANE_V], |
| 362 (vpx_image->d_h + 1) / 2, | 425 (vpx_image->d_h + 1) / 2, |
| 363 video_frame->get()); | 426 video_frame->get()); |
| 364 if (!vpx_codec_alpha_) | |
| 365 return; | |
| 366 if (!vpx_image_alpha) { | 427 if (!vpx_image_alpha) { |
| 367 MakeOpaqueAPlane( | 428 MakeOpaqueAPlane( |
| 368 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); | 429 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); |
| 369 return; | 430 return; |
| 370 } | 431 } |
| 371 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | 432 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
| 372 vpx_image->stride[VPX_PLANE_Y], | 433 vpx_image->stride[VPX_PLANE_Y], |
| 373 vpx_image->d_h, | 434 vpx_image->d_h, |
| 374 video_frame->get()); | 435 video_frame->get()); |
| 375 } | 436 } |
| 376 | 437 |
| 377 } // namespace media | 438 } // namespace media |
| OLD | NEW |