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

Unified Diff: media/filters/vpx_video_decoder.cc

Issue 2096813002: media/vpx: Add support for VP9 alpha channel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add test files for real Created 4 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/test/data/bear-vp9a.webm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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*>(&timestamp_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;
« no previous file with comments | « media/filters/vpx_video_decoder.h ('k') | media/test/data/bear-vp9a.webm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698