Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: media/filters/vpx_video_decoder.cc

Issue 114853002: media: Enabling direct rendering for VP9 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: get/release model for frame bufers. rebase. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
16 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
17 #include "base/sys_byteorder.h" 18 #include "base/sys_byteorder.h"
18 #include "media/base/bind_to_current_loop.h" 19 #include "media/base/bind_to_current_loop.h"
19 #include "media/base/decoder_buffer.h" 20 #include "media/base/decoder_buffer.h"
20 #include "media/base/demuxer_stream.h" 21 #include "media/base/demuxer_stream.h"
22 #include "media/base/limits.h"
21 #include "media/base/media_switches.h" 23 #include "media/base/media_switches.h"
22 #include "media/base/pipeline.h" 24 #include "media/base/pipeline.h"
23 #include "media/base/video_decoder_config.h" 25 #include "media/base/video_decoder_config.h"
24 #include "media/base/video_frame.h" 26 #include "media/base/video_frame.h"
25 #include "media/base/video_util.h" 27 #include "media/base/video_util.h"
26 28
27 // Include libvpx header files. 29 // Include libvpx header files.
28 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide 30 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide
29 // backwards compatibility for legacy applications using the library. 31 // backwards compatibility for legacy applications using the library.
30 #define VPX_CODEC_DISABLE_COMPAT 1 32 #define VPX_CODEC_DISABLE_COMPAT 1
31 extern "C" { 33 extern "C" {
32 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" 34 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h"
35 #include "third_party/libvpx/source/libvpx/vpx/vpx_external_frame_buffer.h"
33 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" 36 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
34 } 37 }
35 38
36 namespace media { 39 namespace media {
37 40
38 // Always try to use three threads for video decoding. There is little reason 41 // 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 42 // 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. 43 // performance benefits on older machines such as P4s with hyperthreading.
41 static const int kDecodeThreads = 2; 44 static const int kDecodeThreads = 2;
42 static const int kMaxDecodeThreads = 16; 45 static const int kMaxDecodeThreads = 16;
(...skipping 17 matching lines...) Expand all
60 } 63 }
61 64
62 return decode_threads; 65 return decode_threads;
63 } 66 }
64 67
65 decode_threads = std::max(decode_threads, 0); 68 decode_threads = std::max(decode_threads, 0);
66 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 69 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
67 return decode_threads; 70 return decode_threads;
68 } 71 }
69 72
73 // Maximum number of frame buffers that can be used (by both chromium and libvpx
74 // combined) for VP9 Decoding.
75 // TODO(vigneshv): Investigate if this can be relaxed to a higher number.
76 static const int kVP9MaxFrameBuffers = VP9_MAXIMUM_REF_BUFFERS +
77 VPX_MAXIMUM_WORK_BUFFERS +
78 limits::kMaxVideoFrames;
79
80 // Reference counted frame buffers used for VP9 decoding. Reference counting is
81 // done manually because both chromium and libvpx has to release this before a
82 // buffer can be re-used.
83 struct VP9FrameBuffer {
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: Make this decl private inside the MemoryPool
vignesh 2014/02/04 01:38:10 Done.
84 uint8* data;
85 uint64 size;
86 uint32 ref_cnt;
87 };
88
89 class VpxVideoDecoder::MemoryPool
90 : public base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool> {
91 public:
92 MemoryPool(VpxVideoDecoder* decoder);
93
94 // Callback that will be called by libvpx when it needs a frame buffer.
95 // Parameters:
96 // |user_priv| Private data passed to libvpx (pointer to memory pool).
97 // |min_size| Minimum size needed by libvpx to decompress the next frame.
98 // |fb| Pointer to the frame buffer to update.
99 // Returns 0 on success. Returns < 0 on failure.
100 static int32 GetVP9FrameBuffer(void* user_priv, size_t min_size,
101 vpx_codec_frame_buffer* fb);
102
103 // Callback that will be called by libvpx when the frame buffer is no more
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: s/more/longer/
vignesh 2014/02/04 01:38:10 Done.
104 // being used by libvpx. Parameters:
105 // |user_priv| Private data passed to libvpx (pointer to memory pool).
106 // |fb| Pointer to the frame buffer that's being released.
107 static int32 ReleaseVP9FrameBuffer(void *user_priv,
108 vpx_codec_frame_buffer *fb);
109
110 // Generates a "no_longer_needed" closure that holds a reference
111 // to this pool.
112 base::Closure frame_callback(VP9FrameBuffer* frame_buffer);
113
114 // Sets |decoder_| to NULL.
115 void ClearDecoder();
116
117 private:
118 friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>;
119 ~MemoryPool();
120
121 // Method that gets called when a VideoFrame that references this pool gets
122 // destroyed.
123 void OnVideoFrameDestroyed(VP9FrameBuffer* frame_buffer);
124
125 // Pointer to the VpxVideoDecoder object that has this object.
126 VpxVideoDecoder* decoder_;
127
128 // Frame buffers to be used by libvpx for VP9 Decoding.
129 std::vector<VP9FrameBuffer*> frame_buffers_;
130
131 DISALLOW_COPY_AND_ASSIGN(MemoryPool);
132 };
133
134 VpxVideoDecoder::MemoryPool::MemoryPool(VpxVideoDecoder* decoder)
135 : decoder_(decoder) {
136 }
137
138 VpxVideoDecoder::MemoryPool::~MemoryPool() {
139 for (size_t i = 0; i < frame_buffers_.size(); ++i) {
140 delete[] frame_buffers_[i]->data;
141 delete frame_buffers_[i];
142 }
143 }
144
145 int32 VpxVideoDecoder::MemoryPool::GetVP9FrameBuffer(
146 void* user_priv, size_t min_size, vpx_codec_frame_buffer* fb) {
147 if (user_priv == NULL || fb == NULL)
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: These look like they should be DCHECKs since
vignesh 2014/02/04 01:38:10 Done.
148 return -1;
149
150 VpxVideoDecoder::MemoryPool* memory_pool =
151 static_cast<VpxVideoDecoder::MemoryPool*>(user_priv);
152
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 Put the rest of this method in a private method an
vignesh 2014/02/04 01:38:10 Done.
153 // Check if a free frame buffer exists.
154 int i = 0;
155 for (i = 0; i < memory_pool->frame_buffers_.size(); ++i) {
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: s/i = 0// since you initialize it on the line
vignesh 2014/02/04 01:38:10 Done.
156 if (memory_pool->frame_buffers_[i]->ref_cnt == 0)
157 break;
158 }
159
160 if (i == memory_pool->frame_buffers_.size()) {
161 // Maximum number of frame buffers reached.
162 if (i == kVP9MaxFrameBuffers)
163 return -1;
164
165 // Create a new frame buffer.
166 memory_pool->frame_buffers_.push_back(new VP9FrameBuffer());
167 }
168
169 // Reallocate the frame buffer if necessary.
170 if (memory_pool->frame_buffers_[i]->size < min_size) {
171 delete[] memory_pool->frame_buffers_[i]->data;
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 Just use std::vector<uint8> for data so you can re
vignesh 2014/02/04 01:38:10 Done.
172 memory_pool->frame_buffers_[i]->data = new uint8[min_size];
173 if (!memory_pool->frame_buffers_[i]->data)
174 return -1;
175 memory_pool->frame_buffers_[i]->size = min_size;
176 }
177
178 fb->data = memory_pool->frame_buffers_[i]->data;
179 fb->size = memory_pool->frame_buffers_[i]->size;
180 ++memory_pool->frame_buffers_[i]->ref_cnt;
181
182 // Set the frame buffer's private data to point at the external frame buffer.
183 fb->frame_priv = static_cast<void*>(memory_pool->frame_buffers_[i]);
184 return 0;
185 }
186
187 int32 VpxVideoDecoder::MemoryPool::ReleaseVP9FrameBuffer(
188 void *user_priv, vpx_codec_frame_buffer *fb) {
189 VP9FrameBuffer* frame_buffer = static_cast<VP9FrameBuffer*>(fb->frame_priv);
190 --frame_buffer->ref_cnt;
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 Is this method and GetVP9FrameBuffer() ALWAYS call
vignesh 2014/02/04 01:38:10 yes, both the methods are always called on the sam
191 return 0;
192 }
193
194 base::Closure VpxVideoDecoder::MemoryPool::frame_callback(
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: This isn't a trivial accessor so it should ha
vignesh 2014/02/04 01:38:10 Done.
195 VP9FrameBuffer* frame_buffer) {
196 ++frame_buffer->ref_cnt;
197 return BindToCurrentLoop(
198 base::Bind(&MemoryPool::OnVideoFrameDestroyed, this,
199 frame_buffer));
200 }
201
202 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed(
203 VP9FrameBuffer* frame_buffer) {
204 --frame_buffer->ref_cnt;
205 }
206
207 void VpxVideoDecoder::MemoryPool::ClearDecoder() {
208 decoder_ = NULL;
209 }
210
70 VpxVideoDecoder::VpxVideoDecoder( 211 VpxVideoDecoder::VpxVideoDecoder(
71 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) 212 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
72 : task_runner_(task_runner), 213 : task_runner_(task_runner),
73 weak_factory_(this), 214 weak_factory_(this),
74 state_(kUninitialized), 215 state_(kUninitialized),
75 vpx_codec_(NULL), 216 vpx_codec_(NULL),
76 vpx_codec_alpha_(NULL) { 217 vpx_codec_alpha_(NULL),
218 memory_pool_(NULL) {
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: You don't need this for a scoped_refptr. It i
vignesh 2014/02/04 01:38:10 Done.
77 } 219 }
78 220
79 VpxVideoDecoder::~VpxVideoDecoder() { 221 VpxVideoDecoder::~VpxVideoDecoder() {
80 DCHECK_EQ(kUninitialized, state_); 222 DCHECK_EQ(kUninitialized, state_);
81 CloseDecoder(); 223 CloseDecoder();
82 } 224 }
83 225
84 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, 226 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
85 const PipelineStatusCB& status_cb) { 227 const PipelineStatusCB& status_cb) {
86 DCHECK(task_runner_->BelongsToCurrentThread()); 228 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 } 277 }
136 if (!can_handle) 278 if (!can_handle)
137 return false; 279 return false;
138 280
139 CloseDecoder(); 281 CloseDecoder();
140 282
141 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); 283 vpx_codec_ = InitializeVpxContext(vpx_codec_, config);
142 if (!vpx_codec_) 284 if (!vpx_codec_)
143 return false; 285 return false;
144 286
287 // We use our own buffers for VP9 so that there is no need to copy data after
288 // decoding.
289 if (config.codec() == kCodecVP9) {
290 memory_pool_ = new MemoryPool(this);
291 if (vpx_codec_set_external_frame_buffer_functions(
292 vpx_codec_,
293 &MemoryPool::GetVP9FrameBuffer,
294 &MemoryPool::ReleaseVP9FrameBuffer,
295 memory_pool_)) {
296 LOG(ERROR) << "Failed to configure external buffers.";
297 return false;
298 }
299 }
300
145 if (config.format() == VideoFrame::YV12A) { 301 if (config.format() == VideoFrame::YV12A) {
146 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); 302 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config);
147 if (!vpx_codec_alpha_) 303 if (!vpx_codec_alpha_)
148 return false; 304 return false;
149 } 305 }
150 306
151 return true; 307 return true;
152 } 308 }
153 309
154 void VpxVideoDecoder::CloseDecoder() { 310 void VpxVideoDecoder::CloseDecoder() {
155 if (vpx_codec_) { 311 if (vpx_codec_) {
156 vpx_codec_destroy(vpx_codec_); 312 vpx_codec_destroy(vpx_codec_);
157 delete vpx_codec_; 313 delete vpx_codec_;
158 vpx_codec_ = NULL; 314 vpx_codec_ = NULL;
315 if (memory_pool_) {
316 memory_pool_->ClearDecoder();
317 memory_pool_ = NULL;
318 }
159 } 319 }
160 if (vpx_codec_alpha_) { 320 if (vpx_codec_alpha_) {
161 vpx_codec_destroy(vpx_codec_alpha_); 321 vpx_codec_destroy(vpx_codec_alpha_);
162 delete vpx_codec_alpha_; 322 delete vpx_codec_alpha_;
163 vpx_codec_alpha_ = NULL; 323 vpx_codec_alpha_ = NULL;
164 } 324 }
165 } 325 }
166 326
167 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 327 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
168 const DecodeCB& decode_cb) { 328 const DecodeCB& decode_cb) {
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 495
336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, 496 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image,
337 const struct vpx_image* vpx_image_alpha, 497 const struct vpx_image* vpx_image_alpha,
338 scoped_refptr<VideoFrame>* video_frame) { 498 scoped_refptr<VideoFrame>* video_frame) {
339 CHECK(vpx_image); 499 CHECK(vpx_image);
340 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 500 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 ||
341 vpx_image->fmt == VPX_IMG_FMT_YV12); 501 vpx_image->fmt == VPX_IMG_FMT_YV12);
342 502
343 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 503 gfx::Size size(vpx_image->d_w, vpx_image->d_h);
344 504
505 if (!vpx_codec_alpha_ && memory_pool_) {
506 *video_frame = VideoFrame::WrapExternalYuvData(
507 VideoFrame::YV12,
508 size, gfx::Rect(size), config_.natural_size(),
509 vpx_image->stride[VPX_PLANE_Y],
510 vpx_image->stride[VPX_PLANE_U],
511 vpx_image->stride[VPX_PLANE_V],
512 vpx_image->planes[VPX_PLANE_Y],
513 vpx_image->planes[VPX_PLANE_U],
514 vpx_image->planes[VPX_PLANE_V],
515 kNoTimestamp(),
516 memory_pool_->frame_callback(
acolwell GONE FROM CHROMIUM 2014/02/04 00:48:35 nit: Change the signature of this method so you do
vignesh 2014/02/04 01:38:10 Done.
517 static_cast<VP9FrameBuffer*>(
518 vpx_image->ext_fb_priv)));
519 return;
520 }
521
345 *video_frame = frame_pool_.CreateFrame( 522 *video_frame = frame_pool_.CreateFrame(
346 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, 523 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12,
347 size, 524 size,
348 gfx::Rect(size), 525 gfx::Rect(size),
349 config_.natural_size(), 526 config_.natural_size(),
350 kNoTimestamp()); 527 kNoTimestamp());
351 528
352 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 529 CopyYPlane(vpx_image->planes[VPX_PLANE_Y],
353 vpx_image->stride[VPX_PLANE_Y], 530 vpx_image->stride[VPX_PLANE_Y],
354 vpx_image->d_h, 531 vpx_image->d_h,
(...skipping 13 matching lines...) Expand all
368 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); 545 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get());
369 return; 546 return;
370 } 547 }
371 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 548 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
372 vpx_image->stride[VPX_PLANE_Y], 549 vpx_image->stride[VPX_PLANE_Y],
373 vpx_image->d_h, 550 vpx_image->d_h,
374 video_frame->get()); 551 video_frame->get());
375 } 552 }
376 553
377 } // namespace media 554 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698