On Wed, Jun 15, 2016 at 12:05 AM, Kongqun Yang <yangkong...@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 (kqy...@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 (kqy...@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@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel