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