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

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: fixing the case when videoframes are destroyed out of order Created 7 years 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 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
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.
74 static const int kVP9MaxFrameBuffers = VP9_MAXIMUM_REF_BUFFERS +
75 VPX_MAXIMUM_WORK_BUFFERS +
76 limits::kMaxVideoFrames;
77
78 class VpxVideoDecoder::MemoryPool
79 : public base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool> {
80 public:
81 MemoryPool(VpxVideoDecoder* decoder);
82 vpx_codec_frame_buffer* frame_buffers() { return frame_buffers_; }
83 size_t frame_buffers_size() const { return arraysize(frame_buffers_); }
84
85 // Callback that will be called by libvpx if the frame buffer size needs to
86 // increase. Parameters:
87 // user_priv Data passed into libvpx (we pass NULL).
88 // new_size Minimum size needed by libvpx to decompress the next frame.
89 // fb Pointer to the frame buffer to update.
90 // Returns VPX_CODEC_OK on success. Returns < 0 on failure.
91 static int32 ReallocVP9FrameBuffer(void* user_priv, size_t new_size,
92 vpx_codec_frame_buffer* fb);
93
94 // Generates a "no_longer_needed" closure that holds a reference
95 // to this pool.
96 base::Closure frame_callback();
97
98 // Checks if it is safe to call libvpx. Since libvpx uses LRU to reuse frame
99 // buffers, it is not safe to call libvpx if the "oldest" frame according to
100 // libvpx is still in use by chromium.
101 bool IsSafeToCallDecoder();
102
103 private:
104 friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>;
105 ~MemoryPool();
106
107 // Method that gets called when a VideoFrame that references this pool gets
108 // destroyed.
109 void OnVideoFrameDestroyed(uint64 frame_id);
110
111 // Pointer to the VpxVideoDecoder object that has this object.
112 VpxVideoDecoder* decoder_;
113
114 // Incrementing counter of frames passed into libvpx.
115 uint64 next_frame_id_;
116
117 // List of frame ids currently in use by chromium.
118 std::set<uint64> frame_ids_in_use_;
119
120 vpx_codec_frame_buffer frame_buffers_[kVP9MaxFrameBuffers];
121 DISALLOW_COPY_AND_ASSIGN(MemoryPool);
122 };
123
124 VpxVideoDecoder::MemoryPool::MemoryPool(VpxVideoDecoder* decoder)
125 : decoder_(decoder),
126 next_frame_id_(0) {
127 memset(frame_buffers_, 0,
128 sizeof(vpx_codec_frame_buffer) * arraysize(frame_buffers_));
acolwell GONE FROM CHROMIUM 2013/12/20 17:26:44 nit: I believe you should be able to just use size
vignesh 2013/12/20 19:59:40 I tried that before i used this, it did not work.
129 }
130
131 VpxVideoDecoder::MemoryPool::~MemoryPool() {
132 for (size_t i = 0; i < arraysize(frame_buffers_); ++i)
133 delete[] frame_buffers_[i].data;
134 }
135
136 int32 VpxVideoDecoder::MemoryPool::ReallocVP9FrameBuffer(
137 void* user_priv, size_t new_size, vpx_codec_frame_buffer* fb) {
138 if (!fb)
139 return -1;
140 if (fb->data)
141 delete[] fb->data;
142 fb->data = new uint8[new_size];
143 if (!fb->data) {
144 fb->size = 0;
145 return -1;
146 }
147 fb->size = new_size;
148 return VPX_CODEC_OK;
149 }
150
151 base::Closure VpxVideoDecoder::MemoryPool::frame_callback() {
152 frame_ids_in_use_.insert(next_frame_id_);
153 return BindToCurrentLoop(
154 base::Bind(&MemoryPool::OnVideoFrameDestroyed, this,
155 next_frame_id_++));
156 }
157
158 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed(uint64 frame_id) {
159 frame_ids_in_use_.erase(frame_id);
160 if (decoder_->pending_buffer_ && IsSafeToCallDecoder()) {
acolwell GONE FROM CHROMIUM 2013/12/20 17:26:44 You'll need a decoder_ null check and a way for th
vignesh 2013/12/20 19:59:40 nice catch. Done.
161 decoder_->DecodeBuffer(decoder_->pending_buffer_);
162 decoder_->pending_buffer_ = NULL;
163 }
164 }
165
166 bool VpxVideoDecoder::MemoryPool::IsSafeToCallDecoder() {
167 return next_frame_id_ < limits::kMaxVideoFrames ||
168 frame_ids_in_use_.find(next_frame_id_ - limits::kMaxVideoFrames) ==
169 frame_ids_in_use_.end();
170 }
171
70 VpxVideoDecoder::VpxVideoDecoder( 172 VpxVideoDecoder::VpxVideoDecoder(
71 const scoped_refptr<base::MessageLoopProxy>& message_loop) 173 const scoped_refptr<base::MessageLoopProxy>& message_loop)
72 : message_loop_(message_loop), 174 : message_loop_(message_loop),
73 weak_factory_(this), 175 weak_factory_(this),
74 state_(kUninitialized), 176 state_(kUninitialized),
75 vpx_codec_(NULL), 177 vpx_codec_(NULL),
76 vpx_codec_alpha_(NULL) { 178 vpx_codec_alpha_(NULL),
179 memory_pool_(NULL),
180 pending_buffer_(NULL) {
77 } 181 }
78 182
79 VpxVideoDecoder::~VpxVideoDecoder() { 183 VpxVideoDecoder::~VpxVideoDecoder() {
80 DCHECK_EQ(kUninitialized, state_); 184 DCHECK_EQ(kUninitialized, state_);
81 CloseDecoder(); 185 CloseDecoder();
82 } 186 }
83 187
84 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, 188 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
85 const PipelineStatusCB& status_cb) { 189 const PipelineStatusCB& status_cb) {
86 DCHECK(message_loop_->BelongsToCurrentThread()); 190 DCHECK(message_loop_->BelongsToCurrentThread());
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 } 239 }
136 if (!can_handle) 240 if (!can_handle)
137 return false; 241 return false;
138 242
139 CloseDecoder(); 243 CloseDecoder();
140 244
141 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); 245 vpx_codec_ = InitializeVpxContext(vpx_codec_, config);
142 if (!vpx_codec_) 246 if (!vpx_codec_)
143 return false; 247 return false;
144 248
249 // We use our own buffers for VP9 so that there is no need to copy data after
250 // decoding.
251 if (config.codec() == kCodecVP9) {
252 memory_pool_ = new MemoryPool(this);
253 if (vpx_codec_set_frame_buffers(
254 vpx_codec_,
255 memory_pool_->frame_buffers(),
256 memory_pool_->frame_buffers_size(),
257 &MemoryPool::ReallocVP9FrameBuffer,
258 NULL)) {
259 LOG(ERROR) << "Failed to configure external buffers.";
260 return false;
261 }
262 if (vpx_codec_control(vpx_codec_, VP9D_SET_FRAME_BUFFER_LRU_CACHE, 1)) {
263 LOG(ERROR) << "Failed to set frame buffer lru cache.";
264 return false;
265 }
266 }
267
145 if (config.format() == VideoFrame::YV12A) { 268 if (config.format() == VideoFrame::YV12A) {
146 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); 269 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config);
147 if (!vpx_codec_alpha_) 270 if (!vpx_codec_alpha_)
148 return false; 271 return false;
149 } 272 }
150 273
151 return true; 274 return true;
152 } 275 }
153 276
154 void VpxVideoDecoder::CloseDecoder() { 277 void VpxVideoDecoder::CloseDecoder() {
155 if (vpx_codec_) { 278 if (vpx_codec_) {
156 vpx_codec_destroy(vpx_codec_); 279 vpx_codec_destroy(vpx_codec_);
157 delete vpx_codec_; 280 delete vpx_codec_;
158 vpx_codec_ = NULL; 281 vpx_codec_ = NULL;
282 memory_pool_ = NULL;
acolwell GONE FROM CHROMIUM 2013/12/20 17:26:44 I think right before this line is where you need t
vignesh 2013/12/20 19:59:40 Done.
283 pending_buffer_ = NULL;
159 } 284 }
160 if (vpx_codec_alpha_) { 285 if (vpx_codec_alpha_) {
161 vpx_codec_destroy(vpx_codec_alpha_); 286 vpx_codec_destroy(vpx_codec_alpha_);
162 delete vpx_codec_alpha_; 287 delete vpx_codec_alpha_;
163 vpx_codec_alpha_ = NULL; 288 vpx_codec_alpha_ = NULL;
164 } 289 }
165 } 290 }
166 291
167 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 292 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
168 const DecodeCB& decode_cb) { 293 const DecodeCB& decode_cb) {
169 DCHECK(message_loop_->BelongsToCurrentThread()); 294 DCHECK(message_loop_->BelongsToCurrentThread());
170 DCHECK(!decode_cb.is_null()); 295 DCHECK(!decode_cb.is_null());
171 CHECK_NE(state_, kUninitialized); 296 CHECK_NE(state_, kUninitialized);
172 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; 297 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
173 298
174 decode_cb_ = BindToCurrentLoop(decode_cb); 299 decode_cb_ = BindToCurrentLoop(decode_cb);
175 300
176 if (state_ == kError) { 301 if (state_ == kError) {
177 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); 302 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
178 return; 303 return;
179 } 304 }
180 305
181 // Return empty frames if decoding has finished. 306 // Return empty frames if decoding has finished.
182 if (state_ == kDecodeFinished) { 307 if (state_ == kDecodeFinished) {
183 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame()); 308 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame());
184 return; 309 return;
185 } 310 }
186 311
312 // Check if it is safe to call libvpx.
313 if (memory_pool_ && !memory_pool_->IsSafeToCallDecoder()) {
314 pending_buffer_ = buffer;
315 return;
316 }
317
187 DecodeBuffer(buffer); 318 DecodeBuffer(buffer);
188 } 319 }
189 320
190 void VpxVideoDecoder::Reset(const base::Closure& closure) { 321 void VpxVideoDecoder::Reset(const base::Closure& closure) {
191 DCHECK(message_loop_->BelongsToCurrentThread()); 322 DCHECK(message_loop_->BelongsToCurrentThread());
192 DCHECK(reset_cb_.is_null()); 323 DCHECK(reset_cb_.is_null());
193 reset_cb_ = BindToCurrentLoop(closure); 324 reset_cb_ = BindToCurrentLoop(closure);
194 325
195 // Defer the reset if a decode is pending. 326 // Defer the reset if a decode is pending.
196 if (!decode_cb_.is_null()) 327 if (!decode_cb_.is_null())
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 466
336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, 467 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image,
337 const struct vpx_image* vpx_image_alpha, 468 const struct vpx_image* vpx_image_alpha,
338 scoped_refptr<VideoFrame>* video_frame) { 469 scoped_refptr<VideoFrame>* video_frame) {
339 CHECK(vpx_image); 470 CHECK(vpx_image);
340 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 471 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 ||
341 vpx_image->fmt == VPX_IMG_FMT_YV12); 472 vpx_image->fmt == VPX_IMG_FMT_YV12);
342 473
343 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 474 gfx::Size size(vpx_image->d_w, vpx_image->d_h);
344 475
476 if (!vpx_codec_alpha_ && memory_pool_) {
477 *video_frame = VideoFrame::WrapExternalYuvData(
478 VideoFrame::YV12,
479 size, gfx::Rect(size), config_.natural_size(),
480 vpx_image->stride[VPX_PLANE_Y],
481 vpx_image->stride[VPX_PLANE_U],
482 vpx_image->stride[VPX_PLANE_V],
483 vpx_image->planes[VPX_PLANE_Y],
484 vpx_image->planes[VPX_PLANE_U],
485 vpx_image->planes[VPX_PLANE_V],
486 kNoTimestamp(),
487 memory_pool_->frame_callback());
488 return;
489 }
490
345 *video_frame = frame_pool_.CreateFrame( 491 *video_frame = frame_pool_.CreateFrame(
346 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, 492 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12,
347 size, 493 size,
348 gfx::Rect(size), 494 gfx::Rect(size),
349 config_.natural_size(), 495 config_.natural_size(),
350 kNoTimestamp()); 496 kNoTimestamp());
351 497
352 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 498 CopyYPlane(vpx_image->planes[VPX_PLANE_Y],
353 vpx_image->stride[VPX_PLANE_Y], 499 vpx_image->stride[VPX_PLANE_Y],
354 vpx_image->d_h, 500 vpx_image->d_h,
(...skipping 13 matching lines...) Expand all
368 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); 514 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get());
369 return; 515 return;
370 } 516 }
371 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 517 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
372 vpx_image->stride[VPX_PLANE_Y], 518 vpx_image->stride[VPX_PLANE_Y],
373 vpx_image->d_h, 519 vpx_image->d_h,
374 video_frame->get()); 520 video_frame->get());
375 } 521 }
376 522
377 } // namespace media 523 } // 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