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> | |
10 | 9 |
11 #include "base/bind.h" | 10 #include "base/bind.h" |
12 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
13 #include "base/command_line.h" | 12 #include "base/command_line.h" |
14 #include "base/location.h" | 13 #include "base/location.h" |
15 #include "base/logging.h" | 14 #include "base/logging.h" |
16 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
17 #include "base/stl_util.h" | |
18 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
19 #include "base/sys_byteorder.h" | 17 #include "base/sys_byteorder.h" |
20 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
21 #include "media/base/decoder_buffer.h" | 19 #include "media/base/decoder_buffer.h" |
22 #include "media/base/demuxer_stream.h" | 20 #include "media/base/demuxer_stream.h" |
23 #include "media/base/limits.h" | |
24 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
25 #include "media/base/pipeline.h" | 22 #include "media/base/pipeline.h" |
26 #include "media/base/video_decoder_config.h" | 23 #include "media/base/video_decoder_config.h" |
27 #include "media/base/video_frame.h" | 24 #include "media/base/video_frame.h" |
28 #include "media/base/video_util.h" | 25 #include "media/base/video_util.h" |
29 | 26 |
30 // Include libvpx header files. | 27 // Include libvpx header files. |
31 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide | 28 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide |
32 // backwards compatibility for legacy applications using the library. | 29 // backwards compatibility for legacy applications using the library. |
33 #define VPX_CODEC_DISABLE_COMPAT 1 | 30 #define VPX_CODEC_DISABLE_COMPAT 1 |
34 extern "C" { | 31 extern "C" { |
35 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" | 32 #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" | 33 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
38 } | 34 } |
39 | 35 |
40 namespace media { | 36 namespace media { |
41 | 37 |
42 // Always try to use three threads for video decoding. There is little reason | 38 // 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 | 39 // 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. | 40 // performance benefits on older machines such as P4s with hyperthreading. |
45 static const int kDecodeThreads = 2; | 41 static const int kDecodeThreads = 2; |
46 static const int kMaxDecodeThreads = 16; | 42 static const int kMaxDecodeThreads = 16; |
(...skipping 17 matching lines...) Expand all Loading... |
64 } | 60 } |
65 | 61 |
66 return decode_threads; | 62 return decode_threads; |
67 } | 63 } |
68 | 64 |
69 decode_threads = std::max(decode_threads, 0); | 65 decode_threads = std::max(decode_threads, 0); |
70 decode_threads = std::min(decode_threads, kMaxDecodeThreads); | 66 decode_threads = std::min(decode_threads, kMaxDecodeThreads); |
71 return decode_threads; | 67 return decode_threads; |
72 } | 68 } |
73 | 69 |
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 | |
203 VpxVideoDecoder::VpxVideoDecoder( | 70 VpxVideoDecoder::VpxVideoDecoder( |
204 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 71 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
205 : task_runner_(task_runner), | 72 : task_runner_(task_runner), |
206 weak_factory_(this), | 73 weak_factory_(this), |
207 state_(kUninitialized), | 74 state_(kUninitialized), |
208 vpx_codec_(NULL), | 75 vpx_codec_(NULL), |
209 vpx_codec_alpha_(NULL) { | 76 vpx_codec_alpha_(NULL) { |
210 } | 77 } |
211 | 78 |
212 VpxVideoDecoder::~VpxVideoDecoder() { | 79 VpxVideoDecoder::~VpxVideoDecoder() { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 } | 135 } |
269 if (!can_handle) | 136 if (!can_handle) |
270 return false; | 137 return false; |
271 | 138 |
272 CloseDecoder(); | 139 CloseDecoder(); |
273 | 140 |
274 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); | 141 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); |
275 if (!vpx_codec_) | 142 if (!vpx_codec_) |
276 return false; | 143 return false; |
277 | 144 |
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 | |
291 if (config.format() == VideoFrame::YV12A) { | 145 if (config.format() == VideoFrame::YV12A) { |
292 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); | 146 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); |
293 if (!vpx_codec_alpha_) | 147 if (!vpx_codec_alpha_) |
294 return false; | 148 return false; |
295 } | 149 } |
296 | 150 |
297 return true; | 151 return true; |
298 } | 152 } |
299 | 153 |
300 void VpxVideoDecoder::CloseDecoder() { | 154 void VpxVideoDecoder::CloseDecoder() { |
301 if (vpx_codec_) { | 155 if (vpx_codec_) { |
302 vpx_codec_destroy(vpx_codec_); | 156 vpx_codec_destroy(vpx_codec_); |
303 delete vpx_codec_; | 157 delete vpx_codec_; |
304 vpx_codec_ = NULL; | 158 vpx_codec_ = NULL; |
305 memory_pool_ = NULL; | |
306 } | 159 } |
307 if (vpx_codec_alpha_) { | 160 if (vpx_codec_alpha_) { |
308 vpx_codec_destroy(vpx_codec_alpha_); | 161 vpx_codec_destroy(vpx_codec_alpha_); |
309 delete vpx_codec_alpha_; | 162 delete vpx_codec_alpha_; |
310 vpx_codec_alpha_ = NULL; | 163 vpx_codec_alpha_ = NULL; |
311 } | 164 } |
312 } | 165 } |
313 | 166 |
314 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 167 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
315 const DecodeCB& decode_cb) { | 168 const DecodeCB& decode_cb) { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 | 335 |
483 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, | 336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, |
484 const struct vpx_image* vpx_image_alpha, | 337 const struct vpx_image* vpx_image_alpha, |
485 scoped_refptr<VideoFrame>* video_frame) { | 338 scoped_refptr<VideoFrame>* video_frame) { |
486 CHECK(vpx_image); | 339 CHECK(vpx_image); |
487 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || | 340 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || |
488 vpx_image->fmt == VPX_IMG_FMT_YV12); | 341 vpx_image->fmt == VPX_IMG_FMT_YV12); |
489 | 342 |
490 gfx::Size size(vpx_image->d_w, vpx_image->d_h); | 343 gfx::Size size(vpx_image->d_w, vpx_image->d_h); |
491 | 344 |
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 | |
507 *video_frame = frame_pool_.CreateFrame( | 345 *video_frame = frame_pool_.CreateFrame( |
508 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, | 346 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, |
509 size, | 347 size, |
510 gfx::Rect(size), | 348 gfx::Rect(size), |
511 config_.natural_size(), | 349 config_.natural_size(), |
512 kNoTimestamp()); | 350 kNoTimestamp()); |
513 | 351 |
514 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], | 352 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], |
515 vpx_image->stride[VPX_PLANE_Y], | 353 vpx_image->stride[VPX_PLANE_Y], |
516 vpx_image->d_h, | 354 vpx_image->d_h, |
(...skipping 13 matching lines...) Expand all Loading... |
530 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); | 368 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); |
531 return; | 369 return; |
532 } | 370 } |
533 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | 371 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
534 vpx_image->stride[VPX_PLANE_Y], | 372 vpx_image->stride[VPX_PLANE_Y], |
535 vpx_image->d_h, | 373 vpx_image->d_h, |
536 video_frame->get()); | 374 video_frame->get()); |
537 } | 375 } |
538 | 376 |
539 } // namespace media | 377 } // namespace media |
OLD | NEW |