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 | 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 Loading... | |
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 // Minimum libvpx decoder ABI version required to support direct rendering. | |
79 static const int kLibvpxMinABIExternalBuffers = 6; | |
80 | |
81 class VpxVideoDecoder::MemoryPool | |
82 : public base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool> { | |
83 public: | |
84 vpx_codec_frame_buffer* frame_buffers() { return frame_buffers_; } | |
85 size_t frame_buffers_size() const { return arraysize(frame_buffers_); } | |
86 | |
87 // Callback that will be called by libvpx if the frame buffer size needs to | |
88 // increase. Parameters: | |
89 // user_priv Data passed into libvpx (we pass NULL). | |
90 // new_size Minimum size needed by libvpx to decompress the next frame. | |
91 // fb Pointer to the frame buffer to update. | |
92 // Returns VPX_CODEC_OK on success. Returns < 0 on failure. | |
93 static int32 ReallocVP9FrameBuffer(void* user_priv, size_t new_size, | |
94 vpx_codec_frame_buffer* fb); | |
95 | |
96 // Generates a "no_longer_needed" closure that holds a reference | |
97 // to this pool. | |
98 base::Closure frame_callback(); | |
99 | |
100 private: | |
101 friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>; | |
102 ~MemoryPool(); | |
103 | |
104 // Empty method that gets called when a VideoFrame that references | |
105 // this pool gets destroyed. | |
106 void OnVideoFrameDestroyed(); | |
107 | |
108 vpx_codec_frame_buffer frame_buffers_[kVP9MaxFrameBuffers]; | |
acolwell GONE FROM CHROMIUM
2013/12/19 15:26:12
Add DISALLOW_COPY_AND_ASSIGN(MemoryPool).
vignesh
2013/12/19 20:27:21
Done.
| |
109 }; | |
110 | |
111 VpxVideoDecoder::MemoryPool::~MemoryPool() { | |
112 for (size_t i = 0; i < arraysize(frame_buffers_); ++i) | |
113 delete [] frame_buffers_[i].data; | |
114 } | |
115 | |
116 int32 VpxVideoDecoder::MemoryPool::ReallocVP9FrameBuffer( | |
117 void* user_priv, size_t new_size, vpx_codec_frame_buffer* fb) { | |
118 if (!fb) | |
119 return -1; | |
120 if (fb->data) | |
121 delete[] fb->data; | |
122 fb->data = new uint8[new_size]; | |
123 if (!fb->data) { | |
124 fb->size = 0; | |
125 return -1; | |
126 } | |
127 fb->size = new_size; | |
128 return VPX_CODEC_OK; | |
129 } | |
130 | |
131 base::Closure VpxVideoDecoder::MemoryPool::frame_callback() { | |
132 return base::Bind(&MemoryPool::OnVideoFrameDestroyed, this); | |
133 } | |
134 | |
135 void VpxVideoDecoder::MemoryPool::OnVideoFrameDestroyed() { | |
136 } | |
137 | |
70 VpxVideoDecoder::VpxVideoDecoder( | 138 VpxVideoDecoder::VpxVideoDecoder( |
71 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 139 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
72 : message_loop_(message_loop), | 140 : message_loop_(message_loop), |
73 weak_factory_(this), | 141 weak_factory_(this), |
74 state_(kUninitialized), | 142 state_(kUninitialized), |
75 vpx_codec_(NULL), | 143 vpx_codec_(NULL), |
76 vpx_codec_alpha_(NULL) { | 144 vpx_codec_alpha_(NULL), |
145 memory_pool_(NULL) { | |
77 } | 146 } |
78 | 147 |
79 VpxVideoDecoder::~VpxVideoDecoder() { | 148 VpxVideoDecoder::~VpxVideoDecoder() { |
80 DCHECK_EQ(kUninitialized, state_); | 149 DCHECK_EQ(kUninitialized, state_); |
81 CloseDecoder(); | 150 CloseDecoder(); |
82 } | 151 } |
83 | 152 |
84 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, | 153 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config, |
85 const PipelineStatusCB& status_cb) { | 154 const PipelineStatusCB& status_cb) { |
86 DCHECK(message_loop_->BelongsToCurrentThread()); | 155 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 } | 204 } |
136 if (!can_handle) | 205 if (!can_handle) |
137 return false; | 206 return false; |
138 | 207 |
139 CloseDecoder(); | 208 CloseDecoder(); |
140 | 209 |
141 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); | 210 vpx_codec_ = InitializeVpxContext(vpx_codec_, config); |
142 if (!vpx_codec_) | 211 if (!vpx_codec_) |
143 return false; | 212 return false; |
144 | 213 |
214 // We use our own buffers for VP9 so that there is no need to copy data after | |
215 // decoding. | |
216 if (config.codec() == kCodecVP9 && | |
217 VPX_DECODER_ABI_VERSION >= kLibvpxMinABIExternalBuffers) { | |
acolwell GONE FROM CHROMIUM
2013/12/19 15:26:12
Is this really needed? Can this code even build w/
vignesh
2013/12/19 20:27:21
We don't need this. Getting rid of it.
| |
218 memory_pool_ = new MemoryPool(); | |
219 if (vpx_codec_set_frame_buffers( | |
220 vpx_codec_, | |
221 memory_pool_->frame_buffers(), | |
222 memory_pool_->frame_buffers_size(), | |
223 &MemoryPool::ReallocVP9FrameBuffer, | |
224 NULL)) { | |
225 LOG(ERROR) << "Failed to configure external buffers."; | |
226 return false; | |
227 } | |
228 // Ask libvpx to use LRU to reuse frame buffers so that it doesn't | |
229 // overwrite the buffers currently in use by chromium (jitter buffers). | |
230 if (vpx_codec_control(vpx_codec_, VP9D_SET_FRAME_BUFFER_LRU_CACHE, 1)) { | |
231 LOG(ERROR) << "Failed to set frame buffer lru cache."; | |
232 return false; | |
233 } | |
234 } | |
235 | |
145 if (config.format() == VideoFrame::YV12A) { | 236 if (config.format() == VideoFrame::YV12A) { |
146 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); | 237 vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config); |
147 if (!vpx_codec_alpha_) | 238 if (!vpx_codec_alpha_) |
148 return false; | 239 return false; |
149 } | 240 } |
150 | 241 |
151 return true; | 242 return true; |
152 } | 243 } |
153 | 244 |
154 void VpxVideoDecoder::CloseDecoder() { | 245 void VpxVideoDecoder::CloseDecoder() { |
155 if (vpx_codec_) { | 246 if (vpx_codec_) { |
156 vpx_codec_destroy(vpx_codec_); | 247 vpx_codec_destroy(vpx_codec_); |
157 delete vpx_codec_; | 248 delete vpx_codec_; |
158 vpx_codec_ = NULL; | 249 vpx_codec_ = NULL; |
250 memory_pool_ = NULL; | |
159 } | 251 } |
160 if (vpx_codec_alpha_) { | 252 if (vpx_codec_alpha_) { |
161 vpx_codec_destroy(vpx_codec_alpha_); | 253 vpx_codec_destroy(vpx_codec_alpha_); |
162 delete vpx_codec_alpha_; | 254 delete vpx_codec_alpha_; |
163 vpx_codec_alpha_ = NULL; | 255 vpx_codec_alpha_ = NULL; |
164 } | 256 } |
165 } | 257 } |
166 | 258 |
167 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 259 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
168 const DecodeCB& decode_cb) { | 260 const DecodeCB& decode_cb) { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
335 | 427 |
336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, | 428 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image, |
337 const struct vpx_image* vpx_image_alpha, | 429 const struct vpx_image* vpx_image_alpha, |
338 scoped_refptr<VideoFrame>* video_frame) { | 430 scoped_refptr<VideoFrame>* video_frame) { |
339 CHECK(vpx_image); | 431 CHECK(vpx_image); |
340 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || | 432 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || |
341 vpx_image->fmt == VPX_IMG_FMT_YV12); | 433 vpx_image->fmt == VPX_IMG_FMT_YV12); |
342 | 434 |
343 gfx::Size size(vpx_image->d_w, vpx_image->d_h); | 435 gfx::Size size(vpx_image->d_w, vpx_image->d_h); |
344 | 436 |
437 if (!vpx_codec_alpha_ && memory_pool_) { | |
438 *video_frame = VideoFrame::WrapExternalYuvData( | |
439 VideoFrame::YV12, | |
440 size, gfx::Rect(size), config_.natural_size(), | |
441 vpx_image->stride[VPX_PLANE_Y], | |
acolwell GONE FROM CHROMIUM
2013/12/19 15:26:12
It would be nice if vpx_image contained a vpx_code
vignesh
2013/12/19 20:27:21
frank's comments address this.
| |
442 vpx_image->stride[VPX_PLANE_U], | |
443 vpx_image->stride[VPX_PLANE_V], | |
444 vpx_image->planes[VPX_PLANE_Y], | |
445 vpx_image->planes[VPX_PLANE_U], | |
446 vpx_image->planes[VPX_PLANE_V], | |
447 kNoTimestamp(), | |
448 memory_pool_->frame_callback()); | |
449 return; | |
450 } | |
451 | |
345 *video_frame = frame_pool_.CreateFrame( | 452 *video_frame = frame_pool_.CreateFrame( |
346 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, | 453 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12, |
347 size, | 454 size, |
348 gfx::Rect(size), | 455 gfx::Rect(size), |
349 config_.natural_size(), | 456 config_.natural_size(), |
350 kNoTimestamp()); | 457 kNoTimestamp()); |
351 | 458 |
352 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], | 459 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], |
353 vpx_image->stride[VPX_PLANE_Y], | 460 vpx_image->stride[VPX_PLANE_Y], |
354 vpx_image->d_h, | 461 vpx_image->d_h, |
355 video_frame->get()); | 462 video_frame->get()); |
356 CopyUPlane(vpx_image->planes[VPX_PLANE_U], | 463 CopyUPlane(vpx_image->planes[VPX_PLANE_U], |
357 vpx_image->stride[VPX_PLANE_U], | 464 vpx_image->stride[VPX_PLANE_U], |
358 (vpx_image->d_h + 1) / 2, | 465 (vpx_image->d_h + 1) / 2, |
359 video_frame->get()); | 466 video_frame->get()); |
360 CopyVPlane(vpx_image->planes[VPX_PLANE_V], | 467 CopyVPlane(vpx_image->planes[VPX_PLANE_V], |
361 vpx_image->stride[VPX_PLANE_V], | 468 vpx_image->stride[VPX_PLANE_V], |
362 (vpx_image->d_h + 1) / 2, | 469 (vpx_image->d_h + 1) / 2, |
363 video_frame->get()); | 470 video_frame->get()); |
364 if (!vpx_codec_alpha_) | |
acolwell GONE FROM CHROMIUM
2013/12/19 15:26:12
You should probably leave this in here since the m
vignesh
2013/12/19 20:27:21
Done.
| |
365 return; | |
366 if (!vpx_image_alpha) { | 471 if (!vpx_image_alpha) { |
367 MakeOpaqueAPlane( | 472 MakeOpaqueAPlane( |
368 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); | 473 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); |
369 return; | 474 return; |
370 } | 475 } |
371 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], | 476 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
372 vpx_image->stride[VPX_PLANE_Y], | 477 vpx_image->stride[VPX_PLANE_Y], |
373 vpx_image->d_h, | 478 vpx_image->d_h, |
374 video_frame->get()); | 479 video_frame->get()); |
375 } | 480 } |
376 | 481 |
377 } // namespace media | 482 } // namespace media |
OLD | NEW |