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

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

Issue 12263013: media: Add support for playback of VP8 Alpha video streams (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: minor fixes Created 7 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 | Annotate | Revision Log
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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 52
53 decode_threads = std::max(decode_threads, 0); 53 decode_threads = std::max(decode_threads, 0);
54 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 54 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
55 return decode_threads; 55 return decode_threads;
56 } 56 }
57 57
58 VpxVideoDecoder::VpxVideoDecoder( 58 VpxVideoDecoder::VpxVideoDecoder(
59 const scoped_refptr<base::MessageLoopProxy>& message_loop) 59 const scoped_refptr<base::MessageLoopProxy>& message_loop)
60 : message_loop_(message_loop), 60 : message_loop_(message_loop),
61 state_(kUninitialized), 61 state_(kUninitialized),
62 vpx_codec_(NULL) { 62 vpx_codec_(NULL),
63 vpx_codec_alpha_(NULL) {
63 } 64 }
64 65
65 VpxVideoDecoder::~VpxVideoDecoder() { 66 VpxVideoDecoder::~VpxVideoDecoder() {
66 DCHECK_EQ(kUninitialized, state_); 67 DCHECK_EQ(kUninitialized, state_);
67 CloseDecoder(); 68 CloseDecoder();
68 } 69 }
69 70
70 void VpxVideoDecoder::Initialize( 71 void VpxVideoDecoder::Initialize(
71 const scoped_refptr<DemuxerStream>& stream, 72 const scoped_refptr<DemuxerStream>& stream,
72 const PipelineStatusCB& status_cb, 73 const PipelineStatusCB& status_cb,
(...skipping 20 matching lines...) Expand all
93 } 94 }
94 95
95 bool VpxVideoDecoder::ConfigureDecoder() { 96 bool VpxVideoDecoder::ConfigureDecoder() {
96 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config(); 97 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
97 if (!config.IsValidConfig()) { 98 if (!config.IsValidConfig()) {
98 DLOG(ERROR) << "Invalid video stream config: " 99 DLOG(ERROR) << "Invalid video stream config: "
99 << config.AsHumanReadableString(); 100 << config.AsHumanReadableString();
100 return false; 101 return false;
101 } 102 }
102 103
103 if (config.codec() != kCodecVP9) 104 format_ = config.format();
scherkus (not reviewing) 2013/02/22 23:18:01 it looks like the only reason for storing format_
vignesh 2013/02/25 21:51:42 Done.
104 return false; 105 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
106 bool can_handle = false;
107 if (cmd_line->HasSwitch(switches::kEnableVp9Playback) &&
108 config.codec() == kCodecVP9) {
109 can_handle = true;
scherkus (not reviewing) 2013/02/22 23:18:01 de-indent by 2
vignesh 2013/02/25 21:51:42 Done.
110 }
111 if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) &&
112 config.codec() == kCodecVP8 && format_ == VideoFrame::YV12A) {
113 can_handle = true;
114 }
115 if (!can_handle)
116 return false;
scherkus (not reviewing) 2013/02/22 23:18:01 de-indent by 2
vignesh 2013/02/25 21:51:42 Done.
105 117
106 CloseDecoder(); 118 CloseDecoder();
107 119
108 vpx_codec_ = new vpx_codec_ctx(); 120 vpx_codec_ = new vpx_codec_ctx();
109 vpx_codec_dec_cfg_t vpx_config = {0}; 121 vpx_codec_dec_cfg_t vpx_config = {0};
110 vpx_config.w = config.coded_size().width(); 122 vpx_config.w = config.coded_size().width();
111 vpx_config.h = config.coded_size().height(); 123 vpx_config.h = config.coded_size().height();
112 vpx_config.threads = GetThreadCount(); 124 vpx_config.threads = GetThreadCount();
113 125
114 vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_, 126 vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_,
115 vpx_codec_vp9_dx(), 127 config.codec() == kCodecVP9 ?
128 vpx_codec_vp9_dx() :
129 vpx_codec_vp8_dx(),
116 &vpx_config, 130 &vpx_config,
117 0); 131 0);
118 if (status != VPX_CODEC_OK) { 132 if (status != VPX_CODEC_OK) {
119 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; 133 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status;
120 delete vpx_codec_; 134 delete vpx_codec_;
121 vpx_codec_ = NULL; 135 vpx_codec_ = NULL;
122 return false; 136 return false;
123 } 137 }
124 138
139 if(format_ == VideoFrame::YV12A) {
scherkus (not reviewing) 2013/02/22 23:18:01 add space between if and (
vignesh 2013/02/25 21:51:42 Done.
140 vpx_codec_alpha_ = new vpx_codec_ctx();
141 vpx_codec_dec_cfg_t vpx_config_alpha = {0};
142
143 vpx_config_alpha.w = config.coded_size().width();
144 vpx_config_alpha.h = config.coded_size().height();
145 vpx_config_alpha.threads = GetThreadCount();
146
147 status = vpx_codec_dec_init(vpx_codec_alpha_,
148 vpx_codec_vp8_dx(),
149 &vpx_config_alpha,
150 0);
151 if (status != VPX_CODEC_OK) {
152 LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status;
153 delete vpx_codec_alpha_;
154 vpx_codec_alpha_ = NULL;
155 return false;
156 }
157 }
158
125 return true; 159 return true;
126 } 160 }
127 161
128 void VpxVideoDecoder::CloseDecoder() { 162 void VpxVideoDecoder::CloseDecoder() {
129 if (vpx_codec_) { 163 if (vpx_codec_) {
130 vpx_codec_destroy(vpx_codec_); 164 vpx_codec_destroy(vpx_codec_);
131 delete vpx_codec_; 165 delete vpx_codec_;
132 vpx_codec_ = NULL; 166 vpx_codec_ = NULL;
133 } 167 }
168 if (vpx_codec_alpha_) {
169 vpx_codec_destroy(vpx_codec_alpha_);
170 delete vpx_codec_alpha_;
171 vpx_codec_alpha_ = NULL;
172 }
134 } 173 }
135 174
136 void VpxVideoDecoder::Read(const ReadCB& read_cb) { 175 void VpxVideoDecoder::Read(const ReadCB& read_cb) {
137 DCHECK(message_loop_->BelongsToCurrentThread()); 176 DCHECK(message_loop_->BelongsToCurrentThread());
138 DCHECK(!read_cb.is_null()); 177 DCHECK(!read_cb.is_null());
139 CHECK_NE(state_, kUninitialized); 178 CHECK_NE(state_, kUninitialized);
140 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; 179 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
141 read_cb_ = BindToCurrentLoop(read_cb); 180 read_cb_ = BindToCurrentLoop(read_cb);
142 181
143 // Return empty frames if decoding has finished. 182 // Return empty frames if decoding has finished.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 } 278 }
240 279
241 scoped_refptr<VideoFrame> video_frame; 280 scoped_refptr<VideoFrame> video_frame;
242 if (!Decode(buffer, &video_frame)) { 281 if (!Decode(buffer, &video_frame)) {
243 state_ = kDecodeFinished; 282 state_ = kDecodeFinished;
244 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 283 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
245 return; 284 return;
246 } 285 }
247 286
248 // Any successful decode counts! 287 // Any successful decode counts!
249 if (buffer->GetDataSize()) { 288 if (buffer->GetDataSize() && buffer->GetSideDataSize()) {
250 PipelineStatistics statistics; 289 PipelineStatistics statistics;
251 statistics.video_bytes_decoded = buffer->GetDataSize(); 290 statistics.video_bytes_decoded = buffer->GetDataSize();
252 statistics_cb_.Run(statistics); 291 statistics_cb_.Run(statistics);
253 } 292 }
254 293
255 // If we didn't get a frame we need more data. 294 // If we didn't get a frame we need more data.
256 if (!video_frame) { 295 if (!video_frame) {
257 ReadFromDemuxerStream(); 296 ReadFromDemuxerStream();
258 return; 297 return;
259 } 298 }
(...skipping 26 matching lines...) Expand all
286 if (!vpx_image) { 325 if (!vpx_image) {
287 *video_frame = NULL; 326 *video_frame = NULL;
288 return true; 327 return true;
289 } 328 }
290 329
291 if (vpx_image->user_priv != reinterpret_cast<void*>(&timestamp)) { 330 if (vpx_image->user_priv != reinterpret_cast<void*>(&timestamp)) {
292 LOG(ERROR) << "Invalid output timestamp."; 331 LOG(ERROR) << "Invalid output timestamp.";
293 return false; 332 return false;
294 } 333 }
295 334
296 CopyVpxImageTo(vpx_image, video_frame); 335 const vpx_image_t* vpx_image_alpha = NULL;
336 if(format_ == VideoFrame::YV12A) {
scherkus (not reviewing) 2013/02/22 23:18:01 add space between if and (
vignesh 2013/02/25 21:51:42 Done.
337
scherkus (not reviewing) 2013/02/22 23:18:01 nit: remove extra blank line
vignesh 2013/02/25 21:51:42 Done.
338 // Pass alpha data to libvpx.
339 int64 timestamp_alpha = buffer->GetTimestamp().InMicroseconds();
340 void* user_priv_alpha = reinterpret_cast<void*>(&timestamp_alpha);
341 const uint8* side_data_id_buf = buffer->GetSideData();
342 uint64_t side_data_id = side_data_id_buf[0];
343 for (size_t i = 1; i < 8; ++i) {
scherkus (not reviewing) 2013/02/22 23:18:01 what's all this stuff doing?
vignesh 2013/02/25 21:51:42 first 8 bytes of side_data is side_data_id in big
344 side_data_id <<= 8;
345 side_data_id |= side_data_id_buf[i];
346 }
347 if (side_data_id == 1) {
348 status = vpx_codec_decode(vpx_codec_alpha_,
349 buffer->GetSideData() + 8,
scherkus (not reviewing) 2013/02/22 23:18:01 what's the magic +8 for?
vignesh 2013/02/25 21:51:42 first 8 bytes of side_data is side_data_id and the
350 buffer->GetSideDataSize() - 8,
351 user_priv_alpha,
352 0);
353
354 if (status != VPX_CODEC_OK) {
355 LOG(ERROR) << "vpx_codec_decode() failed on alpha, status=" << status;
356 return false;
357 }
358
359 // Gets pointer to decoded data.
360 vpx_codec_iter_t iter_alpha = NULL;
361 vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha);
362 if (!vpx_image_alpha) {
363 *video_frame = NULL;
364 return true;
365 }
366
367 if (vpx_image_alpha->user_priv !=
368 reinterpret_cast<void*>(&timestamp_alpha)) {
369 LOG(ERROR) << "Invalid output timestamp on alpha.";
370 return false;
371 }
372 }
373 }
374
375 CopyVpxImageTo(vpx_image, vpx_image_alpha, video_frame);
297 (*video_frame)->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); 376 (*video_frame)->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp));
298 return true; 377 return true;
299 } 378 }
300 379
301 void VpxVideoDecoder::DoReset() { 380 void VpxVideoDecoder::DoReset() {
302 DCHECK(read_cb_.is_null()); 381 DCHECK(read_cb_.is_null());
303 382
304 state_ = kNormal; 383 state_ = kNormal;
305 reset_cb_.Run(); 384 reset_cb_.Run();
306 reset_cb_.Reset(); 385 reset_cb_.Reset();
307 } 386 }
308 387
309 void VpxVideoDecoder::CopyVpxImageTo( 388 void VpxVideoDecoder::CopyVpxImageTo(
310 const vpx_image* vpx_image, 389 const struct vpx_image* vpx_image,
390 const struct vpx_image* vpx_image_alpha,
311 scoped_refptr<VideoFrame>* video_frame) { 391 scoped_refptr<VideoFrame>* video_frame) {
312 CHECK(vpx_image); 392 CHECK(vpx_image);
313 CHECK_EQ(vpx_image->d_w % 2, 0U); 393 CHECK_EQ(vpx_image->d_w % 2, 0U);
314 CHECK_EQ(vpx_image->d_h % 2, 0U); 394 CHECK_EQ(vpx_image->d_h % 2, 0U);
315 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 || 395 CHECK(vpx_image->fmt == VPX_IMG_FMT_I420 ||
316 vpx_image->fmt == VPX_IMG_FMT_YV12); 396 vpx_image->fmt == VPX_IMG_FMT_YV12);
317 397
318 gfx::Size size(vpx_image->d_w, vpx_image->d_h); 398 gfx::Size size(vpx_image->d_w, vpx_image->d_h);
319 gfx::Size natural_size = 399 gfx::Size natural_size =
320 demuxer_stream_->video_decoder_config().natural_size(); 400 demuxer_stream_->video_decoder_config().natural_size();
321 401
322 *video_frame = VideoFrame::CreateFrame(VideoFrame::YV12, 402 *video_frame = VideoFrame::CreateFrame(format_,
323 size, 403 size,
324 gfx::Rect(size), 404 gfx::Rect(size),
325 natural_size, 405 natural_size,
326 kNoTimestamp()); 406 kNoTimestamp());
407
327 CopyYPlane(vpx_image->planes[VPX_PLANE_Y], 408 CopyYPlane(vpx_image->planes[VPX_PLANE_Y],
328 vpx_image->stride[VPX_PLANE_Y], 409 vpx_image->stride[VPX_PLANE_Y],
329 vpx_image->d_h, 410 vpx_image->d_h,
330 *video_frame); 411 *video_frame);
331 CopyUPlane(vpx_image->planes[VPX_PLANE_U], 412 CopyUPlane(vpx_image->planes[VPX_PLANE_U],
332 vpx_image->stride[VPX_PLANE_U], 413 vpx_image->stride[VPX_PLANE_U],
333 vpx_image->d_h / 2, 414 vpx_image->d_h / 2,
334 *video_frame); 415 *video_frame);
335 CopyVPlane(vpx_image->planes[VPX_PLANE_V], 416 CopyVPlane(vpx_image->planes[VPX_PLANE_V],
336 vpx_image->stride[VPX_PLANE_V], 417 vpx_image->stride[VPX_PLANE_V],
337 vpx_image->d_h / 2, 418 vpx_image->d_h / 2,
338 *video_frame); 419 *video_frame);
420 if(format_ == VideoFrame::YV12A) {
scherkus (not reviewing) 2013/02/22 23:18:01 add space between if and (
vignesh 2013/02/25 21:51:42 Done.
421 if(vpx_image_alpha) {
scherkus (not reviewing) 2013/02/22 23:18:01 are we guaranteed to always produce an alpha image
vignesh 2013/02/25 21:51:42 yes. because there could be video files with no al
422 CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
423 vpx_image->stride[VPX_PLANE_Y],
424 vpx_image->d_h,
425 *video_frame);
426 } else {
427 /* there is no alpha. set it to opaque */
scherkus (not reviewing) 2013/02/22 23:18:01 use // for comments
vignesh 2013/02/25 21:51:42 Done.
428 uint64_t alpha_plane_size = vpx_image->stride[VPX_PLANE_Y] *
429 vpx_image->d_h;
430 unsigned char* alpha_plane = static_cast<unsigned char*>(
431 malloc(alpha_plane_size));
scherkus (not reviewing) 2013/02/22 23:18:01 this seems a bit silly: we're allocating a frame,
vignesh 2013/02/25 21:51:42 Adding a ClearAPlane function. Although, the notio
432 memset(alpha_plane, 255, alpha_plane_size);
433 CopyAPlane(alpha_plane,
434 vpx_image->stride[VPX_PLANE_Y],
435 vpx_image->d_h,
436 *video_frame);
437 free(alpha_plane);
438 }
439 }
339 } 440 }
340 441
341 } // namespace media 442 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698