[FFmpeg-devel] [PATCH v5] Add experimental support for vp9 in iso-bmff
Hendrik Leppkes
h.leppkes at gmail.com
Wed Jun 15 01:34:31 CEST 2016
On Wed, Jun 15, 2016 at 12:05 AM, Kongqun Yang <yangkongqun at gmail.com> wrote:
> Implemented according to the draft specification
> "VP Codec ISO Media File Format Binding":
> http://www.webmproject.org/vp9/#draft-vp-codec-iso-media-file-format-binding
>
> '-strict -2' is required to use this feature.
>
Not sure I really like the vpc name, when I read vpc I don't think of
vp9, and the correlation to avc/hevc is also not really there, as
those codecs are actually called that. AVC and HEVC, the C isn't added
randomly.
If anything, it should have been vp9.c then, but oh well.
But anyway, if Ronald is ok with the name I won't complain.
> ---
> libavformat/Makefile | 2 +-
> libavformat/isom.c | 3 +
> libavformat/movenc.c | 26 +++++++++
> libavformat/vpc.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++
> libavformat/vpc.h | 44 ++++++++++++++
> 5 files changed, 233 insertions(+), 1 deletion(-)
> create mode 100644 libavformat/vpc.c
> create mode 100644 libavformat/vpc.h
>
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 6684ead..be8c261 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -276,7 +276,7 @@ OBJS-$(CONFIG_MM_DEMUXER) += mm.o
> OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o
> OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o
> OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o replaygain.o
> -OBJS-$(CONFIG_MOV_MUXER) += movenc.o avc.o hevc.o \
> +OBJS-$(CONFIG_MOV_MUXER) += movenc.o avc.o hevc.o vpc.o \
> movenchint.o mov_chan.o rtp.o \
> movenccenc.o rawutils.o
> OBJS-$(CONFIG_MP2_MUXER) += mp3enc.o rawenc.o id3v2enc.o
> diff --git a/libavformat/isom.c b/libavformat/isom.c
> index b1757e2..9a65268 100644
> --- a/libavformat/isom.c
> +++ b/libavformat/isom.c
> @@ -59,6 +59,7 @@ const AVCodecTag ff_mp4_obj_type[] = {
> { AV_CODEC_ID_AC3 , 0xA5 },
> { AV_CODEC_ID_EAC3 , 0xA6 },
> { AV_CODEC_ID_DTS , 0xA9 }, /* mp4ra.org */
> + { AV_CODEC_ID_VP9 , 0xC0 }, /* non standard, update when there is a standard value */
> { AV_CODEC_ID_TSCC2 , 0xD0 }, /* non standard, camtasia uses it */
> { AV_CODEC_ID_VORBIS , 0xDD }, /* non standard, gpac uses it */
> { AV_CODEC_ID_DVD_SUBTITLE, 0xE0 }, /* non standard, see unsupported-embedded-subs-2.mp4 */
> @@ -179,6 +180,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
> { AV_CODEC_ID_H264, MKTAG('a', 'i', 'v', 'x') }, /* XAVC 4:2:2 10bit */
> { AV_CODEC_ID_H264, MKTAG('r', 'v', '6', '4') }, /* X-Com Radvision */
>
> + { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') }, /* VP9 */
> +
> { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') },
> { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */
> { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 2f00091..e4c51e8 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -49,6 +49,7 @@
> #include "hevc.h"
> #include "rtpenc.h"
> #include "mov_chan.h"
> +#include "vpc.h"
>
> static const AVOption options[] = {
> { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
> @@ -1039,6 +1040,17 @@ static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
> return update_size(pb, pos);
> }
>
> +static int mov_write_vpcc_tag(AVIOContext *pb, MOVTrack *track)
> +{
> + int64_t pos = avio_tell(pb);
> +
> + avio_wb32(pb, 0);
> + ffio_wfourcc(pb, "vpcC");
> + avio_wb32(pb, 0); /* version & flags */
> + ff_isom_write_vpcc(pb, track->par);
> + return update_size(pb, pos);
> +}
> +
> static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track)
> {
> int64_t pos = avio_tell(pb);
> @@ -1143,6 +1155,7 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
>
> if (track->par->codec_id == AV_CODEC_ID_H264) tag = MKTAG('a','v','c','1');
> else if (track->par->codec_id == AV_CODEC_ID_HEVC) tag = MKTAG('h','e','v','1');
> + else if (track->par->codec_id == AV_CODEC_ID_VP9) tag = MKTAG('v','p','0','9');
> else if (track->par->codec_id == AV_CODEC_ID_AC3) tag = MKTAG('a','c','-','3');
> else if (track->par->codec_id == AV_CODEC_ID_EAC3) tag = MKTAG('e','c','-','3');
> else if (track->par->codec_id == AV_CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c');
> @@ -1758,6 +1771,8 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr
> mov_write_avcc_tag(pb, track);
> if (track->mode == MODE_IPOD)
> mov_write_uuid_tag_ipod(pb);
> + } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
> + mov_write_vpcc_tag(pb, track);
> } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
> mov_write_dvc1_tag(pb, track);
> else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
> @@ -5369,6 +5384,17 @@ static int mov_write_header(AVFormatContext *s)
> pix_fmt == AV_PIX_FMT_MONOWHITE ||
> pix_fmt == AV_PIX_FMT_MONOBLACK;
> }
> + if (track->mode == MODE_MP4 &&
> + track->par->codec_id == AV_CODEC_ID_VP9) {
> + if (s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
> + av_log(s, AV_LOG_ERROR,
> + "VP9 in MP4 support is experimental, add "
> + "'-strict %d' if you want to use it.\n",
> + FF_COMPLIANCE_EXPERIMENTAL);
> + ret = AVERROR_EXPERIMENTAL;
> + goto error;
> + }
> + }
> } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
> track->timescale = st->codecpar->sample_rate;
> if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
> diff --git a/libavformat/vpc.c b/libavformat/vpc.c
> new file mode 100644
> index 0000000..890c5a6
> --- /dev/null
> +++ b/libavformat/vpc.c
> @@ -0,0 +1,159 @@
> +/*
> + * Copyright (c) 2016 Google Inc.
> + * Copyright (c) 2016 KongQun Yang (kqyang at google.com)
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/pixfmt.h"
> +#include "vpc.h"
> +
> +enum VpxColorSpace
> +{
> + VPX_COLOR_SPACE_UNSPECIFIED = 0,
> + VPX_COLOR_SPACE_BT601 = 1,
> + VPX_COLOR_SPACE_BT709 = 2,
> + VPX_COLOR_SPACE_SMPTE_170 = 3,
> + VPX_COLOR_SPACE_SMPTE_240 = 4,
> + VPX_COLOR_SPACE_BT2020_NCL = 5,
> + VPX_COLOR_SPACE_BT2020_CL = 6,
> + VPX_COLOR_SPACE_RGB = 7,
> +};
> +
> +static int get_vpx_color_space(enum AVColorSpace color_space)
> +{
> + switch (color_space) {
> + case AVCOL_SPC_RGB:
> + return VPX_COLOR_SPACE_RGB;
> + case AVCOL_SPC_BT709:
> + return VPX_COLOR_SPACE_BT709;
> + case AVCOL_SPC_UNSPECIFIED:
> + return VPX_COLOR_SPACE_UNSPECIFIED;
> + case AVCOL_SPC_BT470BG:
> + return VPX_COLOR_SPACE_BT601;
> + case AVCOL_SPC_SMPTE170M:
> + return VPX_COLOR_SPACE_SMPTE_170;
> + case AVCOL_SPC_SMPTE240M:
> + return VPX_COLOR_SPACE_SMPTE_240;
> + case AVCOL_SPC_BT2020_NCL:
> + return VPX_COLOR_SPACE_BT2020_NCL;
> + case AVCOL_SPC_BT2020_CL:
> + return VPX_COLOR_SPACE_BT2020_CL;
> + default:
> + av_log(NULL, AV_LOG_ERROR, "Unsupported color space (%d)\n",
> + color_space);
> + return -1;
> + }
> +}
> +
> +enum VPX_CHROMA_SUBSAMPLING
> +{
> + VPX_SUBSAMPLING_420_VERTICAL = 0,
> + VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA = 1,
> + VPX_SUBSAMPLING_422 = 2,
> + VPX_SUBSAMPLING_444 = 3,
> +};
> +
> +static int get_vpx_chroma_subsampling(enum AVPixelFormat pixel_format,
> + enum AVChromaLocation chroma_location)
> +{
> + switch (pixel_format) {
> + case AV_PIX_FMT_YUV420P:
> + case AV_PIX_FMT_YUV420P10LE:
> + case AV_PIX_FMT_YUV420P10BE:
> + case AV_PIX_FMT_YUV420P12LE:
> + case AV_PIX_FMT_YUV420P12BE:
> + if (chroma_location == AVCHROMA_LOC_LEFT)
> + return VPX_SUBSAMPLING_420_VERTICAL;
> + // Otherwise assume collocated.
> + return VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA;
> + case AV_PIX_FMT_YUV422P:
> + case AV_PIX_FMT_YUV422P10LE:
> + case AV_PIX_FMT_YUV422P10BE:
> + case AV_PIX_FMT_YUV422P12LE:
> + case AV_PIX_FMT_YUV422P12BE:
> + return VPX_SUBSAMPLING_422;
> + case AV_PIX_FMT_YUV444P:
> + case AV_PIX_FMT_YUV444P10LE:
> + case AV_PIX_FMT_YUV444P10BE:
> + case AV_PIX_FMT_YUV444P12LE:
> + case AV_PIX_FMT_YUV444P12BE:
> + return VPX_SUBSAMPLING_444;
> + default:
> + av_log(NULL, AV_LOG_ERROR, "Unsupported pixel format (%d)\n",
> + pixel_format);
> + return -1;
> + }
> +}
We have subsampling info in the pixel formt descriptors, it would seem
smarter to use thoe instead of hardcoding a long list of ever-changing
pixel formats.
You already use the descriptor in get_bit_depth below, so try looking
at log2_chroma_w/log2_chroma_h, or using
av_pix_fmt_get_chroma_sub_sample (which just returns those two values
to you).
> +
> +static int get_bit_depth(enum AVPixelFormat pixel_format)
> +{
> + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixel_format);
> + if (desc == NULL) {
> + av_log(NULL, AV_LOG_ERROR, "Unsupported pixel format (%d)\n",
> + pixel_format);
> + return -1;
> + }
> + return desc->comp[0].depth;
> +}
> +
> +static int get_vpx_transfer_function(
> + enum AVColorTransferCharacteristic transfer)
> +{
> + return !!(transfer == AVCOL_TRC_SMPTEST2084);
This looks like an odd way to write it, if its ever extended to make
use of more values, you'll have to change it entirely.
But really just a style nit.
> +}
> +
> +static int get_vpx_video_full_range_flag(enum AVColorRange color_range)
> +{
> + return !!(color_range == AVCOL_RANGE_JPEG);
> +}
> +
> +int ff_isom_write_vpcc(AVIOContext *pb, AVCodecParameters *par)
> +{
> + int profile = par->profile;
> + int level = par->level == FF_LEVEL_UNKNOWN ? 0 : par->level;
> + int bit_depth = get_bit_depth(par->format);
> + int vpx_color_space = get_vpx_color_space(par->color_space);
> + int vpx_chroma_subsampling =
> + get_vpx_chroma_subsampling(par->format, par->chroma_location);
> + int vpx_transfer_function = get_vpx_transfer_function(par->color_trc);
> + int vpx_video_full_range_flag =
> + get_vpx_video_full_range_flag(par->color_range);
> +
> + if (bit_depth < 0 || vpx_color_space < 0 || vpx_chroma_subsampling < 0)
> + return AVERROR_INVALIDDATA;
> +
> + if (profile == FF_PROFILE_UNKNOWN) {
> + if (vpx_chroma_subsampling == VPX_SUBSAMPLING_420_VERTICAL ||
> + vpx_chroma_subsampling == VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA) {
> + profile = (bit_depth == 8) ? FF_PROFILE_VP9_0 : FF_PROFILE_VP9_2;
> + } else {
> + profile = (bit_depth == 8) ? FF_PROFILE_VP9_1 : FF_PROFILE_VP9_3;
> + }
> + }
> +
> + avio_w8(pb, profile);
> + avio_w8(pb, level);
> + avio_w8(pb, (bit_depth << 4) | vpx_color_space);
> + avio_w8(pb, (vpx_chroma_subsampling << 4) | (vpx_transfer_function << 1) |
> + vpx_video_full_range_flag);
> +
> + // vp9 does not have codec initialization data.
> + avio_wb16(pb, 0);
> + return 0;
> +}
> diff --git a/libavformat/vpc.h b/libavformat/vpc.h
> new file mode 100644
> index 0000000..6d609cc
> --- /dev/null
> +++ b/libavformat/vpc.h
> @@ -0,0 +1,44 @@
> +/*
> + * Copyright (c) 2016 Google Inc.
> + * Copyright (c) 2016 KongQun Yang (kqyang at google.com)
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * internal header for VPx codec (de)muxer utilities.
> + */
> +
> +#ifndef AVFORMAT_VPC_H
> +#define AVFORMAT_VPC_H
> +
> +#include <stdint.h>
> +#include "avio.h"
> +#include "libavcodec/avcodec.h"
> +
> +/**
> + * Writes VP codec configuration to the provided AVIOContext.
> + *
> + * @param pb address of the AVIOContext where the vpcC shall be written.
> + * @param par address of the AVCodecParameters which contains codec information.
> + * @return >=0 in case of success, a negative value corresponding to an AVERROR
> + * code in case of failure
> + */
> +int ff_isom_write_vpcc(AVIOContext *pb, AVCodecParameters *par);
> +
> +#endif /* AVFORMAT_VPC_H */
> --
> 2.8.0.rc3.226.g39d4020
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
More information about the ffmpeg-devel
mailing list