Skip to content

Commit

Permalink
Introduce AomVideoDecoder (based on VpxVideoDecoder).
Browse files Browse the repository at this point in the history
Adds a simple 1-copy AV1 video decoder to Chrome. Zero copy and
offloading have not been done to start with since libaom may
produce weird formats (8bit data in 16bit allocation).

There are quite a few TODOs left to sort out:
- We currently don't handle the I440 pixel formats.
- We currently only handle a single profile, but more are expected.
- Decoding for AV1 content should probably be offloaded, so the
OffloadThread stuff from VpxVideoDecoder should be factored out.
- Decoding should use zero copy where possible, so the odd 8bit
in 16bit container needs to be sorted out or Chrome taught to
read this. This requires setting the av1 framebuffer functions.
- All AV1 frames are marked as non-power efficient; is this true
even for low resolutions?
- A fuzzertest needs to be added along with corpus data.
- A pipeline integration test needs to be added with test media
for both src= and MSE.
- What should canPlayType()/isTypeSupported() return for this?
- Changes to MediaSourceExtensions for SourceBuffer creation and
demuxing.

To use this, you must update your .gclient file to include the
following within the "src" solution:

  "custom_vars": { "checkout_libaom": True, },

This will propogate a ENABLE_AV1_DECODER buildflag, which can
optionally be turned off via enable_av1_decode=false for
unsupported platfroms (everything except linux x64 currently)

BUG=783519, b/67860375
TEST=new unittest, manual playback test

Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: Ia77a8d0710ebebd1ac3e7ad83648313063181d62
Reviewed-on: https://chromium-review.googlesource.com/762359
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Reviewed-by: Chrome Cunningham <chcunningham@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Steven Holte <holte@chromium.org>
Reviewed-by: Johann Koenig <johannkoenig@google.com>
Cr-Commit-Position: refs/heads/master@{#516847}
  • Loading branch information
dalecurtis authored and Commit Bot committed Nov 15, 2017
1 parent 9204ed3 commit b03fc92
Show file tree
Hide file tree
Showing 28 changed files with 979 additions and 58 deletions.
5 changes: 4 additions & 1 deletion components/arc/common/video_encode_accelerator.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ enum VideoCodecProfile {
THEORAPROFILE_MIN = 23,
THEORAPROFILE_ANY = THEORAPROFILE_MIN,
THEORAPROFILE_MAX = THEORAPROFILE_ANY,
VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY,
AV1PROFILE_MIN = 24,
AV1PROFILE_PROFILE0 = AV1PROFILE_MIN,
AV1PROFILE_MAX = AV1PROFILE_PROFILE0,
VIDEO_CODEC_PROFILE_MAX = AV1PROFILE_PROFILE0,
};

// Specification of an encoding profile supported by an encoder.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ CHECK_PROFILE_ENUM(DOLBYVISION_MAX);
CHECK_PROFILE_ENUM(THEORAPROFILE_MIN);
CHECK_PROFILE_ENUM(THEORAPROFILE_ANY);
CHECK_PROFILE_ENUM(THEORAPROFILE_MAX);
CHECK_PROFILE_ENUM(AV1PROFILE_PROFILE0);
CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_MAX);

#undef CHECK_PROFILE_ENUM
Expand Down Expand Up @@ -157,6 +158,7 @@ bool EnumTraits<arc::mojom::VideoCodecProfile, media::VideoCodecProfile>::
case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE5:
case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7:
case arc::mojom::VideoCodecProfile::THEORAPROFILE_ANY:
case arc::mojom::VideoCodecProfile::AV1PROFILE_PROFILE0:
*output = static_cast<media::VideoCodecProfile>(input);
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions content/browser/gpu/gpu_internals_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ std::string GetProfileName(gpu::VideoCodecProfile profile) {
return "dolby vision profile 7";
case gpu::THEORAPROFILE_ANY:
return "theora";
case gpu::AV1PROFILE_PROFILE0:
return "av1 profile0";
}
NOTREACHED();
return "";
Expand Down
3 changes: 2 additions & 1 deletion gpu/config/gpu_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ enum VideoCodecProfile {
DOLBYVISION_PROFILE5,
DOLBYVISION_PROFILE7,
THEORAPROFILE_ANY,
VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY,
AV1PROFILE_PROFILE0,
VIDEO_CODEC_PROFILE_MAX = AV1PROFILE_PROFILE0,
};

// Specification of a decoding profile supported by a hardware decoder.
Expand Down
1 change: 1 addition & 0 deletions gpu/ipc/common/gpu_info.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum VideoCodecProfile {
DOLBYVISION_PROFILE5,
DOLBYVISION_PROFILE7,
THEORAPROFILE_ANY,
AV1PROFILE_PROFILE0,
};

// gpu::VideoDecodeAcceleratorSupportedProfile
Expand Down
5 changes: 5 additions & 0 deletions gpu/ipc/common/gpu_info_struct_traits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ EnumTraits<gpu::mojom::VideoCodecProfile, gpu::VideoCodecProfile>::ToMojom(
return gpu::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7;
case gpu::VideoCodecProfile::THEORAPROFILE_ANY:
return gpu::mojom::VideoCodecProfile::THEORAPROFILE_ANY;
case gpu::VideoCodecProfile::AV1PROFILE_PROFILE0:
return gpu::mojom::VideoCodecProfile::AV1PROFILE_PROFILE0;
}
NOTREACHED() << "Invalid VideoCodecProfile:" << video_codec_profile;
return gpu::mojom::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN;
Expand Down Expand Up @@ -200,6 +202,9 @@ bool EnumTraits<gpu::mojom::VideoCodecProfile, gpu::VideoCodecProfile>::
case gpu::mojom::VideoCodecProfile::THEORAPROFILE_ANY:
*out = gpu::VideoCodecProfile::THEORAPROFILE_ANY;
return true;
case gpu::mojom::VideoCodecProfile::AV1PROFILE_PROFILE0:
*out = gpu::VideoCodecProfile::AV1PROFILE_PROFILE0;
return true;
}
NOTREACHED() << "Invalid VideoCodecProfile: " << input;
return false;
Expand Down
1 change: 1 addition & 0 deletions media/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ include_rules = [
"+ppapi/features",
"+skia/ext",
"+third_party/ffmpeg",
"+third_party/libaom",
"+third_party/libvpx",
"+third_party/libyuv",
"+third_party/opus",
Expand Down
1 change: 1 addition & 0 deletions media/base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ source_set("base") {
"//gpu/command_buffer/common",
"//ppapi/features",
"//skia",
"//third_party/libaom:av1_features",
"//third_party/libyuv",
"//third_party/widevine/cdm:headers",
"//ui/display:display",
Expand Down
8 changes: 8 additions & 0 deletions media/base/decode_capabilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "media/base/media_switches.h"
#include "third_party/libaom/av1_features.h"
#include "ui/display/display_switches.h"

#if !defined(MEDIA_DISABLE_LIBVPX)
Expand Down Expand Up @@ -163,6 +164,13 @@ bool IsSupportedAudioConfig(const AudioConfig& config) {
// specific logic for Android (move from MimeUtilIntenral).
bool IsSupportedVideoConfig(const VideoConfig& config) {
switch (config.codec) {
case media::kCodecAV1:
#if BUILDFLAG(ENABLE_AV1_DECODER)
return IsColorSpaceSupported(config.color_space);
#else
return false;
#endif

case media::kCodecVP9:
// Color management required for HDR to not look terrible.
return IsColorSpaceSupported(config.color_space) &&
Expand Down
8 changes: 8 additions & 0 deletions media/base/video_codecs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ std::string GetCodecName(VideoCodec codec) {
return "vp8";
case kCodecVP9:
return "vp9";
case kCodecAV1:
return "av1";
}
NOTREACHED();
return "";
Expand Down Expand Up @@ -92,6 +94,8 @@ std::string GetProfileName(VideoCodecProfile profile) {
return "dolby vision profile 7";
case THEORAPROFILE_ANY:
return "theora";
case AV1PROFILE_PROFILE0:
return "av1 profile0";
}
NOTREACHED();
return "";
Expand Down Expand Up @@ -608,6 +612,10 @@ VideoCodec StringToVideoCodec(const std::string& codec_id) {
uint8_t level = 0;
VideoColorSpace color_space;

// TODO(dalecurtis): The actual codec string will be similar (equivalent?) to
// the vp9 codec string. Fix this before release. http://crbug.com/784607.
if (codec_id == "av1")
return kCodecAV1;
if (codec_id == "vp8" || codec_id == "vp8.0")
return kCodecVP8;
if (ParseNewStyleVp9CodecID(codec_id, &profile, &level, &color_space) ||
Expand Down
11 changes: 8 additions & 3 deletions media/base/video_codecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ enum VideoCodec {
kCodecVP9,
kCodecHEVC,
kCodecDolbyVision,
kCodecAV1,
// DO NOT ADD RANDOM VIDEO CODECS!
//
// The only acceptable time to add a new codec is if there is production code
// that uses said codec in the same CL.

kVideoCodecMax =
kCodecDolbyVision, // Must equal the last "real" codec above.
kVideoCodecMax = kCodecAV1, // Must equal the last "real" codec above.
};

// Video codec profiles. Keep in sync with mojo::VideoCodecProfile (see
Expand Down Expand Up @@ -88,7 +88,12 @@ enum VideoCodecProfile {
THEORAPROFILE_MIN = 23,
THEORAPROFILE_ANY = THEORAPROFILE_MIN,
THEORAPROFILE_MAX = THEORAPROFILE_ANY,
VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY,
// TODO(dalecurtis): AV1 profiles are not finalized, this needs updating
// before enabling for release. http://crbug.com/784993
AV1PROFILE_MIN = 24,
AV1PROFILE_PROFILE0 = AV1PROFILE_MIN,
AV1PROFILE_MAX = AV1PROFILE_PROFILE0,
VIDEO_CODEC_PROFILE_MAX = AV1PROFILE_PROFILE0,
};

struct CodecProfileLevel {
Expand Down
2 changes: 2 additions & 0 deletions media/base/video_decoder_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ VideoCodec VideoCodecProfileToVideoCodec(VideoCodecProfile profile) {
return kCodecDolbyVision;
case THEORAPROFILE_ANY:
return kCodecTheora;
case AV1PROFILE_PROFILE0:
return kCodecAV1;
}
NOTREACHED();
return kUnknownVideoCodec;
Expand Down
13 changes: 9 additions & 4 deletions media/base/video_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ enum VideoPixelFormat {
PIXEL_FORMAT_UNKNOWN = 0, // Unknown or unspecified format value.
PIXEL_FORMAT_I420 =
1, // 12bpp YUV planar 1x1 Y, 2x2 UV samples, a.k.a. YU12.
PIXEL_FORMAT_YV12 = 2, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
PIXEL_FORMAT_YV16 = 3, // 16bpp YVU planar 1x1 Y, 2x1 VU samples.
PIXEL_FORMAT_YV12A = 4, // 20bpp YUVA planar 1x1 Y, 2x2 VU, 1x1 A samples.

// Note: Chrome does not actually support YVU compositing, so you probably
// don't actually want to use either of these. See http://crbug.com/784627.
PIXEL_FORMAT_YV12 = 2, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
PIXEL_FORMAT_YV16 = 3, // 16bpp YVU planar 1x1 Y, 2x1 VU samples.

PIXEL_FORMAT_YV12A = 4, // 20bpp YUVA planar 1x1 Y, 2x2 UV, 1x1 A samples.
PIXEL_FORMAT_YV24 = 5, // 24bpp YUV planar, no subsampling.
PIXEL_FORMAT_NV12 =
6, // 12bpp with Y plane followed by a 2x2 interleaved UV plane.
Expand All @@ -47,13 +51,14 @@ enum VideoPixelFormat {
// Plane size = Row pitch * (((height+31)/32)*32)
PIXEL_FORMAT_MT21 = 15,

// The P* in the formats below designates the number of bits per pixel. I.e.
// P9 is 9-bits per pixel, P10 is 10-bits per pixel, etc.
PIXEL_FORMAT_YUV420P9 = 16,
PIXEL_FORMAT_YUV420P10 = 17,
PIXEL_FORMAT_YUV422P9 = 18,
PIXEL_FORMAT_YUV422P10 = 19,
PIXEL_FORMAT_YUV444P9 = 20,
PIXEL_FORMAT_YUV444P10 = 21,

PIXEL_FORMAT_YUV420P12 = 22,
PIXEL_FORMAT_YUV422P12 = 23,
PIXEL_FORMAT_YUV444P12 = 24,
Expand Down
103 changes: 56 additions & 47 deletions media/ffmpeg/ffmpeg_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ static VideoCodec CodecIDToVideoCodec(AVCodecID codec_id) {
return kCodecVP8;
case AV_CODEC_ID_VP9:
return kCodecVP9;
case AV_CODEC_ID_AV1:
return kCodecAV1;
default:
DVLOG(1) << "Unknown video CodecID: " << codec_id;
}
Expand All @@ -211,6 +213,8 @@ AVCodecID VideoCodecToCodecID(VideoCodec video_codec) {
return AV_CODEC_ID_VP8;
case kCodecVP9:
return AV_CODEC_ID_VP9;
case kCodecAV1:
return AV_CODEC_ID_AV1;
default:
DVLOG(1) << "Unknown VideoCodec: " << video_codec;
}
Expand Down Expand Up @@ -448,65 +452,65 @@ bool AVStreamToVideoDecoderConfig(const AVStream* stream,
if (!codec_context)
return false;

// AVStream.codec->coded_{width,height} access is deprecated in ffmpeg.
// Use just the width and height as hints of coded size.
gfx::Size coded_size(codec_context->width, codec_context->height);

// TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
// for now, but may not always be true forever. Fix this in the future.
gfx::Rect visible_rect(codec_context->width, codec_context->height);
gfx::Size coded_size = visible_rect.size();

AVRational aspect_ratio = { 1, 1 };
AVRational aspect_ratio = {1, 1};
if (stream->sample_aspect_ratio.num)
aspect_ratio = stream->sample_aspect_ratio;
else if (codec_context->sample_aspect_ratio.num)
aspect_ratio = codec_context->sample_aspect_ratio;

VideoCodec codec = CodecIDToVideoCodec(codec_context->codec_id);

VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
if (codec == kCodecVP8)
profile = VP8PROFILE_ANY;
else if (codec == kCodecVP9)
// TODO(servolk): Find a way to obtain actual VP9 profile from FFmpeg.
// crbug.com/592074
profile = VP9PROFILE_PROFILE0;
else if (codec == kCodecTheora)
profile = THEORAPROFILE_ANY;
else
profile = ProfileIDToVideoCodecProfile(codec_context->profile);

// Without the FFmpeg h264 decoder, AVFormat is unable to get the profile, so
// default to baseline and let the VDA fail later if it doesn't support the
// real profile. This is alright because if the FFmpeg h264 decoder isn't
// enabled, there is no fallback if the VDA fails.
#if defined(DISABLE_FFMPEG_VIDEO_DECODERS)
if (codec == kCodecH264)
profile = H264PROFILE_BASELINE;
#endif

gfx::Size natural_size = GetNaturalSize(
visible_rect.size(), aspect_ratio.num, aspect_ratio.den);
gfx::Size natural_size =
GetNaturalSize(visible_rect.size(), aspect_ratio.num, aspect_ratio.den);

VideoPixelFormat format =
AVPixelFormatToVideoPixelFormat(codec_context->pix_fmt);
// The format and coded size may be unknown if FFmpeg is compiled without
// video decoders.

// Without the ffmpeg decoder configured, libavformat is unable to get the
// profile, format, or coded size. So choose sensible defaults and let
// decoders fail later if the configuration is actually unsupported.
//
// TODO(chcunningham): We need real profiles for all of the codecs below to
// actually handle capabilities requests correctly. http://crbug.com/784610
VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
switch (codec) {
#if defined(DISABLE_FFMPEG_VIDEO_DECODERS)
if (format == PIXEL_FORMAT_UNKNOWN)
format = PIXEL_FORMAT_YV12;
if (coded_size == gfx::Size(0, 0))
coded_size = visible_rect.size();
case kCodecH264:
// TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
format = PIXEL_FORMAT_YV12;
profile = H264PROFILE_BASELINE;
break;
#endif

if (codec == kCodecVP9) {
// TODO(tomfinegan): libavcodec doesn't know about VP9.
format = PIXEL_FORMAT_YV12;
coded_size = visible_rect.size();
case kCodecVP8:
#if defined(DISABLE_FFMPEG_VIDEO_DECODERS)
// TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
format = PIXEL_FORMAT_YV12;
#endif
profile = VP8PROFILE_ANY;
break;
case kCodecVP9:
// TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
format = PIXEL_FORMAT_YV12;
profile = VP9PROFILE_PROFILE0;
break;
case kCodecAV1:
format = PIXEL_FORMAT_I420;
profile = AV1PROFILE_PROFILE0;
break;
case kCodecTheora:
profile = THEORAPROFILE_ANY;
break;
default:
profile = ProfileIDToVideoCodecProfile(codec_context->profile);
}

// Pad out |coded_size| for subsampled YUV formats.
if (format != PIXEL_FORMAT_YV24) {
if (format != PIXEL_FORMAT_YV24 && format != PIXEL_FORMAT_UNKNOWN) {
coded_size.set_width((coded_size.width() + 1) / 2 * 2);
if (format != PIXEL_FORMAT_YV16)
coded_size.set_height((coded_size.height() + 1) / 2 * 2);
Expand Down Expand Up @@ -538,7 +542,7 @@ bool AVStreamToVideoDecoderConfig(const AVStream* stream,
video_rotation = VIDEO_ROTATION_270;
break;
default:
LOG(ERROR) << "Unsupported video rotation metadata: " << rotation;
DLOG(ERROR) << "Unsupported video rotation metadata: " << rotation;
break;
}

Expand All @@ -556,11 +560,9 @@ bool AVStreamToVideoDecoderConfig(const AVStream* stream,
// http://crbug.com/517163
if (codec_context->extradata != nullptr &&
codec_context->extradata_size == 0) {
LOG(ERROR) << __func__ << " Non-Null extra data cannot have size of 0.";
DLOG(ERROR) << __func__ << " Non-Null extra data cannot have size of 0.";
return false;
}
CHECK_EQ(codec_context->extradata == nullptr,
codec_context->extradata_size == 0);

std::vector<uint8_t> extra_data;
if (codec_context->extradata_size > 0) {
Expand Down Expand Up @@ -681,15 +683,19 @@ VideoPixelFormat AVPixelFormatToVideoPixelFormat(AVPixelFormat pixel_format) {
// The YUVJ alternatives are FFmpeg's (deprecated, but still in use) way to
// specify a pixel format and full range color combination.
switch (pixel_format) {
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUVJ422P:
return PIXEL_FORMAT_YV16;
case AV_PIX_FMT_YUV444P:
case AV_PIX_FMT_YUVJ444P:
return PIXEL_FORMAT_YV24;

// TODO(dalecurtis): These are incorrect; see http://crbug.com/784627. This
// should actually be PIXEL_FORMAT_I420 and PIXEL_FORMAT_I422.
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUVJ420P:
return PIXEL_FORMAT_YV12;
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUVJ422P:
return PIXEL_FORMAT_YV16;

case AV_PIX_FMT_YUVA420P:
return PIXEL_FORMAT_YV12A;

Expand Down Expand Up @@ -722,10 +728,13 @@ VideoPixelFormat AVPixelFormatToVideoPixelFormat(AVPixelFormat pixel_format) {

AVPixelFormat VideoPixelFormatToAVPixelFormat(VideoPixelFormat video_format) {
switch (video_format) {
// TODO(dalecurtis): These are incorrect; see http://crbug.com/784627.
// FFmpeg actually has no YVU format...
case PIXEL_FORMAT_YV16:
return AV_PIX_FMT_YUV422P;
case PIXEL_FORMAT_YV12:
return AV_PIX_FMT_YUV420P;

case PIXEL_FORMAT_YV12A:
return AV_PIX_FMT_YUVA420P;
case PIXEL_FORMAT_YV24:
Expand Down
Loading

0 comments on commit b03fc92

Please sign in to comment.