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 #include <vector> |
9 | 10 |
10 #include "base/bind.h" | 11 #include "base/bind.h" |
11 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/location.h" | 14 #include "base/location.h" |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 17 #include "base/stl_util.h" |
16 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
17 #include "base/sys_byteorder.h" | 19 #include "base/sys_byteorder.h" |
18 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
19 #include "media/base/decoder_buffer.h" | 21 #include "media/base/decoder_buffer.h" |
20 #include "media/base/demuxer_stream.h" | 22 #include "media/base/demuxer_stream.h" |
| 23 #include "media/base/limits.h" |
21 #include "media/base/media_switches.h" | 24 #include "media/base/media_switches.h" |
22 #include "media/base/pipeline.h" | 25 #include "media/base/pipeline.h" |
23 #include "media/base/video_decoder_config.h" | 26 #include "media/base/video_decoder_config.h" |
24 #include "media/base/video_frame.h" | 27 #include "media/base/video_frame.h" |
25 #include "media/base/video_util.h" | 28 #include "media/base/video_util.h" |
26 | 29 |
27 // Include libvpx header files. | 30 // Include libvpx header files. |
28 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide | 31 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide |
29 // backwards compatibility for legacy applications using the library. | 32 // backwards compatibility for legacy applications using the library. |
30 #define VPX_CODEC_DISABLE_COMPAT 1 | 33 #define VPX_CODEC_DISABLE_COMPAT 1 |
31 extern "C" { | 34 extern "C" { |
32 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" | 35 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" |
| 36 #include "third_party/libvpx/source/libvpx/vpx/vpx_frame_buffer.h" |
33 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" | 37 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
34 } | 38 } |
35 | 39 |
36 namespace media { | 40 namespace media { |
37 | 41 |
38 // Always try to use three threads for video decoding. There is little reason | 42 // 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 | 43 // 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. | 44 // performance benefits on older machines such as P4s with hyperthreading. |
41 static const int kDecodeThreads = 2; | 45 static const int kDecodeThreads = 2; |
42 static const int kMaxDecodeThreads = 16; | 46 static const int kMaxDecodeThreads = 16; |
(...skipping 17 matching lines...) Expand all Loading... |
60 } | 64 } |
61 | 65 |
62 return decode_threads; | 66 return decode_threads; |
63 } | 67 } |
64 | 68 |
65 decode_threads = std::max(decode_threads, 0); | 69 decode_threads = std::max(decode_threads, 0); |
66 decode_threads = std::min(decode_threads, kMaxDecodeThreads); | 70 decode_threads = std::min(decode_threads, kMaxDecodeThreads); |
67 return decode_threads; | 71 return decode_threads; |
68 } | 72 } |
69 | 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. |
| 77 static const uint32 kVP9MaxFrameBuffers = VP9_MAXIMUM_REF_BUFFERS + |
| 78 VPX_MAXIMUM_WORK_BUFFERS + |
| 79 limits::kMaxVideoFrames; |
| 80 |
| 81 class 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 std::vector<uint8> data; |
| 115 uint32 ref_cnt; |
| 116 }; |
| 117 |
| 118 // Gets the next available frame buffer for use by libvpx. |
| 119 VP9FrameBuffer* GetFreeFrameBuffer(size_t min_size); |
| 120 |
| 121 // Method that gets called when a VideoFrame that references this pool gets |
| 122 // destroyed. |
| 123 void OnVideoFrameDestroyed(VP9FrameBuffer* frame_buffer); |
| 124 |
| 125 // Frame buffers to be used by libvpx for VP9 Decoding. |
| 126 std::vector<VP9FrameBuffer*> frame_buffers_; |
| 127 |
| 128 DISALLOW_COPY_AND_ASSIGN(MemoryPool); |
| 129 }; |
| 130 |
| 131 VpxVideoDecoder::MemoryPool::MemoryPool() {} |
| 132 |
| 133 VpxVideoDecoder::MemoryPool::~MemoryPool() { |
| 134 STLDeleteElements(&frame_buffers_); |
| 135 } |
| 136 |
| 137 VpxVideoDecoder::MemoryPool::VP9FrameBuffer* |
| 138 VpxVideoDecoder::MemoryPool::GetFreeFrameBuffer(size_t min_size) { |
| 139 // Check if a free frame buffer exists. |
| 140 size_t i = 0; |
| 141 for (; i < frame_buffers_.size(); ++i) { |
| 142 if (frame_buffers_[i]->ref_cnt == 0) |
| 143 break; |
| 144 } |
| 145 |
| 146 if (i == frame_buffers_.size()) { |
| 147 // Maximum number of frame buffers reached. |
| 148 if (i == kVP9MaxFrameBuffers) |
| 149 return NULL; |
| 150 |
| 151 // Create a new frame buffer. |
| 152 frame_buffers_.push_back(new VP9FrameBuffer()); |
| 153 } |
| 154 |
| 155 // Resize the frame buffer if necessary. |
| 156 if (frame_buffers_[i]->data.size() < min_size) |
| 157 frame_buffers_[i]->data.resize(min_size); |
| 158 return frame_buffers_[i]; |
| 159 } |
| 160 |
| 161 int32 VpxVideoDecoder::MemoryPool::GetVP9FrameBuffer( |
| 162 void* user_priv, size_t min_size, vpx_codec_frame_buffer* fb) { |
| 163 DCHECK(user_priv); |
| 164 DCHECK(fb); |
| 165 |
| 166 VpxVideoDecoder::MemoryPool* memory_pool = |
| 167 static_cast<VpxVideoDecoder::MemoryPool*>(user_priv); |
| 168 |
| 169 VP9FrameBuffer* fb_to_use = memory_pool->GetFreeFrameBuffer(min_size); |
| 170 if (fb_to_use == NULL) |
| 171 return -1; |
| 172 |
| 173 fb->data = &fb_to_use->data[0]; |
| 174 fb->size = fb_to_use->data.size(); |
| 175 ++fb_to_use->ref_cnt; |
| 176 |
| 177 // Set the frame buffer's private data to point at the external frame buffer. |
| 178 fb->priv = static_cast<void*>(fb_to_use); |
| 179 return 0; |
| 180 } |
| 181 |
| 182 int32 VpxVideoDecoder::MemoryPool::ReleaseVP9FrameBuffer( |
| 183 void *user_priv, vpx_codec_frame_buffer *fb) { |
| 184 VP9FrameBuffer* frame_buffer = static_cast<VP9FrameBuffer*>(fb->priv); |
| 185 --frame_buffer->ref_cnt; |
| 186 return 0; |
| 187 } |
| 188 |
| 189 base::Closure VpxVideoDecoder::MemoryPool::CreateFrameCallback( |
| 190 void* fb_priv_data) { |
| 191 VP9FrameBuffer* frame_buffer = static_cast<VP9FrameBuffer*>(fb_priv_data); |
| 192 ++frame_buffer->ref_cnt; |
| 193 return BindToCurrentLoop( |
| 194 base::Bind(&MemoryPool::OnVideoFrameDestroyed, this, |
| 195 frame_buffer)); |
| 196 } |
| 197 |
| 198 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed( |
| 199 VP9FrameBuffer* frame_buffer) { |
| 200 --frame_buffer->ref_cnt; |
| 201 } |
| 202 |
70 VpxVideoDecoder::VpxVideoDecoder( | 203 VpxVideoDecoder::VpxVideoDecoder( |
71 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 204 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
72 : task_runner_(task_runner), | 205 : task_runner_(task_runner), |
73 weak_factory_(this), | 206 weak_factory_(this), |
74 state_(kUninitialized), | 207 state_(kUninitialized), |
75 vpx_codec_(NULL), | 208 vpx_codec_(NULL), |
76 vpx_codec_alpha_(NULL) { | 209 vpx_codec_alpha_(NULL) { |
77 } | 210 } |
78 | 211 |
79 VpxVideoDecoder::~VpxVideoDecoder() { | 212 VpxVideoDecoder::~VpxVideoDecoder() { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 } | 268 } |
136 if (!can_handle) | 269 if (!can_handle) |
137 return false; | 270 return false; |
138 | 271 |
139 CloseDecoder(); | 272 CloseDecoder(); |
140 | 273 |
141 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); | 274 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); |
142 if (!vpx_codec_) | 275 if (!vpx_codec_) |
143 return false; | 276 return false; |
144 | 277 |
| 278 // We use our own buffers for VP9 so that there is no need to copy data after |
| 279 // decoding. |
| 280 if (config.codec() == kCodecVP9) { |
| 281 memory_pool_ = new MemoryPool(); |
| 282 if (vpx_codec_set_frame_buffer_functions(vpx_codec_, |
| 283 &MemoryPool::GetVP9FrameBuffer, |
| 284 &MemoryPool::ReleaseVP9FrameBuffer, |
| 285 memory_pool_)) { |
| 286 LOG(ERROR) << "Failed to configure external buffers."; |
| 287 return false; |
| 288 } |
| 289 } |
| 290 |
145 if (config.format() == VideoFrame::YV12A) { | 291 if (config.format() == VideoFrame::YV12A) { |
146 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); | 292 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); |
147 if (!vpx_codec_alpha_) | 293 if (!vpx_codec_alpha_) |
148 return false; | 294 return false; |
149 } | 295 } |
150 | 296 |
151 return true; | 297 return true; |
152 } | 298 } |
153 | 299 |
154 void VpxVideoDecoder::CloseDecoder() { | 300 void VpxVideoDecoder::CloseDecoder() { |
155 if (vpx_codec_) { | 301 if (vpx_codec_) { |
156 vpx_codec_destroy(vpx_codec_); | 302 vpx_codec_destroy(vpx_codec_); |
157 delete vpx_codec_; | 303 delete vpx_codec_; |
158 vpx_codec_ = NULL; | 304 vpx_codec_ = NULL; |
| 305 memory_pool_ = NULL; |
159 } | 306 } |
160 if (vpx_codec_alpha_) { | 307 if (vpx_codec_alpha_) { |
161 vpx_codec_destroy(vpx_codec_alpha_); | 308 vpx_codec_destroy(vpx_codec_alpha_); |
162 delete vpx_codec_alpha_; | 309 delete vpx_codec_alpha_; |
163 vpx_codec_alpha_ = NULL; | 310 vpx_codec_alpha_ = NULL; |
164 } | 311 } |
165 } | 312 } |
166 | 313 |
167 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 314 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
168 const DecodeCB& decode_cb) { | 315 const DecodeCB& decode_cb) { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 | 482 |
336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, | 483 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, |
337 const struct vpx_image* vpx_image_alpha, | 484 const struct vpx_image* vpx_image_alpha, |
338 scoped_refptr<VideoFrame>* video_frame) { | 485 scoped_refptr<VideoFrame>* video_frame) { |
339 CHECK(vpx_image); | 486 CHECK(vpx_image); |
340 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || | 487 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || |
341 vpx_image->fmt == VPX_IMG_FMT_YV12); | 488 vpx_image->fmt == VPX_IMG_FMT_YV12); |
342 | 489 |
343 gfx::Size size(vpx_image->d_w, vpx_image->d_h); | 490 gfx::Size size(vpx_image->d_w, vpx_image->d_h); |
344 | 491 |
| 492 if (!vpx_codec_alpha_ && memory_pool_) { |
| 493 *video_frame = VideoFrame::WrapExternalYuvData( |
| 494 VideoFrame::YV12, |
| 495 size, gfx::Rect(size), config_.natural_size(), |
| 496 vpx_image->stride[VPX_PLANE_Y], |
| 497 vpx_image->stride[VPX_PLANE_U], |
| 498 vpx_image->stride[VPX_PLANE_V], |
| 499 vpx_image->planes[VPX_PLANE_Y], |
| 500 vpx_image->planes[VPX_PLANE_U], |
| 501 vpx_image->planes[VPX_PLANE_V], |
| 502 kNoTimestamp(), |
| 503 memory_pool_->CreateFrameCallback(vpx_image->fb_priv)); |
| 504 return; |
| 505 } |
| 506 |
345 *video_frame = frame_pool_.CreateFrame( | 507 *video_frame = frame_pool_.CreateFrame( |
346 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, | 508 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, |
347 size, | 509 size, |
348 gfx::Rect(size), | 510 gfx::Rect(size), |
349 config_.natural_size(), | 511 config_.natural_size(), |
350 kNoTimestamp()); | 512 kNoTimestamp()); |
351 | 513 |
352 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], | 514 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], |
353 vpx_image->stride[VPX_PLANE_Y], | 515 vpx_image->stride[VPX_PLANE_Y], |
354 vpx_image->d_h, | 516 vpx_image->d_h, |
(...skipping 13 matching lines...) Expand all Loading... |
368 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); | 530 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); |
369 return; | 531 return; |
370 } | 532 } |
371 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | 533 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
372 vpx_image->stride[VPX_PLANE_Y], | 534 vpx_image->stride[VPX_PLANE_Y], |
373 vpx_image->d_h, | 535 vpx_image->d_h, |
374 video_frame->get()); | 536 video_frame->get()); |
375 } | 537 } |
376 | 538 |
377 } // namespace media | 539 } // namespace media |
OLD | NEW |