Chromium Code Reviews| Index: media/filters/vpx_video_decoder.cc |
| diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc |
| index 0b92a7d8459c4e152bbd7261b56ce7dcc1c32ffe..c782e3e2e4b372682065598f5168ae0e318893c2 100644 |
| --- a/media/filters/vpx_video_decoder.cc |
| +++ b/media/filters/vpx_video_decoder.cc |
| @@ -20,15 +20,6 @@ |
| #include "media/base/video_frame.h" |
| #include "media/base/video_util.h" |
| -// Include libvpx header files. |
| -// VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide |
| -// backwards compatibility for legacy applications using the library. |
| -#define VPX_CODEC_DISABLE_COMPAT 1 |
| -extern "C" { |
| -#include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" |
| -#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
| -} |
| - |
| namespace media { |
| // Always try to use three threads for video decoding. There is little reason |
| @@ -58,13 +49,11 @@ static int GetThreadCount() { |
| VpxVideoDecoder::VpxVideoDecoder( |
| const scoped_refptr<base::MessageLoopProxy>& message_loop) |
| : message_loop_(message_loop), |
| - state_(kUninitialized), |
| - vpx_codec_(NULL) { |
| + state_(kUninitialized) { |
| } |
| VpxVideoDecoder::~VpxVideoDecoder() { |
| DCHECK_EQ(kUninitialized, state_); |
| - CloseDecoder(); |
| } |
| void VpxVideoDecoder::Initialize( |
| @@ -100,37 +89,55 @@ bool VpxVideoDecoder::ConfigureDecoder() { |
| return false; |
| } |
| - if (config.codec() != kCodecVP9) |
| + const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| + bool can_handle = false; |
| + if (cmd_line->HasSwitch(switches::kEnableVp9Playback) && |
| + config.codec() == kCodecVP9) { |
| + can_handle = true; |
| + } |
| + if (cmd_line->HasSwitch(switches::kEnableVp8AlphaPlayback) && |
| + config.codec() == kCodecVP8 && config.format() == VideoFrame::YV12A) { |
| + can_handle = true; |
| + } |
| + if (!can_handle) |
| return false; |
| - CloseDecoder(); |
| - |
| - vpx_codec_ = new vpx_codec_ctx(); |
| + vpx_codec_.reset(new vpx_codec_ctx()); |
| vpx_codec_dec_cfg_t vpx_config = {0}; |
| vpx_config.w = config.coded_size().width(); |
| vpx_config.h = config.coded_size().height(); |
| vpx_config.threads = GetThreadCount(); |
| - vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_, |
| - vpx_codec_vp9_dx(), |
| + vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_.get(), |
| + config.codec() == kCodecVP9 ? |
| + vpx_codec_vp9_dx() : |
| + vpx_codec_vp8_dx(), |
| &vpx_config, |
| 0); |
| if (status != VPX_CODEC_OK) { |
| LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; |
| - delete vpx_codec_; |
| - vpx_codec_ = NULL; |
| return false; |
| } |
| - return true; |
| -} |
| - |
| -void VpxVideoDecoder::CloseDecoder() { |
| - if (vpx_codec_) { |
| - vpx_codec_destroy(vpx_codec_); |
| - delete vpx_codec_; |
| - vpx_codec_ = NULL; |
| + if (config.format() == VideoFrame::YV12A) { |
| + vpx_codec_alpha_.reset(new vpx_codec_ctx()); |
| + vpx_codec_dec_cfg_t vpx_config_alpha = {0}; |
| + |
| + vpx_config_alpha.w = config.coded_size().width(); |
| + vpx_config_alpha.h = config.coded_size().height(); |
| + vpx_config_alpha.threads = GetThreadCount(); |
| + |
| + status = vpx_codec_dec_init(vpx_codec_alpha_.get(), |
| + vpx_codec_vp8_dx(), |
| + &vpx_config_alpha, |
| + 0); |
| + if (status != VPX_CODEC_OK) { |
| + LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status; |
| + return false; |
| + } |
| } |
| + |
| + return true; |
| } |
| void VpxVideoDecoder::Read(const ReadCB& read_cb) { |
| @@ -246,7 +253,7 @@ void VpxVideoDecoder::DecodeBuffer( |
| } |
| // Any successful decode counts! |
| - if (buffer->GetDataSize()) { |
| + if (buffer->GetDataSize() && buffer->GetSideDataSize()) { |
| PipelineStatistics statistics; |
| statistics.video_bytes_decoded = buffer->GetDataSize(); |
| statistics_cb_.Run(statistics); |
| @@ -270,7 +277,7 @@ bool VpxVideoDecoder::Decode( |
| // Pass |buffer| to libvpx. |
| int64 timestamp = buffer->GetTimestamp().InMicroseconds(); |
| void* user_priv = reinterpret_cast<void*>(×tamp); |
| - vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, |
| + vpx_codec_err_t status = vpx_codec_decode(vpx_codec_.get(), |
| buffer->GetData(), |
| buffer->GetDataSize(), |
| user_priv, |
| @@ -282,7 +289,7 @@ bool VpxVideoDecoder::Decode( |
| // Gets pointer to decoded data. |
| vpx_codec_iter_t iter = NULL; |
| - const vpx_image_t* vpx_image = vpx_codec_get_frame(vpx_codec_, &iter); |
| + const vpx_image_t* vpx_image = vpx_codec_get_frame(vpx_codec_.get(), &iter); |
| if (!vpx_image) { |
| *video_frame = NULL; |
| return true; |
| @@ -293,7 +300,48 @@ bool VpxVideoDecoder::Decode( |
| return false; |
| } |
| - CopyVpxImageTo(vpx_image, video_frame); |
| + const vpx_image_t* vpx_image_alpha = NULL; |
| + if (vpx_codec_alpha_.get()) { |
| + // Pass alpha data to libvpx. |
| + int64 timestamp_alpha = buffer->GetTimestamp().InMicroseconds(); |
| + void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha); |
| + const uint8* side_data_id_buf = buffer->GetSideData(); |
| + // First 8 bytes of side data is side_data_id in big endian. |
| + uint64_t side_data_id = side_data_id_buf[0]; |
| + for (size_t i = 1; i < 8; ++i) { |
| + side_data_id <<= 8; |
| + side_data_id |= side_data_id_buf[i]; |
| + } |
| + if (side_data_id == 1) { |
| + status = vpx_codec_decode(vpx_codec_alpha_.get(), |
| + buffer->GetSideData() + 8, |
| + buffer->GetSideDataSize() - 8, |
| + user_priv_alpha, |
| + 0); |
| + |
| + if (status != VPX_CODEC_OK) { |
| + LOG(ERROR) << "vpx_codec_decode() failed on alpha, status=" << status; |
| + return false; |
| + } |
| + |
| + // Gets pointer to decoded data. |
| + vpx_codec_iter_t iter_alpha = NULL; |
| + vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_.get(), |
| + &iter_alpha); |
| + if (!vpx_image_alpha) { |
| + *video_frame = NULL; |
| + return true; |
| + } |
| + |
| + if (vpx_image_alpha->user_priv != |
| + reinterpret_cast<void*>(×tamp_alpha)) { |
| + LOG(ERROR) << "Invalid output timestamp on alpha."; |
| + return false; |
| + } |
| + } |
| + } |
| + |
| + CopyVpxImageTo(vpx_image, vpx_image_alpha, video_frame); |
| (*video_frame)->SetTimestamp(base::TimeDelta::FromMicroseconds(timestamp)); |
| return true; |
| } |
| @@ -307,7 +355,8 @@ void VpxVideoDecoder::DoReset() { |
| } |
| void VpxVideoDecoder::CopyVpxImageTo( |
| - const vpx_image* vpx_image, |
| + const struct vpx_image* vpx_image, |
| + const struct vpx_image* vpx_image_alpha, |
| scoped_refptr<VideoFrame>* video_frame) { |
| CHECK(vpx_image); |
| CHECK_EQ(vpx_image->d_w % 2, 0U); |
| @@ -319,11 +368,14 @@ void VpxVideoDecoder::CopyVpxImageTo( |
| gfx::Size natural_size = |
| demuxer_stream_->video_decoder_config().natural_size(); |
| - *video_frame = VideoFrame::CreateFrame(VideoFrame::YV12, |
| + *video_frame = VideoFrame::CreateFrame(vpx_codec_alpha_.get() ? |
| + VideoFrame::YV12A : |
| + VideoFrame::YV12, |
| size, |
| gfx::Rect(size), |
| natural_size, |
| kNoTimestamp()); |
| + |
| CopyYPlane(vpx_image->planes[VPX_PLANE_Y], |
| vpx_image->stride[VPX_PLANE_Y], |
| vpx_image->d_h, |
| @@ -336,6 +388,17 @@ void VpxVideoDecoder::CopyVpxImageTo( |
| vpx_image->stride[VPX_PLANE_V], |
| vpx_image->d_h / 2, |
| *video_frame); |
| + if (vpx_codec_alpha_.get()) { |
| + if(vpx_image_alpha) { |
|
scherkus (not reviewing)
2013/02/27 07:28:26
add space between if and (
vignesh
2013/03/28 21:45:12
Done.
|
| + CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y], |
| + vpx_image->stride[VPX_PLANE_Y], |
| + vpx_image->d_h, |
| + *video_frame); |
| + } else { |
| + MakeOpaqueAPlane(vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h, |
| + *video_frame); |
| + } |
| + } |
| } |
| } // namespace media |