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 3 // found in the LICENSE file. 4 5 #include "media/filters/vpx_video_decoder.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 11 #include "base/bind.h" 12 #include "base/callback_helpers.h" 13 #include "base/command_line.h" 14 #include "base/location.h" 15 #include "base/logging.h" 16 #include "base/single_thread_task_runner.h" 17 #include "base/stl_util.h" 18 #include "base/strings/string_number_conversions.h" 19 #include "base/sys_byteorder.h" 20 #include "media/base/bind_to_current_loop.h" 21 #include "media/base/decoder_buffer.h" 22 #include "media/base/demuxer_stream.h" 23 #include "media/base/limits.h" 24 #include "media/base/media_switches.h" 25 #include "media/base/pipeline.h" 26 #include "media/base/video_decoder_config.h" 27 #include "media/base/video_frame.h" 28 #include "media/base/video_util.h" 29 30 // Include libvpx header files. 31 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide 32 // backwards compatibility for legacy applications using the library. 33 #define VPX_CODEC_DISABLE_COMPAT 1 34 extern "C" { 35 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" 36 #include "third_party/libvpx/source/libvpx/vpx/vpx_frame_buffer.h" 37 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" 38 } 39 40 namespace media { 41 42 // Always try to use three threads for video decoding. There is little reason 43 // not to since current day CPUs tend to be multi-core and we measured 44 // performance benefits on older machines such as P4s with hyperthreading. 45 static const int kDecodeThreads = 2; 46 static const int kMaxDecodeThreads = 16; 47 48 // Returns the number of threads. 49 static int GetThreadCount(const VideoDecoderConfig& config) { 50 // Refer to http://crbug.com/93932 for tsan suppressions on decoding. 51 int decode_threads = kDecodeThreads; 52 53 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 54 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); 55 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) { 56 if (config.codec() == kCodecVP9) { 57 // For VP9 decode when using the default thread count, increase the number 58 // of decode threads to equal the maximum number of tiles possible for 59 // higher resolution streams. 60 if (config.coded_size().width() >= 2048) 61 decode_threads = 8; 62 else if (config.coded_size().width() >= 1024) 63 decode_threads = 4; 64 } 65 66 return decode_threads; 67 } 68 69 decode_threads = std::max(decode_threads, 0); 70 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 71 return decode_threads; 72 } 73 74 class VpxVideoDecoder::MemoryPool 75 : public base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool> { 76 public: 77 MemoryPool(); 78 79 // Callback that will be called by libvpx when it needs a frame buffer. 80 // Parameters: 81 // |user_priv| Private data passed to libvpx (pointer to memory pool). 82 // |min_size| Minimum size needed by libvpx to decompress the next frame. 83 // |fb| Pointer to the frame buffer to update. 84 // Returns 0 on success. Returns < 0 on failure. 85 static int32 GetVP9FrameBuffer(void* user_priv, size_t min_size, 86 vpx_codec_frame_buffer* fb); 87 88 // Callback that will be called by libvpx when the frame buffer is no longer 89 // being used by libvpx. Parameters: 90 // |user_priv| Private data passed to libvpx (pointer to memory pool). 91 // |fb| Pointer to the frame buffer that's being released. 92 static int32 ReleaseVP9FrameBuffer(void *user_priv, 93 vpx_codec_frame_buffer *fb); 94 95 // Generates a "no_longer_needed" closure that holds a reference 96 // to this pool. 97 base::Closure CreateFrameCallback(void* fb_priv_data); 98 99 private: 100 friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>; 101 ~MemoryPool(); 102 103 // Reference counted frame buffers used for VP9 decoding. Reference counting 104 // is done manually because both chromium and libvpx has to release this 105 // before a buffer can be re-used. 106 struct VP9FrameBuffer { 107 VP9FrameBuffer() : ref_cnt(0) {} 108 std::vector<uint8> data; 109 uint32 ref_cnt; 110 }; 111 112 // Gets the next available frame buffer for use by libvpx. 113 VP9FrameBuffer* GetFreeFrameBuffer(size_t min_size); 114 115 // Method that gets called when a VideoFrame that references this pool gets 116 // destroyed. 117 void OnVideoFrameDestroyed(VP9FrameBuffer* frame_buffer); 118 119 // Frame buffers to be used by libvpx for VP9 Decoding. 120 std::vector<VP9FrameBuffer*> frame_buffers_; 121 122 DISALLOW_COPY_AND_ASSIGN(MemoryPool); 123 }; 124 125 VpxVideoDecoder::MemoryPool::MemoryPool() {} 126 127 VpxVideoDecoder::MemoryPool::~MemoryPool() { 128 STLDeleteElements(&frame_buffers_); 129 } 130 131 VpxVideoDecoder::MemoryPool::VP9FrameBuffer* 132 VpxVideoDecoder::MemoryPool::GetFreeFrameBuffer(size_t min_size) { 133 // Check if a free frame buffer exists. 134 size_t i = 0; 135 for (; i < frame_buffers_.size(); ++i) { 136 if (frame_buffers_[i]->ref_cnt == 0) 137 break; 138 } 139 140 if (i == frame_buffers_.size()) { 141 // Create a new frame buffer. 142 frame_buffers_.push_back(new VP9FrameBuffer()); 143 } 144 145 // Resize the frame buffer if necessary. 146 if (frame_buffers_[i]->data.size() < min_size) 147 frame_buffers_[i]->data.resize(min_size); 148 return frame_buffers_[i]; 149 } 150 151 int32 VpxVideoDecoder::MemoryPool::GetVP9FrameBuffer( 152 void* user_priv, size_t min_size, vpx_codec_frame_buffer* fb) { 153 DCHECK(user_priv); 154 DCHECK(fb); 155 156 VpxVideoDecoder::MemoryPool* memory_pool = 157 static_cast<VpxVideoDecoder::MemoryPool*>(user_priv); 158 159 VP9FrameBuffer* fb_to_use = memory_pool->GetFreeFrameBuffer(min_size); 160 if (fb_to_use == NULL) 161 return -1; 162 163 fb->data = &fb_to_use->data[0]; 164 fb->size = fb_to_use->data.size(); 165 ++fb_to_use->ref_cnt; 166 167 // Set the frame buffer's private data to point at the external frame buffer. 168 fb->priv = static_cast<void*>(fb_to_use); 169 return 0; 170 } 171 172 int32 VpxVideoDecoder::MemoryPool::ReleaseVP9FrameBuffer( 173 void *user_priv, vpx_codec_frame_buffer *fb) { 174 VP9FrameBuffer* frame_buffer = static_cast<VP9FrameBuffer*>(fb->priv); 175 --frame_buffer->ref_cnt; 176 return 0; 177 } 178 179 base::Closure VpxVideoDecoder::MemoryPool::CreateFrameCallback( 180 void* fb_priv_data) { 181 VP9FrameBuffer* frame_buffer = static_cast<VP9FrameBuffer*>(fb_priv_data); 182 ++frame_buffer->ref_cnt; 183 return BindToCurrentLoop( 184 base::Bind(&MemoryPool::OnVideoFrameDestroyed, this, 185 frame_buffer)); 186 } 187 188 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed( 189 VP9FrameBuffer* frame_buffer) { 190 --frame_buffer->ref_cnt; 191 } 192 193 VpxVideoDecoder::VpxVideoDecoder( 194 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) 195 : task_runner_(task_runner), 196 state_(kUninitialized), 197 vpx_codec_(NULL), 198 vpx_codec_alpha_(NULL) {} 199 200 VpxVideoDecoder::~VpxVideoDecoder() { 201 DCHECK(task_runner_->BelongsToCurrentThread()); 202 CloseDecoder(); 203 } 204 205 std::string VpxVideoDecoder::GetDisplayName() const { 206 return "VpxVideoDecoder"; 207 } 208 209 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, 210 bool low_delay, 211 const PipelineStatusCB& status_cb, 212 const OutputCB& output_cb) { 213 DCHECK(task_runner_->BelongsToCurrentThread()); 214 DCHECK(config.IsValidConfig()); 215 DCHECK(!config.is_encrypted()); 216 DCHECK(decode_cb_.is_null()); 217 218 if (!ConfigureDecoder(config)) { 219 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 220 return; 221 } 222 223 // Success! 224 config_ = config; 225 state_ = kNormal; 226 output_cb_ = BindToCurrentLoop(output_cb); 227 status_cb.Run(PIPELINE_OK); 228 } 229 230 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context, 231 const VideoDecoderConfig& config) { 232 context = new vpx_codec_ctx(); 233 vpx_codec_dec_cfg_t vpx_config = {0}; 234 vpx_config.w = config.coded_size().width(); 235 vpx_config.h = config.coded_size().height(); 236 vpx_config.threads = GetThreadCount(config); 237 238 vpx_codec_err_t status = vpx_codec_dec_init(context, 239 config.codec() == kCodecVP9 ? 240 vpx_codec_vp9_dx() : 241 vpx_codec_vp8_dx(), 242 &vpx_config, 243 0); 244 if (status != VPX_CODEC_OK) { 245 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; 246 delete context; 247 return NULL; 248 } 249 return context; 250 } 251 252 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { 253 if (config.codec() != kCodecVP8 && config.codec() != kCodecVP9) 254 return false; 255 256 // In VP8 videos, only those with alpha are handled by VpxVideoDecoder. All 257 // other VP8 videos go to FFmpegVideoDecoder. 258 if (config.codec() == kCodecVP8 && config.format() != VideoFrame::YV12A) 259 return false; 260 261 CloseDecoder(); 262 263 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); 264 if (!vpx_codec_) 265 return false; 266 267 // We use our own buffers for VP9 so that there is no need to copy data after 268 // decoding. 269 if (config.codec() == kCodecVP9) { 270 memory_pool_ = new MemoryPool(); 271 if (vpx_codec_set_frame_buffer_functions(vpx_codec_, 272 &MemoryPool::GetVP9FrameBuffer, 273 &MemoryPool::ReleaseVP9FrameBuffer, 274 memory_pool_.get())) { 275 LOG(ERROR) << "Failed to configure external buffers."; 276 return false; 277 } 278 } 279 280 if (config.format() == VideoFrame::YV12A) { 281 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); 282 if (!vpx_codec_alpha_) 283 return false; 284 } 285 286 return true; 287 } 288 289 void VpxVideoDecoder::CloseDecoder() { 290 if (vpx_codec_) { 291 vpx_codec_destroy(vpx_codec_); 292 delete vpx_codec_; 293 vpx_codec_ = NULL; 294 memory_pool_ = NULL; 295 } 296 if (vpx_codec_alpha_) { 297 vpx_codec_destroy(vpx_codec_alpha_); 298 delete vpx_codec_alpha_; 299 vpx_codec_alpha_ = NULL; 300 } 301 } 302 303 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 304 const DecodeCB& decode_cb) { 305 DCHECK(task_runner_->BelongsToCurrentThread()); 306 DCHECK(!decode_cb.is_null()); 307 CHECK_NE(state_, kUninitialized); 308 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; 309 310 decode_cb_ = BindToCurrentLoop(decode_cb); 311 312 if (state_ == kError) { 313 base::ResetAndReturn(&decode_cb_).Run(kDecodeError); 314 return; 315 } 316 317 // Return empty frames if decoding has finished. 318 if (state_ == kDecodeFinished) { 319 base::ResetAndReturn(&decode_cb_).Run(kOk); 320 return; 321 } 322 323 DecodeBuffer(buffer); 324 } 325 326 void VpxVideoDecoder::Reset(const base::Closure& closure) { 327 DCHECK(task_runner_->BelongsToCurrentThread()); 328 DCHECK(decode_cb_.is_null()); 329 330 state_ = kNormal; 331 task_runner_->PostTask(FROM_HERE, closure); 332 } 333 334 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { 335 DCHECK(task_runner_->BelongsToCurrentThread()); 336 DCHECK_NE(state_, kUninitialized); 337 DCHECK_NE(state_, kDecodeFinished); 338 DCHECK_NE(state_, kError); 339 DCHECK(!decode_cb_.is_null()); 340 DCHECK(buffer.get()); 341 342 // Transition to kDecodeFinished on the first end of stream buffer. 343 if (state_ == kNormal && buffer->end_of_stream()) { 344 state_ = kDecodeFinished; 345 base::ResetAndReturn(&decode_cb_).Run(kOk); 346 return; 347 } 348 349 scoped_refptr<VideoFrame> video_frame; 350 if (!VpxDecode(buffer, &video_frame)) { 351 state_ = kError; 352 base::ResetAndReturn(&decode_cb_).Run(kDecodeError); 353 return; 354 } 355 356 base::ResetAndReturn(&decode_cb_).Run(kOk); 357 358 if (video_frame.get()) 359 output_cb_.Run(video_frame); 360 } 361 362 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer, 363 scoped_refptr<VideoFrame>* video_frame) { 364 DCHECK(video_frame); 365 DCHECK(!buffer->end_of_stream()); 366 367 // Pass |buffer| to libvpx. 368 int64 timestamp = buffer->timestamp().InMicroseconds(); 369 void* user_priv = reinterpret_cast<void*>(×tamp); 370 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, 371 buffer->data(), 372 buffer->data_size(), 373 user_priv, 374 0); 375 if (status != VPX_CODEC_OK) { 376 LOG(ERROR) << "vpx_codec_decode() failed, status=" << status; 377 return false; 378 } 379 380 // Gets pointer to decoded data. 381 vpx_codec_iter_t iter = NULL; 382 const vpx_image_t* vpx_image = vpx_codec_get_frame(vpx_codec_, &iter); 383 if (!vpx_image) { 384 *video_frame = NULL; 385 return true; 386 } 387 388 if (vpx_image->user_priv != reinterpret_cast<void*>(×tamp)) { 389 LOG(ERROR) << "Invalid output timestamp."; 390 return false; 391 } 392 393 const vpx_image_t* vpx_image_alpha = NULL; 394 if (vpx_codec_alpha_ && buffer->side_data_size() >= 8) { 395 // Pass alpha data to libvpx. 396 int64 timestamp_alpha = buffer->timestamp().InMicroseconds(); 397 void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha); 398 399 // First 8 bytes of side data is side_data_id in big endian. 400 const uint64 side_data_id = base::NetToHost64( 401 *(reinterpret_cast<const uint64*>(buffer->side_data()))); 402 if (side_data_id == 1) { 403 status = vpx_codec_decode(vpx_codec_alpha_, 404 buffer->side_data() + 8, 405 buffer->side_data_size() - 8, 406 user_priv_alpha, 407 0); 408 409 if (status != VPX_CODEC_OK) { 410 LOG(ERROR) << "vpx_codec_decode() failed on alpha, status=" << status; 411 return false; 412 } 413 414 // Gets pointer to decoded data. 415 vpx_codec_iter_t iter_alpha = NULL; 416 vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); 417 if (!vpx_image_alpha) { 418 *video_frame = NULL; 419 return true; 420 } 421 422 if (vpx_image_alpha->user_priv != 423 reinterpret_cast<void*>(×tamp_alpha)) { 424 LOG(ERROR) << "Invalid output timestamp on alpha."; 425 return false; 426 } 427 } 428 } 429 430 CopyVpxImageTo(vpx_image, vpx_image_alpha, video_frame); 431 (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp)); 432 return true; 433 } 434 435 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, 436 const struct vpx_image* vpx_image_alpha, 437 scoped_refptr<VideoFrame>* video_frame) { 438 CHECK(vpx_image); 439 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 440 vpx_image->fmt == VPX_IMG_FMT_YV12 || 441 vpx_image->fmt == VPX_IMG_FMT_I444); 442 443 VideoFrame::Format codec_format = VideoFrame::YV12; 444 int uv_rows = (vpx_image->d_h + 1) / 2; 445 446 if (vpx_image->fmt == VPX_IMG_FMT_I444) { 447 CHECK(!vpx_codec_alpha_); 448 codec_format = VideoFrame::YV24; 449 uv_rows = vpx_image->d_h; 450 } else if (vpx_codec_alpha_) { 451 codec_format = VideoFrame::YV12A; 452 } 453 454 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 455 456 if (!vpx_codec_alpha_ && memory_pool_.get()) { 457 *video_frame = VideoFrame::WrapExternalYuvData( 458 codec_format, 459 size, gfx::Rect(size), config_.natural_size(), 460 vpx_image->stride[VPX_PLANE_Y], 461 vpx_image->stride[VPX_PLANE_U], 462 vpx_image->stride[VPX_PLANE_V], 463 vpx_image->planes[VPX_PLANE_Y], 464 vpx_image->planes[VPX_PLANE_U], 465 vpx_image->planes[VPX_PLANE_V], 466 kNoTimestamp(), 467 memory_pool_->CreateFrameCallback(vpx_image->fb_priv)); 468 return; 469 } 470 471 *video_frame = frame_pool_.CreateFrame( 472 codec_format, 473 size, 474 gfx::Rect(size), 475 config_.natural_size(), 476 kNoTimestamp()); 477 478 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 479 vpx_image->stride[VPX_PLANE_Y], 480 vpx_image->d_h, 481 video_frame->get()); 482 CopyUPlane(vpx_image->planes[VPX_PLANE_U], 483 vpx_image->stride[VPX_PLANE_U], 484 uv_rows, 485 video_frame->get()); 486 CopyVPlane(vpx_image->planes[VPX_PLANE_V], 487 vpx_image->stride[VPX_PLANE_V], 488 uv_rows, 489 video_frame->get()); 490 if (!vpx_codec_alpha_) 491 return; 492 if (!vpx_image_alpha) { 493 MakeOpaqueAPlane( 494 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); 495 return; 496 } 497 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 498 vpx_image->stride[VPX_PLANE_Y], 499 vpx_image->d_h, 500 video_frame->get()); 501 } 502 503 } // namespace media 504