| 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..76054eb1cbd26dd087782f94c606c9f119c4280e 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"
|
| @@ -20,15 +21,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 +50,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(
|
| @@ -92,45 +82,60 @@ void VpxVideoDecoder::Initialize(
|
| status_cb.Run(PIPELINE_OK);
|
| }
|
|
|
| -bool VpxVideoDecoder::ConfigureDecoder() {
|
| - const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
|
| - if (!config.IsValidConfig()) {
|
| - DLOG(ERROR) << "Invalid video stream config: "
|
| - << config.AsHumanReadableString();
|
| - return false;
|
| - }
|
| -
|
| - if (config.codec() != kCodecVP9)
|
| - return false;
|
| -
|
| - CloseDecoder();
|
| -
|
| - vpx_codec_ = new vpx_codec_ctx();
|
| +static scoped_ptr<vpx_codec_ctx, VpxDeleter> InitializeVpxContext(
|
| + scoped_ptr<vpx_codec_ctx, VpxDeleter> context,
|
| + const VideoDecoderConfig& config) {
|
| + context.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(context.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;
|
| + context.reset();
|
| + }
|
| + return context.Pass();
|
| +}
|
| +
|
| +bool VpxVideoDecoder::ConfigureDecoder() {
|
| + const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
|
| + if (!config.IsValidConfig()) {
|
| + DLOG(ERROR) << "Invalid video stream config: "
|
| + << config.AsHumanReadableString();
|
| return false;
|
| }
|
|
|
| - return true;
|
| -}
|
| + 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;
|
| +
|
| + vpx_codec_ = InitializeVpxContext(vpx_codec_.Pass(), config);
|
| + if (!vpx_codec_.get())
|
| + return false;
|
|
|
| -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_ = InitializeVpxContext(vpx_codec_alpha_.Pass(), config);
|
| + if (!vpx_codec_alpha_.get())
|
| + return false;
|
| }
|
| +
|
| + return true;
|
| }
|
|
|
| void VpxVideoDecoder::Read(const ReadCB& read_cb) {
|
| @@ -246,7 +251,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 +275,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 +287,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 +298,45 @@ bool VpxVideoDecoder::Decode(
|
| return false;
|
| }
|
|
|
| - CopyVpxImageTo(vpx_image, video_frame);
|
| + const vpx_image_t* vpx_image_alpha = NULL;
|
| + if (vpx_codec_alpha_.get() && 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_.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 +350,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 +363,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 +383,17 @@ void VpxVideoDecoder::CopyVpxImageTo(
|
| vpx_image->stride[VPX_PLANE_V],
|
| vpx_image->d_h / 2,
|
| *video_frame);
|
| + if (!vpx_codec_alpha_.get())
|
| + 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
|
|
|