| Index: media/filters/vpx_video_decoder.cc
|
| diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
|
| index baab01741ab4a49bd3a02df5e400b0b80bbf0d12..c07c1b12ce381269996fbc720506eaca846396d3 100644
|
| --- a/media/filters/vpx_video_decoder.cc
|
| +++ b/media/filters/vpx_video_decoder.cc
|
| @@ -11,6 +11,7 @@
|
| #include "base/logging.h"
|
| #include "base/message_loop_proxy.h"
|
| #include "base/string_number_conversions.h"
|
| +#include "base/sys_byteorder.h"
|
| #include "media/base/bind_to_loop.h"
|
| #include "media/base/decoder_buffer.h"
|
| #include "media/base/demuxer_stream.h"
|
| @@ -60,7 +61,8 @@ VpxVideoDecoder::VpxVideoDecoder(
|
| : message_loop_(message_loop),
|
| weak_factory_(this),
|
| state_(kUninitialized),
|
| - vpx_codec_(NULL) {
|
| + vpx_codec_(NULL),
|
| + vpx_codec_alpha_(NULL) {
|
| }
|
|
|
| VpxVideoDecoder::~VpxVideoDecoder() {
|
| @@ -94,6 +96,28 @@ void VpxVideoDecoder::Initialize(
|
| status_cb.Run(PIPELINE_OK);
|
| }
|
|
|
| +static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context,
|
| + const VideoDecoderConfig& config) {
|
| + context = 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(context,
|
| + 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 context;
|
| + return NULL;
|
| + }
|
| + return context;
|
| +}
|
| +
|
| bool VpxVideoDecoder::ConfigureDecoder() {
|
| const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
|
| if (!config.IsValidConfig()) {
|
| @@ -102,26 +126,29 @@ 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_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_config,
|
| - 0);
|
| - if (status != VPX_CODEC_OK) {
|
| - LOG(ERROR) << "vpx_codec_dec_init failed, status=" << status;
|
| - delete vpx_codec_;
|
| - vpx_codec_ = NULL;
|
| + vpx_codec_ = InitializeVpxContext(vpx_codec_, config);
|
| + if (!vpx_codec_)
|
| return false;
|
| +
|
| + if (config.format() == VideoFrame::YV12A) {
|
| + vpx_codec_alpha_ = InitializeVpxContext(vpx_codec_alpha_, config);
|
| + if (!vpx_codec_alpha_)
|
| + return false;
|
| }
|
|
|
| return true;
|
| @@ -133,6 +160,11 @@ void VpxVideoDecoder::CloseDecoder() {
|
| delete vpx_codec_;
|
| vpx_codec_ = NULL;
|
| }
|
| + if (vpx_codec_alpha_) {
|
| + vpx_codec_destroy(vpx_codec_alpha_);
|
| + delete vpx_codec_alpha_;
|
| + vpx_codec_alpha_ = NULL;
|
| + }
|
| }
|
|
|
| void VpxVideoDecoder::Read(const ReadCB& read_cb) {
|
| @@ -248,7 +280,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);
|
| @@ -295,7 +327,44 @@ bool VpxVideoDecoder::Decode(
|
| return false;
|
| }
|
|
|
| - CopyVpxImageTo(vpx_image, video_frame);
|
| + const vpx_image_t* vpx_image_alpha = NULL;
|
| + if (vpx_codec_alpha_ && buffer->GetSideDataSize() >= 8) {
|
| + // Pass alpha data to libvpx.
|
| + int64 timestamp_alpha = buffer->GetTimestamp().InMicroseconds();
|
| + void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha);
|
| +
|
| + // First 8 bytes of side data is side_data_id in big endian.
|
| + const uint64 side_data_id = base::NetToHost64(
|
| + *(reinterpret_cast<const uint64*>(buffer->GetSideData())));
|
| + if (side_data_id == 1) {
|
| + status = vpx_codec_decode(vpx_codec_alpha_,
|
| + 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_, &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;
|
| }
|
| @@ -310,6 +379,7 @@ void VpxVideoDecoder::DoReset() {
|
|
|
| void VpxVideoDecoder::CopyVpxImageTo(
|
| const 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);
|
| @@ -321,11 +391,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_ ?
|
| + 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,
|
| @@ -338,6 +411,17 @@ void VpxVideoDecoder::CopyVpxImageTo(
|
| vpx_image->stride[VPX_PLANE_V],
|
| vpx_image->d_h / 2,
|
| *video_frame);
|
| + if (!vpx_codec_alpha_)
|
| + return;
|
| + if (!vpx_image_alpha) {
|
| + MakeOpaqueAPlane(vpx_image->stride[VPX_PLANE_Y], vpx_image->d_h,
|
| + *video_frame);
|
| + return;
|
| + }
|
| + CopyAPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
|
| + vpx_image->stride[VPX_PLANE_Y],
|
| + vpx_image->d_h,
|
| + *video_frame);
|
| }
|
|
|
| } // namespace media
|
|
|