[FFmpeg-devel] [PATCH v5] Add experimental support for vp9 in iso-bmff

KongQun Yang kqyang at google.com
Wed Jun 15 03:27:07 CEST 2016


-- KongQun Yang (KQ)

On Tue, Jun 14, 2016 at 4:34 PM, Hendrik Leppkes <h.leppkes at gmail.com>
wrote:

> 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).
>

Good idea. Didn't know about these utility functions. Thanks for the
pointer. Done.

>
> > +
> > +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
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>


More information about the ffmpeg-devel mailing list