Basic Daala format header reading and parsing. --- libavformat/Makefile | 1 + libavformat/oggdec.c | 1 + libavformat/oggdec.h | 1 + libavformat/oggparsedaala.c | 248 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+) create mode 100644 libavformat/oggparsedaala.c
diff --git a/libavformat/Makefile b/libavformat/Makefile index ded2d54..ec641f3 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -297,6 +297,7 @@ OBJS-$(CONFIG_NUT_MUXER) += nutenc.o nut.o OBJS-$(CONFIG_NUV_DEMUXER) += nuv.o OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ oggparsecelt.o \ + oggparsedaala.o \ oggparsedirac.o \ oggparseflac.o \ oggparseogm.o \ diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index ae56915..9682ee9 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -41,6 +41,7 @@ static const struct ogg_codec * const ogg_codecs[] = { &ff_skeleton_codec, + &ff_daala_codec, &ff_dirac_codec, &ff_speex_codec, &ff_vorbis_codec, diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h index 7dc7716..d7af1cf 100644 --- a/libavformat/oggdec.h +++ b/libavformat/oggdec.h @@ -114,6 +114,7 @@ struct ogg { #define OGG_NOGRANULE_VALUE (-1ull) extern const struct ogg_codec ff_celt_codec; +extern const struct ogg_codec ff_daala_codec; extern const struct ogg_codec ff_dirac_codec; extern const struct ogg_codec ff_flac_codec; extern const struct ogg_codec ff_ogm_audio_codec; diff --git a/libavformat/oggparsedaala.c b/libavformat/oggparsedaala.c new file mode 100644 index 0000000..4c2b791 --- /dev/null +++ b/libavformat/oggparsedaala.c @@ -0,0 +1,248 @@ +/* + Copyright (C) 2015 Rostislav Pehlivanov + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +**/ + +#include <stdlib.h> +#include "libavutil/bswap.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavcodec/get_bits.h" +#include "libavcodec/bytestream.h" +#include "avformat.h" +#include "internal.h" +#include "oggdec.h" + +struct DaalaPixFmt { + int ffmpeg_fmt; + int depth; + int planes; + int xdec[3]; /* for chroma + alpha planes only */ + int ydec[3]; +}; + +struct DaalaPixFmt list_fmts[] = { + { AV_PIX_FMT_YUV420P, 8, 1, {1, 1}, {1, 1} }, + { AV_PIX_FMT_YUV420P10, 10, 1, {1, 1}, {1, 1} }, + { AV_PIX_FMT_YUV420P12, 12, 1, {1, 1}, {1, 1} }, +}; + +typedef struct DaalaParams { + int init_d; + int gpshift; + int gpmask; + int version_maj; + int version_min; + int version_sub; + int frame_duration; + int keyframe_granule_shift; + struct DaalaPixFmt format; +} DaalaParams; + +static inline int daala_match_pix_fmt(struct DaalaPixFmt *fmt) +{ + int i, j; + for (i = 0; i < FF_ARRAY_ELEMS(list_fmts); i++) { + int match = 0; + if (fmt->depth != list_fmts[i].depth) + continue; + if (fmt->planes != list_fmts[i].planes) + continue; + if (fmt->planes == 1) + return list_fmts[i].ffmpeg_fmt; + for (j = 0; j < fmt->planes; j++) { + if (fmt->xdec[j] != list_fmts[i].xdec[j]) + continue; + if (fmt->ydec[j] != list_fmts[i].ydec[j]) + continue; + match++; + } + if (match == fmt->planes) + return list_fmts[i].ffmpeg_fmt; + } + return -1; +} + +static int daala_header(AVFormatContext *s, int idx) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + AVStream *st = s->streams[idx]; + DaalaParams *dhp = os->private; + int cds = st->codec->extradata_size + os->psize + 2; + int err, i; + uint8_t *cdp; + + if (!(os->buf[os->pstart] & 0x80)) + return 0; + + if (!dhp) { + dhp = av_mallocz(sizeof(*dhp)); + if (!dhp) + return AVERROR(ENOMEM); + os->private = dhp; + } + + switch (os->buf[os->pstart]) { + case 0x80: { + GetByteContext gb; + AVRational timebase; + + bytestream2_init(&gb, os->buf + os->pstart, os->psize); + bytestream2_skip(&gb, ff_daala_codec.magicsize); + + dhp->version_maj = bytestream2_get_byte(&gb); + dhp->version_min = bytestream2_get_byte(&gb); + dhp->version_sub = bytestream2_get_byte(&gb); + + st->codec->width = bytestream2_get_ne32(&gb); + st->codec->height = bytestream2_get_ne32(&gb); + + st->sample_aspect_ratio.num = bytestream2_get_ne32(&gb); + st->sample_aspect_ratio.den = bytestream2_get_ne32(&gb); + + timebase.num = bytestream2_get_ne32(&gb); + timebase.den = bytestream2_get_ne32(&gb); + if (timebase.num <= 0 && timebase.den <= 0) { + av_log(s, AV_LOG_WARNING, "Invalid timebase, assuming 25 FPS\n"); + timebase.num = 1; + timebase.den = 25; + } + avpriv_set_pts_info(st, 64, timebase.den, timebase.num); + + dhp->frame_duration = bytestream2_get_ne32(&gb); + dhp->gpshift = bytestream2_get_ne32(&gb); + dhp->gpmask = (1 << dhp->gpshift) - 1; + + dhp->format.depth = 8 + 2*(bytestream2_get_byte(&gb)); + dhp->format.planes = bytestream2_get_byte(&gb); + for (i = 0; i < dhp->format.planes; i++) { + dhp->format.xdec[i] = bytestream2_get_byte(&gb); + dhp->format.xdec[i] = bytestream2_get_byte(&gb); + } + if ((st->codec->pix_fmt = daala_match_pix_fmt(&dhp->format)) == -1) + av_log(s, AV_LOG_ERROR, "Unsupported daala pixel format - %i %i\n", dhp->format.depth, dhp->format.planes); + + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_DAALA; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + + dhp->init_d = 1; + } + break; + case 0x81: + ff_vorbis_stream_comment(s, st, + os->buf + os->pstart + ff_daala_codec.magicsize, + os->psize - ff_daala_codec.magicsize); + case 0x82: + if (!dhp->init_d) + return AVERROR_INVALIDDATA; + break; + default: + av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]); + return AVERROR_INVALIDDATA; + } + + if ((err = av_reallocp(&st->codec->extradata, + cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { + st->codec->extradata_size = 0; + return err; + } + memset(st->codec->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + cdp = st->codec->extradata + st->codec->extradata_size; + *cdp++ = os->psize >> 8; + *cdp++ = os->psize & 0xff; + memcpy(cdp, os->buf + os->pstart, os->psize); + st->codec->extradata_size = cds; + + return 1; +} + +static uint64_t daala_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, + int64_t *dts) +{ + struct ogg *ogg = ctx->priv_data; + struct ogg_stream *os = ogg->streams + idx; + DaalaParams *dhp = os->private; + uint64_t iframe, pframe; + + if (!dhp) + return AV_NOPTS_VALUE; + + iframe = gp >> dhp->gpshift; + pframe = gp & dhp->gpmask; + + if (!pframe) + os->pflags |= AV_PKT_FLAG_KEY; + + if (dts) + *dts = iframe + pframe; + + return iframe + pframe; +} + +static int daala_packet(AVFormatContext *s, int idx) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + int duration; + + /* first packet handling + h ere w*e parse the duration of each packet in the first page and compare + the total duration to the page granule to find the encoder delay and + set the first timestamp */ + + if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { + int seg; + + duration = 1; + for (seg = os->segp; seg < os->nsegs; seg++) { + if (os->segments[seg] < 255) + duration ++; + } + + os->lastpts = os->lastdts = daala_gptopts(s, idx, os->granule, NULL) - duration; + if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { + s->streams[idx]->start_time = os->lastpts; + if (s->streams[idx]->duration) + s->streams[idx]->duration -= s->streams[idx]->start_time; + } + } + + /* parse packet duration */ + if (os->psize > 0) { + os->pduration = 1; + } + + return 0; +} + +const struct ogg_codec ff_daala_codec = { + .name = "Daala", + .magic = "\200daala", + .magicsize = 6, + .header = daala_header, + .packet = daala_packet, + .gptopts = daala_gptopts, + .nb_header = 3, +}; -- 2.6.1.204.gc021fdf _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel