On 8/6/2020 5:04 AM, Xu Guangxin wrote: > It's defined in Section 5.2, used by netflix. > see http://download.opencontent.netflix.com/?prefix=AV1/Chimera/ > --- > libavformat/allformats.c | 1 + > libavformat/av1dec.c | 193 +++++++++++++++++++++++++++++++++++++-- > 2 files changed, 185 insertions(+), 9 deletions(-) > > diff --git a/libavformat/allformats.c b/libavformat/allformats.c > index fd9e46e233..8eead5619d 100644 > --- a/libavformat/allformats.c > +++ b/libavformat/allformats.c > @@ -75,6 +75,7 @@ extern AVOutputFormat ff_asf_stream_muxer; > extern AVInputFormat ff_au_demuxer; > extern AVOutputFormat ff_au_muxer; > extern AVInputFormat ff_av1_demuxer; > +extern AVInputFormat ff_av1_low_overhead_demuxer;
How about ff_obu_demuxer instead? > extern AVInputFormat ff_avi_demuxer; > extern AVOutputFormat ff_avi_muxer; > extern AVInputFormat ff_avisynth_demuxer; > diff --git a/libavformat/av1dec.c b/libavformat/av1dec.c > index ec66152e03..0c5d172a0f 100644 > --- a/libavformat/av1dec.c > +++ b/libavformat/av1dec.c > @@ -28,6 +28,9 @@ > #include "avio_internal.h" > #include "internal.h" > > +//2 + max leb 128 size > +#define MAX_HEAD_SIZE 10 This value is also used in av1_parse.h, so you could put it there and reuse it. But if you do, use a less generic name, like MAX_OBU_HEADER_SIZE. > + > typedef struct AnnexBContext { > const AVClass *class; > AVBSFContext *bsf; > @@ -139,9 +142,8 @@ static int annexb_probe(const AVProbeData *p) > return 0; > } > > -static int annexb_read_header(AVFormatContext *s) > +static int read_header(AVFormatContext *s, AVRational framerate, > AVBSFContext **bsf, void *c) Since c is now a log context, rename it to logctx. > { > - AnnexBContext *c = s->priv_data; > const AVBitStreamFilter *filter = av_bsf_get_by_name("av1_frame_merge"); > AVStream *st; > int ret; > @@ -160,25 +162,32 @@ static int annexb_read_header(AVFormatContext *s) > st->codecpar->codec_id = AV_CODEC_ID_AV1; > st->need_parsing = AVSTREAM_PARSE_HEADERS; > > - st->internal->avctx->framerate = c->framerate; > + st->internal->avctx->framerate = framerate; > // taken from rawvideo demuxers > avpriv_set_pts_info(st, 64, 1, 1200000); > > - ret = av_bsf_alloc(filter, &c->bsf); > + ret = av_bsf_alloc(filter, bsf); If it requires this bsf, then it should be added as a depencency to configure. > if (ret < 0) > return ret; > > - ret = avcodec_parameters_copy(c->bsf->par_in, st->codecpar); > + ret = avcodec_parameters_copy((*bsf)->par_in, st->codecpar); > if (ret < 0) { > - av_bsf_free(&c->bsf); > + av_bsf_free(bsf); > return ret; > } > > - ret = av_bsf_init(c->bsf); > + ret = av_bsf_init(*bsf); > if (ret < 0) > - av_bsf_free(&c->bsf); > + av_bsf_free(bsf); > > return ret; > + > +} > + > +static int annexb_read_header(AVFormatContext *s) > +{ > + AnnexBContext *c = s->priv_data; > + return read_header(s, c->framerate, &c->bsf, c); > } > > static int annexb_read_packet(AVFormatContext *s, AVPacket *pkt) > @@ -246,12 +255,158 @@ static int annexb_read_close(AVFormatContext *s) > return 0; > } > > -#define OFFSET(x) offsetof(AnnexBContext, x) > +typedef struct LowOverheadContext { > + const AVClass *class; > + AVBSFContext *bsf; > + AVRational framerate; > + uint8_t prefetched[MAX_HEAD_SIZE]; > + //prefetched len > + int len; > +} LowOverheadContext; > + > +static int low_overhead_probe(const AVProbeData *p) > +{ > + AVIOContext pb; > + int64_t obu_size; > + int ret, type, cnt = 0, has_size_flag; > + > + ffio_init_context(&pb, p->buf, p->buf_size, 0, > + NULL, NULL, NULL, NULL); > + > + // Check that the first OBU is a Temporal Delimiter. > + ret = read_obu(p->buf + cnt, FFMIN(p->buf_size - cnt, MAX_HEAD_SIZE), > &obu_size, &type, &has_size_flag); cnt is 0 at this point, so might as well remove it. > + if (ret < 0 || type != AV1_OBU_TEMPORAL_DELIMITER || obu_size != 0 || > !has_size_flag) > + return 0; > + cnt += ret; > + > + ret = read_obu(p->buf + cnt, FFMIN(p->buf_size - cnt, MAX_HEAD_SIZE), > &obu_size, &type, &has_size_flag); > + if (ret < 0 || type != AV1_OBU_SEQUENCE_HEADER || !has_size_flag) Afaik, there's nothing in the spec that forbids a Metadata OBU to appear here before a Sequence Header. > + return 0; > + cnt += ret; > + > + ret = read_obu(p->buf + cnt, FFMIN(p->buf_size - cnt, MAX_HEAD_SIZE), > &obu_size, &type, &has_size_flag); > + if (ret < 0 || (type != AV1_OBU_FRAME && type != AV1_OBU_FRAME_HEADER) > || obu_size <= 0 || !has_size_flag) Similarly, the third OBU is not required to be a Frame or Frame Header. It could be Metadata after the second one was a Sequence Header, or vice-versa. > + return 0; > + return AVPROBE_SCORE_EXTENSION + 1; > +} > + > +static int low_overhead_read_header(AVFormatContext *s) > +{ > + LowOverheadContext *c = s->priv_data; > + return read_header(s, c->framerate, &c->bsf, c); > +} > + > +static int low_overhead_prefetch(AVFormatContext *s) > +{ > + LowOverheadContext *c = s->priv_data; > + int ret; > + int size = MAX_HEAD_SIZE - c->len; > + if (size > 0 && !avio_feof(s->pb)) { > + ret = avio_read(s->pb, &c->prefetched[c->len], size); > + if (ret < 0) > + return ret; > + c->len += ret; > + } > + return c->len; > +} > + > +static int low_overhead_read_data(AVFormatContext *s, AVPacket *pkt, int > size) > +{ > + int left; > + LowOverheadContext *c = s->priv_data; > + int ret = av_new_packet(pkt, size); > + if (ret < 0) { > + av_log(c, AV_LOG_ERROR, "Failed to allocate packet for obu\n"); > + return ret; > + } > + if (size <= c->len) { > + memcpy(pkt->data, c->prefetched, size); > + > + left = c->len - size; > + memcpy(c->prefetched, c->prefetched + size, left); This looks like it should be a memmove, as it can overlap. > + c->len = left; > + } else { > + memcpy(pkt->data, c->prefetched, c->len); > + left = size - c->len; > + ret = avio_read(s->pb, pkt->data + c->len, left); > + if (ret != left) { > + av_log(c, AV_LOG_ERROR, "Failed to read %d frome file\n", left); > + return ret; > + } > + c->len = 0; > + } > + return 0; > +} > + > +static int low_overhead_get_packet(AVFormatContext *s, AVPacket *pkt) > +{ > + int64_t obu_size; > + int ret, type, has_size_flag; > + LowOverheadContext *c = s->priv_data; > + ret = low_overhead_prefetch(s); > + if (ret < 0) > + return ret; > + if (ret) { > + ret = read_obu(c->prefetched, c->len, &obu_size, &type, > &has_size_flag); > + if (ret < 0 && !has_size_flag) { Shouldn't this be (ret < 0 || !has_size_flag)? > + av_log(c, AV_LOG_ERROR, "Failed to read obu\n"); > + return ret; > + } > + ret = low_overhead_read_data(s, pkt, ret); > + } > + return ret; > +} > + > +static int low_overhead_read_packet(AVFormatContext *s, AVPacket *pkt) > +{ > + LowOverheadContext *c = s->priv_data; > + int ret; > + > + while (1) { > + ret = low_overhead_get_packet(s, pkt); > + if (ret < 0) > + return ret; > + ret = av_bsf_send_packet(c->bsf, pkt); > + if (ret < 0) { > + av_log(s, AV_LOG_ERROR, "Failed to send packet to " > + "av1_frame_merge filter\n"); > + return ret; > + } > + ret = av_bsf_receive_packet(c->bsf, pkt); > + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) > + av_log(s, AV_LOG_ERROR, "av1_frame_merge filter failed to " > + "send output packet\n"); > + > + if (ret != AVERROR(EAGAIN)) > + break; > + } > + > + return ret; > +} > + > +static int low_overhead_read_close(AVFormatContext *s) > +{ > + LowOverheadContext *c = s->priv_data; > + > + av_bsf_free(&c->bsf); > + return 0; > +} > + > #define DEC AV_OPT_FLAG_DECODING_PARAM > + > +#define OFFSET(x) offsetof(AnnexBContext, x) > static const AVOption annexb_options[] = { > { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = > "25"}, 0, INT_MAX, DEC}, > { NULL }, > }; > +#undef OFFSET > + > +#define OFFSET(x) offsetof(LowOverheadContext, x) > +static const AVOption low_overhead_options[] = { > + { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = > "25"}, 0, INT_MAX, DEC}, > + { NULL }, > +}; > +#undef OFFSET > > static const AVClass annexb_demuxer_class = { > .class_name = "AV1 Annex B demuxer", > @@ -272,3 +427,23 @@ AVInputFormat ff_av1_demuxer = { > .flags = AVFMT_GENERIC_INDEX, > .priv_class = &annexb_demuxer_class, > }; > + > +static const AVClass low_overhead_demuxer_class = { > + .class_name = "AV1 low overhead OBU demuxer", > + .item_name = av_default_item_name, > + .option = low_overhead_options, > + .version = LIBAVUTIL_VERSION_INT, > +}; > + > +AVInputFormat ff_av1_low_overhead_demuxer = { > + .name = "av1", This name is already used by the AnnexB demuxer, so change it to "obu". > + .long_name = NULL_IF_CONFIG_SMALL("AV1 low overhead OBU"), > + .priv_data_size = sizeof(LowOverheadContext), > + .read_probe = low_overhead_probe, > + .read_header = low_overhead_read_header, > + .read_packet = low_overhead_read_packet, > + .read_close = low_overhead_read_close, > + .extensions = "obu", > + .flags = AVFMT_GENERIC_INDEX, > + .priv_class = &low_overhead_demuxer_class, > +}; > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".