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

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

Issue 16274005: Separate DemuxerStream and VideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix win64 Created 7 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/media.gyp » ('j') | 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>
8 #include <string>
9
7 #include "base/bind.h" 10 #include "base/bind.h"
8 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
9 #include "base/command_line.h" 12 #include "base/command_line.h"
10 #include "base/location.h" 13 #include "base/location.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
14 #include "base/sys_byteorder.h" 17 #include "base/sys_byteorder.h"
15 #include "media/base/bind_to_loop.h" 18 #include "media/base/bind_to_loop.h"
16 #include "media/base/decoder_buffer.h" 19 #include "media/base/decoder_buffer.h"
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 decode_threads = std::max(decode_threads, 0); 57 decode_threads = std::max(decode_threads, 0);
55 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 58 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
56 return decode_threads; 59 return decode_threads;
57 } 60 }
58 61
59 VpxVideoDecoder::VpxVideoDecoder( 62 VpxVideoDecoder::VpxVideoDecoder(
60 const scoped_refptr<base::MessageLoopProxy>& message_loop) 63 const scoped_refptr<base::MessageLoopProxy>& message_loop)
61 : message_loop_(message_loop), 64 : message_loop_(message_loop),
62 weak_factory_(this), 65 weak_factory_(this),
63 state_(kUninitialized), 66 state_(kUninitialized),
64 demuxer_stream_(NULL),
65 vpx_codec_(NULL), 67 vpx_codec_(NULL),
66 vpx_codec_alpha_(NULL) { 68 vpx_codec_alpha_(NULL) {
67 } 69 }
68 70
69 VpxVideoDecoder::~VpxVideoDecoder() { 71 VpxVideoDecoder::~VpxVideoDecoder() {
70 DCHECK_EQ(kUninitialized, state_); 72 DCHECK_EQ(kUninitialized, state_);
71 CloseDecoder(); 73 CloseDecoder();
72 } 74 }
73 75
74 void VpxVideoDecoder::Initialize( 76 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
75 DemuxerStream* stream, 77 const PipelineStatusCB& status_cb,
76 const PipelineStatusCB& status_cb, 78 const StatisticsCB& statistics_cb) {
77 const StatisticsCB& statistics_cb) {
78 DCHECK(message_loop_->BelongsToCurrentThread()); 79 DCHECK(message_loop_->BelongsToCurrentThread());
79 DCHECK(stream); 80 DCHECK(config.IsValidConfig());
81 DCHECK(!config.is_encrypted());
80 DCHECK(read_cb_.is_null()); 82 DCHECK(read_cb_.is_null());
81 DCHECK(reset_cb_.is_null()); 83 DCHECK(reset_cb_.is_null());
82 84
83 weak_this_ = weak_factory_.GetWeakPtr(); 85 weak_this_ = weak_factory_.GetWeakPtr();
84 86
85 demuxer_stream_ = stream; 87 if (!ConfigureDecoder(config)) {
86 statistics_cb_ = statistics_cb;
87
88 if (!ConfigureDecoder()) {
89 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 88 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
90 return; 89 return;
91 } 90 }
92 91
93 // Success! 92 // Success!
93 config_ = config;
94 statistics_cb_ = statistics_cb;
94 state_ = kNormal; 95 state_ = kNormal;
95 status_cb.Run(PIPELINE_OK); 96 status_cb.Run(PIPELINE_OK);
96 } 97 }
97 98
98 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context, 99 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context,
99 const VideoDecoderConfig& config) { 100 const VideoDecoderConfig& config) {
100 context = new vpx_codec_ctx(); 101 context = new vpx_codec_ctx();
101 vpx_codec_dec_cfg_t vpx_config = {0}; 102 vpx_codec_dec_cfg_t vpx_config = {0};
102 vpx_config.w = config.coded_size().width(); 103 vpx_config.w = config.coded_size().width();
103 vpx_config.h = config.coded_size().height(); 104 vpx_config.h = config.coded_size().height();
104 vpx_config.threads = GetThreadCount(); 105 vpx_config.threads = GetThreadCount();
105 106
106 vpx_codec_err_t status = vpx_codec_dec_init(context, 107 vpx_codec_err_t status = vpx_codec_dec_init(context,
107 config.codec() == kCodecVP9 ? 108 config.codec() == kCodecVP9 ?
108 vpx_codec_vp9_dx() : 109 vpx_codec_vp9_dx() :
109 vpx_codec_vp8_dx(), 110 vpx_codec_vp8_dx(),
110 &vpx_config, 111 &vpx_config,
111 0); 112 0);
112 if (status != VPX_CODEC_OK) { 113 if (status != VPX_CODEC_OK) {
113 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; 114 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status;
114 delete context; 115 delete context;
115 return NULL; 116 return NULL;
116 } 117 }
117 return context; 118 return context;
118 } 119 }
119 120
120 bool VpxVideoDecoder::ConfigureDecoder() { 121 bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) {
121 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
122 DCHECK(config.IsValidConfig());
123
124 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 122 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
125 bool can_handle = false; 123 bool can_handle = false;
126 if (config.codec() == kCodecVP9) 124 if (config.codec() == kCodecVP9)
127 can_handle = true; 125 can_handle = true;
128 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) && 126 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) &&
129 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { 127 config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) {
130 can_handle = true; 128 can_handle = true;
131 } 129 }
132 if (!can_handle) 130 if (!can_handle)
133 return false; 131 return false;
(...skipping 19 matching lines...) Expand all
153 delete vpx_codec_; 151 delete vpx_codec_;
154 vpx_codec_ = NULL; 152 vpx_codec_ = NULL;
155 } 153 }
156 if (vpx_codec_alpha_) { 154 if (vpx_codec_alpha_) {
157 vpx_codec_destroy(vpx_codec_alpha_); 155 vpx_codec_destroy(vpx_codec_alpha_);
158 delete vpx_codec_alpha_; 156 delete vpx_codec_alpha_;
159 vpx_codec_alpha_ = NULL; 157 vpx_codec_alpha_ = NULL;
160 } 158 }
161 } 159 }
162 160
163 void VpxVideoDecoder::Read(const ReadCB& read_cb) { 161 void VpxVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
162 const ReadCB& read_cb) {
164 DCHECK(message_loop_->BelongsToCurrentThread()); 163 DCHECK(message_loop_->BelongsToCurrentThread());
165 DCHECK(!read_cb.is_null()); 164 DCHECK(!read_cb.is_null());
166 CHECK_NE(state_, kUninitialized); 165 CHECK_NE(state_, kUninitialized);
167 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; 166 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
167
168 read_cb_ = BindToCurrentLoop(read_cb); 168 read_cb_ = BindToCurrentLoop(read_cb);
169 169
170 if (state_ == kError) { 170 if (state_ == kError) {
171 read_cb.Run(kDecodeError, NULL); 171 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
172 return; 172 return;
173 } 173 }
174 174
175 // Return empty frames if decoding has finished. 175 // Return empty frames if decoding has finished.
176 if (state_ == kDecodeFinished) { 176 if (state_ == kDecodeFinished) {
177 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); 177 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
178 return; 178 return;
179 } 179 }
180 180
181 ReadFromDemuxerStream(); 181 DecodeBuffer(buffer);
182 } 182 }
183 183
184 void VpxVideoDecoder::Reset(const base::Closure& closure) { 184 void VpxVideoDecoder::Reset(const base::Closure& closure) {
185 DCHECK(message_loop_->BelongsToCurrentThread()); 185 DCHECK(message_loop_->BelongsToCurrentThread());
186 DCHECK(reset_cb_.is_null()); 186 DCHECK(reset_cb_.is_null());
187 reset_cb_ = BindToCurrentLoop(closure); 187 reset_cb_ = BindToCurrentLoop(closure);
188 188
189 // Defer the reset if a read is pending. 189 // Defer the reset if a read is pending.
190 if (!read_cb_.is_null()) 190 if (!read_cb_.is_null())
191 return; 191 return;
(...skipping 11 matching lines...) Expand all
203 if (!read_cb_.is_null()) { 203 if (!read_cb_.is_null()) {
204 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 204 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
205 // Reset is pending only when read is pending. 205 // Reset is pending only when read is pending.
206 if (!reset_cb_.is_null()) 206 if (!reset_cb_.is_null())
207 base::ResetAndReturn(&reset_cb_).Run(); 207 base::ResetAndReturn(&reset_cb_).Run();
208 } 208 }
209 209
210 state_ = kUninitialized; 210 state_ = kUninitialized;
211 } 211 }
212 212
213 void VpxVideoDecoder::ReadFromDemuxerStream() {
214 DCHECK_NE(state_, kUninitialized);
215 DCHECK_NE(state_, kDecodeFinished);
216 DCHECK_NE(state_, kError);
217 DCHECK(!read_cb_.is_null());
218
219 demuxer_stream_->Read(base::Bind(
220 &VpxVideoDecoder::DoDecryptOrDecodeBuffer, weak_this_));
221 }
222
223 bool VpxVideoDecoder::HasAlpha() const { 213 bool VpxVideoDecoder::HasAlpha() const {
224 return vpx_codec_alpha_ != NULL; 214 return vpx_codec_alpha_ != NULL;
225 } 215 }
226 216
227 void VpxVideoDecoder::DoDecryptOrDecodeBuffer( 217 void VpxVideoDecoder::DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) {
228 DemuxerStream::Status status,
229 const scoped_refptr<DecoderBuffer>& buffer) {
230 DCHECK(message_loop_->BelongsToCurrentThread());
231 DCHECK_NE(state_, kDecodeFinished);
232 DCHECK_EQ(status != DemuxerStream::kOk, !buffer.get()) << status;
233
234 if (state_ == kUninitialized)
235 return;
236
237 DCHECK(!read_cb_.is_null());
238
239 if (!reset_cb_.is_null()) {
240 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
241 DoReset();
242 return;
243 }
244
245 if (status == DemuxerStream::kAborted) {
246 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
247 return;
248 }
249
250 // VideoFrameStream ensures no kConfigChanged is passed to VideoDecoders.
251 DCHECK_EQ(status, DemuxerStream::kOk) << status;
252 DecodeBuffer(buffer);
253 }
254
255 void VpxVideoDecoder::DecodeBuffer(
256 const scoped_refptr<DecoderBuffer>& buffer) {
257 DCHECK(message_loop_->BelongsToCurrentThread()); 218 DCHECK(message_loop_->BelongsToCurrentThread());
258 DCHECK_NE(state_, kUninitialized); 219 DCHECK_NE(state_, kUninitialized);
259 DCHECK_NE(state_, kDecodeFinished); 220 DCHECK_NE(state_, kDecodeFinished);
260 DCHECK_NE(state_, kError); 221 DCHECK_NE(state_, kError);
261 DCHECK(reset_cb_.is_null()); 222 DCHECK(reset_cb_.is_null());
262 DCHECK(!read_cb_.is_null()); 223 DCHECK(!read_cb_.is_null());
263 DCHECK(buffer.get()); 224 DCHECK(buffer);
264 225
265 // Transition to kDecodeFinished on the first end of stream buffer. 226 // Transition to kDecodeFinished on the first end of stream buffer.
266 if (state_ == kNormal && buffer->IsEndOfStream()) { 227 if (state_ == kNormal && buffer->IsEndOfStream()) {
267 state_ = kDecodeFinished; 228 state_ = kDecodeFinished;
268 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); 229 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
269 return; 230 return;
270 } 231 }
271 232
272 scoped_refptr<VideoFrame> video_frame; 233 scoped_refptr<VideoFrame> video_frame;
273 if (!Decode(buffer, &video_frame)) { 234 if (!VpxDecode(buffer, &video_frame)) {
274 state_ = kError; 235 state_ = kError;
275 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 236 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
276 return; 237 return;
277 } 238 }
278 239
279 // Any successful decode counts! 240 // Any successful decode counts!
280 if (buffer->GetDataSize() && buffer->GetSideDataSize()) { 241 if (buffer->GetDataSize() && buffer->GetSideDataSize()) {
281 PipelineStatistics statistics; 242 PipelineStatistics statistics;
282 statistics.video_bytes_decoded = buffer->GetDataSize(); 243 statistics.video_bytes_decoded = buffer->GetDataSize();
283 statistics_cb_.Run(statistics); 244 statistics_cb_.Run(statistics);
284 } 245 }
285 246
286 // If we didn't get a frame we need more data.
287 if (!video_frame.get()) { 247 if (!video_frame.get()) {
288 ReadFromDemuxerStream(); 248 base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL);
289 return; 249 return;
290 } 250 }
291 251
292 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); 252 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame);
293 } 253 }
294 254
295 bool VpxVideoDecoder::Decode( 255 bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer,
296 const scoped_refptr<DecoderBuffer>& buffer, 256 scoped_refptr<VideoFrame>* video_frame) {
297 scoped_refptr<VideoFrame>* video_frame) {
298 DCHECK(video_frame); 257 DCHECK(video_frame);
299 DCHECK(!buffer->IsEndOfStream()); 258 DCHECK(!buffer->IsEndOfStream());
300 259
301 // Pass |buffer| to libvpx. 260 // Pass |buffer| to libvpx.
302 int64 timestamp = buffer->GetTimestamp().InMicroseconds(); 261 int64 timestamp = buffer->GetTimestamp().InMicroseconds();
303 void* user_priv = reinterpret_cast<void*>(&timestamp); 262 void* user_priv = reinterpret_cast<void*>(&timestamp);
304 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, 263 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_,
305 buffer->GetData(), 264 buffer->GetData(),
306 buffer->GetDataSize(), 265 buffer->GetDataSize(),
307 user_priv, 266 user_priv,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 } 326 }
368 327
369 void VpxVideoDecoder::DoReset() { 328 void VpxVideoDecoder::DoReset() {
370 DCHECK(read_cb_.is_null()); 329 DCHECK(read_cb_.is_null());
371 330
372 state_ = kNormal; 331 state_ = kNormal;
373 reset_cb_.Run(); 332 reset_cb_.Run();
374 reset_cb_.Reset(); 333 reset_cb_.Reset();
375 } 334 }
376 335
377 void VpxVideoDecoder::CopyVpxImageTo( 336 void VpxVideoDecoder::CopyVpxImageTo(const vpx_image* vpx_image,
378 const vpx_image* vpx_image, 337 const struct vpx_image* vpx_image_alpha,
379 const struct vpx_image* vpx_image_alpha, 338 scoped_refptr<VideoFrame>* video_frame) {
380 scoped_refptr<VideoFrame>* video_frame) {
381 CHECK(vpx_image); 339 CHECK(vpx_image);
382 CHECK_EQ(vpx_image->d_w % 2, 0U); 340 CHECK_EQ(vpx_image->d_w % 2, 0U);
383 CHECK_EQ(vpx_image->d_h % 2, 0U); 341 CHECK_EQ(vpx_image->d_h % 2, 0U);
384 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 342 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 ||
385 vpx_image->fmt == VPX_IMG_FMT_YV12); 343 vpx_image->fmt == VPX_IMG_FMT_YV12);
386 344
387 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 345 gfx::Size size(vpx_image->d_w, vpx_image->d_h);
388 gfx::Size natural_size =
389 demuxer_stream_->video_decoder_config().natural_size();
390 346
391 *video_frame = VideoFrame::CreateFrame(vpx_codec_alpha_ ? 347 *video_frame = VideoFrame::CreateFrame(
392 VideoFrame::YV12A : 348 vpx_codec_alpha_ ? VideoFrame::YV12A : VideoFrame::YV12,
393 VideoFrame::YV12, 349 size,
394 size, 350 gfx::Rect(size),
395 gfx::Rect(size), 351 config_.natural_size(),
396 natural_size, 352 kNoTimestamp());
397 kNoTimestamp());
398 353
399 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 354 CopyYPlane(vpx_image->planes[VPX_PLANE_Y],
400 vpx_image->stride[VPX_PLANE_Y], 355 vpx_image->stride[VPX_PLANE_Y],
401 vpx_image->d_h, 356 vpx_image->d_h,
402 video_frame->get()); 357 video_frame->get());
403 CopyUPlane(vpx_image->planes[VPX_PLANE_U], 358 CopyUPlane(vpx_image->planes[VPX_PLANE_U],
404 vpx_image->stride[VPX_PLANE_U], 359 vpx_image->stride[VPX_PLANE_U],
405 vpx_image->d_h / 2, 360 vpx_image->d_h / 2,
406 video_frame->get()); 361 video_frame->get());
407 CopyVPlane(vpx_image->planes[VPX_PLANE_V], 362 CopyVPlane(vpx_image->planes[VPX_PLANE_V],
408 vpx_image->stride[VPX_PLANE_V], 363 vpx_image->stride[VPX_PLANE_V],
409 vpx_image->d_h / 2, 364 vpx_image->d_h / 2,
410 video_frame->get()); 365 video_frame->get());
411 if (!vpx_codec_alpha_) 366 if (!vpx_codec_alpha_)
412 return; 367 return;
413 if (!vpx_image_alpha) { 368 if (!vpx_image_alpha) {
414 MakeOpaqueAPlane( 369 MakeOpaqueAPlane(
415 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get()); 370 vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, video_frame->get());
416 return; 371 return;
417 } 372 }
418 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], 373 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
419 vpx_image->stride[VPX_PLANE_Y], 374 vpx_image->stride[VPX_PLANE_Y],
420 vpx_image->d_h, 375 vpx_image->d_h,
421 video_frame->get()); 376 video_frame->get());
422 } 377 }
423 378
424 } // namespace media 379 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698