| Index: media/filters/vpx_video_decoder.cc
|
| diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
|
| index 1d68d0cfc94f58b03ae44b72297a27290a6c006f..2ff93936bb25555e88fd50c2341febba8ad1ed14 100644
|
| --- a/media/filters/vpx_video_decoder.cc
|
| +++ b/media/filters/vpx_video_decoder.cc
|
| @@ -200,19 +200,20 @@ class VpxVideoDecoder::MemoryPool
|
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
|
| base::trace_event::ProcessMemoryDump* pmd) override;
|
|
|
| - private:
|
| - friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>;
|
| - ~MemoryPool() override;
|
| -
|
| // Reference counted frame buffers used for VP9 decoding. Reference counting
|
| // is done manually because both chromium and libvpx has to release this
|
| // before a buffer can be re-used.
|
| struct VP9FrameBuffer {
|
| VP9FrameBuffer() : ref_cnt(0) {}
|
| std::vector<uint8_t> data;
|
| + std::vector<uint8_t> alpha_data;
|
| uint32_t ref_cnt;
|
| };
|
|
|
| + private:
|
| + friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>;
|
| + ~MemoryPool() override;
|
| +
|
| // Gets the next available frame buffer for use by libvpx.
|
| VP9FrameBuffer* GetFreeFrameBuffer(size_t min_size);
|
|
|
| @@ -446,11 +447,11 @@ bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) {
|
| return false;
|
|
|
| // These are the combinations of codec-pixel format supported in principle.
|
| - // Note that VP9 does not support Alpha in the current implementation.
|
| DCHECK(
|
| (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12) ||
|
| (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12A) ||
|
| (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12) ||
|
| + (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12A) ||
|
| (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV24));
|
|
|
| #if !defined(DISABLE_FFMPEG_VIDEO_DECODERS)
|
| @@ -466,9 +467,10 @@ bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) {
|
| if (!vpx_codec_)
|
| return false;
|
|
|
| - // Configure VP9 to decode on our buffers to skip a data copy on decoding.
|
| + // Configure VP9 to decode on our buffers to skip a data copy on
|
| + // decoding. For YV12A-VP9, we use our buffers for the Y, U and V planes and
|
| + // copy the A plane.
|
| if (config.codec() == kCodecVP9) {
|
| - DCHECK_NE(PIXEL_FORMAT_YV12A, config.format());
|
| DCHECK(vpx_codec_get_caps(vpx_codec_->iface) &
|
| VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER);
|
|
|
| @@ -549,8 +551,26 @@ bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer,
|
| return false;
|
| }
|
|
|
| - if (!CopyVpxImageToVideoFrame(vpx_image, video_frame))
|
| + const vpx_image_t* vpx_image_alpha = nullptr;
|
| + AlphaDecodeStatus alpha_decode_status =
|
| + DecodeAlphaPlane(vpx_image, &vpx_image_alpha, buffer);
|
| + if (alpha_decode_status == kAlphaPlaneError) {
|
| return false;
|
| + } else if (alpha_decode_status == kNoAlphaPlaneData) {
|
| + *video_frame = nullptr;
|
| + return true;
|
| + }
|
| + if (!CopyVpxImageToVideoFrame(vpx_image, vpx_image_alpha, video_frame)) {
|
| + return false;
|
| + }
|
| + if (vpx_image_alpha && config_.codec() == kCodecVP8) {
|
| + libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
|
| + vpx_image_alpha->stride[VPX_PLANE_Y],
|
| + (*video_frame)->visible_data(VideoFrame::kAPlane),
|
| + (*video_frame)->stride(VideoFrame::kAPlane),
|
| + (*video_frame)->visible_rect().width(),
|
| + (*video_frame)->visible_rect().height());
|
| + }
|
|
|
| (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp));
|
|
|
| @@ -564,29 +584,26 @@ bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer,
|
| (*video_frame)
|
| ->metadata()
|
| ->SetInteger(VideoFrameMetadata::COLOR_SPACE, color_space);
|
| + return true;
|
| +}
|
|
|
| - if (!vpx_codec_alpha_)
|
| - return true;
|
| -
|
| - if (buffer->side_data_size() < 8) {
|
| - // TODO(mcasas): Is this a warning or an error?
|
| - DLOG(WARNING) << "Making Alpha channel opaque due to missing input";
|
| - const uint32_t kAlphaOpaqueValue = 255;
|
| - libyuv::SetPlane((*video_frame)->visible_data(VideoFrame::kAPlane),
|
| - (*video_frame)->stride(VideoFrame::kAPlane),
|
| - (*video_frame)->visible_rect().width(),
|
| - (*video_frame)->visible_rect().height(),
|
| - kAlphaOpaqueValue);
|
| - return true;
|
| +VpxVideoDecoder::AlphaDecodeStatus VpxVideoDecoder::DecodeAlphaPlane(
|
| + const struct vpx_image* vpx_image,
|
| + const struct vpx_image** vpx_image_alpha,
|
| + const scoped_refptr<DecoderBuffer>& buffer) {
|
| + if (!vpx_codec_alpha_ || buffer->side_data_size() < 8) {
|
| + return kAlphaPlaneProcessed;
|
| }
|
|
|
| // First 8 bytes of side data is |side_data_id| in big endian.
|
| const uint64_t side_data_id = base::NetToHost64(
|
| *(reinterpret_cast<const uint64_t*>(buffer->side_data())));
|
| - if (side_data_id != 1)
|
| - return true;
|
| + if (side_data_id != 1) {
|
| + return kAlphaPlaneProcessed;
|
| + }
|
|
|
| - // Try and decode buffer->side_data() minus the first 8 bytes as a full frame.
|
| + // Try and decode buffer->side_data() minus the first 8 bytes as a full
|
| + // frame.
|
| int64_t timestamp_alpha = buffer->timestamp().InMicroseconds();
|
| void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha);
|
| {
|
| @@ -598,48 +615,56 @@ bool VpxVideoDecoder::VpxDecode(const scoped_refptr<DecoderBuffer>& buffer,
|
| if (status != VPX_CODEC_OK) {
|
| DLOG(ERROR) << "vpx_codec_decode() failed for the alpha: "
|
| << vpx_codec_error(vpx_codec_);
|
| - return false;
|
| + return kAlphaPlaneError;
|
| }
|
| }
|
|
|
| vpx_codec_iter_t iter_alpha = NULL;
|
| - const vpx_image_t* vpx_image_alpha =
|
| - vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha);
|
| - if (!vpx_image_alpha) {
|
| - *video_frame = nullptr;
|
| - return true;
|
| + *vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha);
|
| + if (!(*vpx_image_alpha)) {
|
| + return kNoAlphaPlaneData;
|
| }
|
|
|
| - if (vpx_image_alpha->user_priv != user_priv_alpha) {
|
| + if ((*vpx_image_alpha)->user_priv != user_priv_alpha) {
|
| DLOG(ERROR) << "Invalid output timestamp on alpha.";
|
| - return false;
|
| + return kAlphaPlaneError;
|
| }
|
|
|
| - if (vpx_image_alpha->d_h != vpx_image->d_h ||
|
| - vpx_image_alpha->d_w != vpx_image->d_w) {
|
| + if ((*vpx_image_alpha)->d_h != vpx_image->d_h ||
|
| + (*vpx_image_alpha)->d_w != vpx_image->d_w) {
|
| DLOG(ERROR) << "The alpha plane dimensions are not the same as the "
|
| "image dimensions.";
|
| - return false;
|
| + return kAlphaPlaneError;
|
| }
|
|
|
| - libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y],
|
| - vpx_image_alpha->stride[VPX_PLANE_Y],
|
| - (*video_frame)->visible_data(VideoFrame::kAPlane),
|
| - (*video_frame)->stride(VideoFrame::kAPlane),
|
| - (*video_frame)->visible_rect().width(),
|
| - (*video_frame)->visible_rect().height());
|
| - return true;
|
| + if (config_.codec() == kCodecVP9) {
|
| + VpxVideoDecoder::MemoryPool::VP9FrameBuffer* frame_buffer =
|
| + static_cast<VpxVideoDecoder::MemoryPool::VP9FrameBuffer*>(
|
| + vpx_image->fb_priv);
|
| + uint64_t alpha_plane_size =
|
| + (*vpx_image_alpha)->stride[VPX_PLANE_Y] * (*vpx_image_alpha)->d_h;
|
| + if (frame_buffer->alpha_data.size() < alpha_plane_size) {
|
| + frame_buffer->alpha_data.resize(alpha_plane_size);
|
| + }
|
| + libyuv::CopyPlane((*vpx_image_alpha)->planes[VPX_PLANE_Y],
|
| + (*vpx_image_alpha)->stride[VPX_PLANE_Y],
|
| + &frame_buffer->alpha_data[0],
|
| + (*vpx_image_alpha)->stride[VPX_PLANE_Y],
|
| + (*vpx_image_alpha)->d_w, (*vpx_image_alpha)->d_h);
|
| + }
|
| + return kAlphaPlaneProcessed;
|
| }
|
|
|
| bool VpxVideoDecoder::CopyVpxImageToVideoFrame(
|
| const struct vpx_image* vpx_image,
|
| + const struct vpx_image* vpx_image_alpha,
|
| scoped_refptr<VideoFrame>* video_frame) {
|
| DCHECK(vpx_image);
|
|
|
| VideoPixelFormat codec_format;
|
| switch (vpx_image->fmt) {
|
| case VPX_IMG_FMT_I420:
|
| - codec_format = vpx_codec_alpha_ ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12;
|
| + codec_format = vpx_image_alpha ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12;
|
| break;
|
|
|
| case VPX_IMG_FMT_I444:
|
| @@ -660,17 +685,25 @@ bool VpxVideoDecoder::CopyVpxImageToVideoFrame(
|
|
|
| if (memory_pool_.get()) {
|
| DCHECK_EQ(kCodecVP9, config_.codec());
|
| - DCHECK(!vpx_codec_alpha_) << "Uh-oh, VP9 and Alpha shouldn't coexist.";
|
| - *video_frame = VideoFrame::WrapExternalYuvData(
|
| - codec_format,
|
| - coded_size, gfx::Rect(visible_size), config_.natural_size(),
|
| - vpx_image->stride[VPX_PLANE_Y],
|
| - vpx_image->stride[VPX_PLANE_U],
|
| - vpx_image->stride[VPX_PLANE_V],
|
| - vpx_image->planes[VPX_PLANE_Y],
|
| - vpx_image->planes[VPX_PLANE_U],
|
| - vpx_image->planes[VPX_PLANE_V],
|
| - kNoTimestamp());
|
| + if (vpx_image_alpha) {
|
| + VpxVideoDecoder::MemoryPool::VP9FrameBuffer* frame_buffer =
|
| + static_cast<VpxVideoDecoder::MemoryPool::VP9FrameBuffer*>(
|
| + vpx_image->fb_priv);
|
| + *video_frame = VideoFrame::WrapExternalYuvaData(
|
| + codec_format, coded_size, gfx::Rect(visible_size),
|
| + config_.natural_size(), vpx_image->stride[VPX_PLANE_Y],
|
| + vpx_image->stride[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_V],
|
| + vpx_image_alpha->stride[VPX_PLANE_Y], vpx_image->planes[VPX_PLANE_Y],
|
| + vpx_image->planes[VPX_PLANE_U], vpx_image->planes[VPX_PLANE_V],
|
| + &frame_buffer->alpha_data[0], kNoTimestamp());
|
| + } else {
|
| + *video_frame = VideoFrame::WrapExternalYuvData(
|
| + codec_format, coded_size, gfx::Rect(visible_size),
|
| + config_.natural_size(), vpx_image->stride[VPX_PLANE_Y],
|
| + vpx_image->stride[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_V],
|
| + vpx_image->planes[VPX_PLANE_Y], vpx_image->planes[VPX_PLANE_U],
|
| + vpx_image->planes[VPX_PLANE_V], kNoTimestamp());
|
| + }
|
| if (!(*video_frame))
|
| return false;
|
|
|
|
|