Discussion:
[libav-devel] AV1 support part I of many
Luca Barbato
2018-10-03 19:15:29 UTC
Permalink
While I'm trying to figure out an unrelated bug on an unrelated piece of
software here some picks needed to support AV1 in mkv and mp4.
Luca Barbato
2018-10-03 19:15:30 UTC
Permalink
From: Jan Sebechlebsky <***@gmail.com>

Use of this function can save unnecessary malloc operation
in bitstream filter.

Signed-off-by: Jan Sebechlebsky <***@gmail.com>
Signed-off-by: Michael Niedermayer <***@niedermayer.cc>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/bsf.c | 16 ++++++++++++++++
libavcodec/bsf.h | 11 +++++++++++
2 files changed, 27 insertions(+)

diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 05cad546de..f6f894b50a 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -227,3 +227,19 @@ int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt)

return 0;
}
+
+int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
+{
+ AVBSFInternal *in = ctx->internal;
+
+ if (in->eof)
+ return AVERROR_EOF;
+
+ if (!ctx->internal->buffer_pkt->data &&
+ !ctx->internal->buffer_pkt->side_data_elems)
+ return AVERROR(EAGAIN);
+
+ av_packet_move_ref(pkt, ctx->internal->buffer_pkt);
+
+ return 0;
+}
diff --git a/libavcodec/bsf.h b/libavcodec/bsf.h
index cf35fc8e01..39301a286f 100644
--- a/libavcodec/bsf.h
+++ b/libavcodec/bsf.h
@@ -28,6 +28,17 @@
*/
int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt);

+/**
+ * Called by bitstream filters to get packet for filtering.
+ * The reference to packet is moved to provided packet structure.
+ *
+ * @param ctx pointer to AVBSFContext of filter
+ * @param pkt pointer to packet to move reference to
+ *
+ * @return 0>= on success, negative AVERROR in case of failure
+ */
+int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt);
+
const AVClass *ff_bsf_child_class_next(const AVClass *prev);

#endif /* AVCODEC_BSF_H */
--
2.12.2
Luca Barbato
2018-10-03 19:15:31 UTC
Permalink
From: Nikolas Bowe <nbowe-at-***@ffmpeg.org>

Signed-off-by: Michael Niedermayer <***@niedermayer.cc>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/extract_extradata_bsf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 100c60d063..10d108054a 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -78,7 +78,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
ret = ff_h2645_packet_split(&h2645_pkt, pkt->data, pkt->size,
ctx, 0, 0, ctx->par_in->codec_id);
if (ret < 0)
- return ret;
+ goto fail;

for (i = 0; i < h2645_pkt.nb_nals; i++) {
H2645NAL *nal = &h2645_pkt.nals[i];
--
2.12.2
Luca Barbato
2018-10-03 19:15:32 UTC
Permalink
From: James Almer <***@gmail.com>

Reviewed-by: Derek Buitenhuis <***@gmail.com>
Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/extract_extradata_bsf.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 10d108054a..ed5d90b246 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -114,6 +114,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
ret = AVERROR(ENOMEM);
goto fail;
}
+ memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);

*data = extradata;
*size = extradata_size;
@@ -137,6 +138,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
pkt->buf = filtered_buf;
pkt->data = filtered_buf->data;
pkt->size = filtered_data - filtered_buf->data;
+
+ memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
}

@@ -171,6 +174,7 @@ static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
return AVERROR(ENOMEM);

memcpy(*data, pkt->data, extradata_size);
+ memset(*data + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
*size = extradata_size;

if (s->remove) {
@@ -202,6 +206,8 @@ static int extract_extradata_mpeg124(AVBSFContext *ctx, AVPacket *pkt,
return AVERROR(ENOMEM);

memcpy(*data, pkt->data, *size);
+ memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE);

if (s->remove) {
pkt->data += *size;
--
2.12.2
James Almer
2018-10-04 02:59:09 UTC
Permalink
Post by Luca Barbato
---
libavcodec/extract_extradata_bsf.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 10d108054a..ed5d90b246 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -114,6 +114,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
ret = AVERROR(ENOMEM);
goto fail;
}
+ memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
*data = extradata;
*size = extradata_size;
@@ -137,6 +138,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
pkt->buf = filtered_buf;
pkt->data = filtered_buf->data;
pkt->size = filtered_data - filtered_buf->data;
+
+ memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
}
@@ -171,6 +174,7 @@ static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
return AVERROR(ENOMEM);
memcpy(*data, pkt->data, extradata_size);
+ memset(*data + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
*size = extradata_size;
if (s->remove) {
@@ -202,6 +206,8 @@ static int extract_extradata_mpeg124(AVBSFContext *ctx, AVPacket *pkt,
return AVERROR(ENOMEM);
memcpy(*data, pkt->data, *size);
+ memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
Duplicated line.

LGTM otherwise.
Post by Luca Barbato
if (s->remove) {
pkt->data += *size;
Luca Barbato
2018-10-03 19:15:33 UTC
Permalink
From: James Almer <***@gmail.com>

Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/extract_extradata_bsf.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index ed5d90b246..8d58aa10f6 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -62,7 +62,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
ExtractExtradataContext *s = ctx->priv_data;

H2645Packet h2645_pkt = { 0 };
- int extradata_size = 0;
+ int extradata_size = 0, filtered_size = 0;
const int *extradata_nal_types;
int nb_extradata_nal_types;
int i, has_sps = 0, has_vps = 0, ret = 0;
@@ -90,6 +90,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
} else {
if (nal->type == H264_NAL_SPS) has_sps = 1;
}
+ } else if (s->remove) {
+ filtered_size += nal->raw_size + 3;
}
}

@@ -100,11 +102,13 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
uint8_t *extradata, *filtered_data;

if (s->remove) {
- filtered_buf = av_buffer_alloc(pkt->size + AV_INPUT_BUFFER_PADDING_SIZE);
+ filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!filtered_buf) {
ret = AVERROR(ENOMEM);
goto fail;
}
+ memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
filtered_data = filtered_buf->data;
}

@@ -137,9 +141,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
av_buffer_unref(&pkt->buf);
pkt->buf = filtered_buf;
pkt->data = filtered_buf->data;
- pkt->size = filtered_data - filtered_buf->data;
-
- memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ pkt->size = filtered_size;
}
}
--
2.12.2
Luca Barbato
2018-10-03 19:15:34 UTC
Permalink
From: James Almer <***@gmail.com>

There is no need to allocate a new packet for it.

Reviewed-by: Mark Thompson <***@jkqxz.net>
Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/extract_extradata_bsf.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 8d58aa10f6..7b5ace301a 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -253,24 +253,23 @@ static int extract_extradata_init(AVBSFContext *ctx)
return 0;
}

-static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *out)
+static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *pkt)
{
ExtractExtradataContext *s = ctx->priv_data;
- AVPacket *in;
uint8_t *extradata = NULL;
int extradata_size;
int ret = 0;

- ret = ff_bsf_get_packet(ctx, &in);
+ ret = ff_bsf_get_packet_ref(ctx, pkt);
if (ret < 0)
return ret;

- ret = s->extract(ctx, in, &extradata, &extradata_size);
+ ret = s->extract(ctx, pkt, &extradata, &extradata_size);
if (ret < 0)
goto fail;

if (extradata) {
- ret = av_packet_add_side_data(in, AV_PKT_DATA_NEW_EXTRADATA,
+ ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
extradata, extradata_size);
if (ret < 0) {
av_freep(&extradata);
@@ -278,10 +277,10 @@ static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *out)
}
}

- av_packet_move_ref(out, in);
+ return 0;

fail:
- av_packet_free(&in);
+ av_packet_unref(pkt);
return ret;
}
--
2.12.2
Luca Barbato
2018-10-03 19:15:35 UTC
Permalink
From: James Almer <***@gmail.com>

Based on hevc_parser code. This prevents repeated unnecessary allocations
and frees on every packet processed by the bsf.

Reviewed-by: Jun Zhao <***@gmail.com>
Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/extract_extradata_bsf.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 7b5ace301a..0094d11496 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -36,6 +36,9 @@ typedef struct ExtractExtradataContext {
int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
uint8_t **data, int *size);

+ /* H264/HEVC specifc fields */
+ H2645Packet h2645_pkt;
+
/* AVOptions */
int remove;
} ExtractExtradataContext;
@@ -61,7 +64,6 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,

ExtractExtradataContext *s = ctx->priv_data;

- H2645Packet h2645_pkt = { 0 };
int extradata_size = 0, filtered_size = 0;
const int *extradata_nal_types;
int nb_extradata_nal_types;
@@ -75,13 +77,13 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_h264);
}

- ret = ff_h2645_packet_split(&h2645_pkt, pkt->data, pkt->size,
+ ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size,
ctx, 0, 0, ctx->par_in->codec_id);
if (ret < 0)
- goto fail;
+ return ret;

- for (i = 0; i < h2645_pkt.nb_nals; i++) {
- H2645NAL *nal = &h2645_pkt.nals[i];
+ for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
+ H2645NAL *nal = &s->h2645_pkt.nals[i];
if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) {
extradata_size += nal->raw_size + 3;
if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
@@ -104,8 +106,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
if (s->remove) {
filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!filtered_buf) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ return AVERROR(ENOMEM);
}
memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);

@@ -115,16 +116,15 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!extradata) {
av_buffer_unref(&filtered_buf);
- ret = AVERROR(ENOMEM);
- goto fail;
+ return AVERROR(ENOMEM);
}
memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);

*data = extradata;
*size = extradata_size;

- for (i = 0; i < h2645_pkt.nb_nals; i++) {
- H2645NAL *nal = &h2645_pkt.nals[i];
+ for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
+ H2645NAL *nal = &s->h2645_pkt.nals[i];
if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
nal->type)) {
AV_WB24(extradata, 1); // startcode
@@ -145,9 +145,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
}
}

-fail:
- ff_h2645_packet_uninit(&h2645_pkt);
- return ret;
+ return 0;
}

static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
@@ -284,6 +282,12 @@ fail:
return ret;
}

+static void extract_extradata_close(AVBSFContext *ctx)
+{
+ ExtractExtradataContext *s = ctx->priv_data;
+ ff_h2645_packet_uninit(&s->h2645_pkt);
+}
+
static const enum AVCodecID codec_ids[] = {
AV_CODEC_ID_CAVS,
AV_CODEC_ID_H264,
@@ -316,4 +320,5 @@ const AVBitStreamFilter ff_extract_extradata_bsf = {
.priv_class = &extract_extradata_class,
.init = extract_extradata_init,
.filter = extract_extradata_filter,
+ .close = extract_extradata_close,
};
--
2.12.2
Luca Barbato
2018-10-11 10:12:37 UTC
Permalink
Post by Luca Barbato
Based on hevc_parser code. This prevents repeated unnecessary allocations
and frees on every packet processed by the bsf.
---
libavcodec/extract_extradata_bsf.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
I'd merge the extract_extradata improvements today, James do you see
anything I should fold in?

lu
James Almer
2018-10-11 21:28:38 UTC
Permalink
Post by Luca Barbato
Post by Luca Barbato
Based on hevc_parser code. This prevents repeated unnecessary allocations
and frees on every packet processed by the bsf.
---
libavcodec/extract_extradata_bsf.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
I'd merge the extract_extradata improvements today, James do you see
anything I should fold in?
lu
No, patches 1 to 6 can go in as is.

Luca Barbato
2018-10-03 19:15:36 UTC
Permalink
From: James Almer <***@gmail.com>

Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/av1_parse.c | 103 ++++++++++++++++++++++++++++++++++++++++
libavcodec/av1_parse.h | 126 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 229 insertions(+)
create mode 100644 libavcodec/av1_parse.c
create mode 100644 libavcodec/av1_parse.h

diff --git a/libavcodec/av1_parse.c b/libavcodec/av1_parse.c
new file mode 100644
index 0000000000..45dbef379f
--- /dev/null
+++ b/libavcodec/av1_parse.c
@@ -0,0 +1,103 @@
+/*
+ * AV1 common parsing code
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "libavutil/mem.h"
+
+#include "av1_parse.h"
+#include "bytestream.h"
+
+int ff_av1_extract_obu(AV1OBU *obu, const uint8_t *buf, int length, void *logctx)
+{
+ int64_t obu_size;
+ int start_pos, type, temporal_id, spatial_id;
+
+ int ret = parse_obu_header(buf, length, &obu_size, &start_pos,
+ &type, &temporal_id, &spatial_id);
+ if (ret < 0)
+ return ret;
+
+ if (obu_size > INT_MAX / 8 || obu_size < 0)
+ return AVERROR(ERANGE);
+
+ obu->type = type;
+ obu->temporal_id = temporal_id;
+ obu->spatial_id = spatial_id;
+
+ length = obu_size + start_pos;
+
+ obu->data = buf + start_pos;
+ obu->size = obu_size;
+ obu->raw_data = buf;
+ obu->raw_size = length;
+
+ ret = init_get_bits(&obu->gb, obu->data, obu->size * 8);
+ if (ret < 0)
+ return ret;
+
+ av_log(logctx, AV_LOG_DEBUG,
+ "obu_type: %d, temporal_id: %d, spatial_id: %d, payload size: %d\n",
+ obu->type, obu->temporal_id, obu->spatial_id, obu->size);
+
+ return length;
+}
+
+int ff_av1_packet_split(AV1Packet *pkt, const uint8_t *buf, int length, void *logctx)
+{
+ GetByteContext bc;
+ int consumed;
+
+ bytestream2_init(&bc, buf, length);
+ pkt->nb_obus = 0;
+
+ while (bytestream2_get_bytes_left(&bc) > 0) {
+ AV1OBU *obu;
+
+ if (pkt->obus_allocated < pkt->nb_obus + 1) {
+ int new_size = pkt->obus_allocated + 1;
+ AV1OBU *tmp = av_realloc_array(pkt->obus, new_size, sizeof(*tmp));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+
+ pkt->obus = tmp;
+ memset(pkt->obus + pkt->obus_allocated, 0,
+ (new_size - pkt->obus_allocated) * sizeof(*tmp));
+ pkt->obus_allocated = new_size;
+ }
+ obu = &pkt->obus[pkt->nb_obus];
+
+ consumed = ff_av1_extract_obu(obu, bc.buffer, bytestream2_get_bytes_left(&bc), logctx);
+ if (consumed < 0)
+ return consumed;
+
+ pkt->nb_obus++;
+
+ bytestream2_skip(&bc, consumed);
+ }
+
+ return 0;
+}
+
+void ff_av1_packet_uninit(AV1Packet *pkt)
+{
+ av_freep(&pkt->obus);
+ pkt->obus_allocated = 0;
+}
diff --git a/libavcodec/av1_parse.h b/libavcodec/av1_parse.h
new file mode 100644
index 0000000000..5e2337d5e4
--- /dev/null
+++ b/libavcodec/av1_parse.h
@@ -0,0 +1,126 @@
+/*
+ * AV1 common parsing code
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_AV1_PARSE_H
+#define AVCODEC_AV1_PARSE_H
+
+#include <stdint.h>
+
+#include "avcodec.h"
+#include "get_bits.h"
+
+typedef struct AV1OBU {
+ /** Size of payload */
+ int size;
+ const uint8_t *data;
+
+ /** Size of entire OBU, including header */
+ int raw_size;
+ const uint8_t *raw_data;
+
+ /** GetBitContext initialized to the start of the payload */
+ GetBitContext gb;
+
+ int type;
+
+ int temporal_id;
+ int spatial_id;
+} AV1OBU;
+
+/** An input packet split into OBUs */
+typedef struct AV1Packet {
+ AV1OBU *obus;
+ int nb_obus;
+ int obus_allocated;
+} AV1Packet;
+
+/**
+ * Extract an OBU from a raw bitstream.
+ *
+ * @note This function does not copy or store any bistream data. All
+ * the pointers in the AV1OBU structure will be valid as long
+ * as the input buffer also is.
+ */
+int ff_av1_extract_obu(AV1OBU *obu, const uint8_t *buf, int length,
+ void *logctx);
+
+/**
+ * Split an input packet into OBUs.
+ *
+ * @note This function does not copy or store any bistream data. All
+ * the pointers in the AV1Packet structure will be valid as
+ * long as the input buffer also is.
+ */
+int ff_av1_packet_split(AV1Packet *pkt, const uint8_t *buf, int length,
+ void *logctx);
+
+/**
+ * Free all the allocated memory in the packet.
+ */
+void ff_av1_packet_uninit(AV1Packet *pkt);
+
+static inline int64_t leb128(GetBitContext *gb) {
+ int64_t ret = 0;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ int byte = get_bits(gb, 8);
+ ret |= (int64_t)(byte & 0x7f) << (i * 7);
+ if (!(byte & 0x80))
+ break;
+ }
+ return ret;
+}
+
+static inline int parse_obu_header(const uint8_t *buf, int buf_size,
+ int64_t *obu_size, int *start_pos, int *type,
+ int *temporal_id, int *spatial_id)
+{
+ GetBitContext gb;
+ int ret, extension_flag, has_size_flag;
+
+ ret = init_get_bits8(&gb, buf, FFMIN(buf_size, 2 + 8)); // OBU header fields + max leb128 length
+ if (ret < 0)
+ return ret;
+
+ if (get_bits1(&gb) != 0) // obu_forbidden_bit
+ return AVERROR_INVALIDDATA;
+
+ *type = get_bits(&gb, 4);
+ extension_flag = get_bits1(&gb);
+ has_size_flag = get_bits1(&gb);
+ skip_bits1(&gb); // obu_reserved_1bit
+
+ if (extension_flag) {
+ *temporal_id = get_bits(&gb, 3);
+ *spatial_id = get_bits(&gb, 2);
+ skip_bits(&gb, 3); // extension_header_reserved_3bits
+ } else {
+ *temporal_id = *spatial_id = 0;
+ }
+
+ *obu_size = has_size_flag ? leb128(&gb)
+ : buf_size - 1 - extension_flag;
+ *start_pos = get_bits_count(&gb) / 8;
+
+ return 0;
+}
+
+#endif /* AVCODEC_AV1_PARSE_H */
--
2.12.2
James Almer
2018-10-04 02:57:17 UTC
Permalink
Post by Luca Barbato
---
libavcodec/av1_parse.c | 103 ++++++++++++++++++++++++++++++++++++++++
libavcodec/av1_parse.h | 126 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 229 insertions(+)
create mode 100644 libavcodec/av1_parse.c
create mode 100644 libavcodec/av1_parse.h
This got some extra changes after the fact that i think would be best if
they are squashed into this commit instead of being separate.
Similarly, the actual mp4/matroska changes that came after this got
several modifications that followed the evolution of the spec from draft
to final, which in some cases meant rewriting the whole thing.
Luca Barbato
2018-10-04 08:41:38 UTC
Permalink
Post by James Almer
Post by Luca Barbato
---
libavcodec/av1_parse.c | 103 ++++++++++++++++++++++++++++++++++++++++
libavcodec/av1_parse.h | 126 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 229 insertions(+)
create mode 100644 libavcodec/av1_parse.c
create mode 100644 libavcodec/av1_parse.h
This got some extra changes after the fact that i think would be best if
they are squashed into this commit instead of being separate.
I hope to have time to pick them.
Post by James Almer
Similarly, the actual mp4/matroska changes that came after this got
several modifications that followed the evolution of the spec from draft
to final, which in some cases meant rewriting the whole thing.
Thank you for pointing this out :)

lu
Luca Barbato
2018-10-03 19:15:37 UTC
Permalink
From: James Almer <***@gmail.com>

Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/Makefile | 2 +-
libavcodec/extract_extradata_bsf.c | 80 ++++++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index ea0c9dceae..3f6ecb2d13 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -781,7 +781,7 @@ OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o mpeg4audio.o
OBJS-$(CONFIG_CHOMP_BSF) += chomp_bsf.o
OBJS-$(CONFIG_DUMP_EXTRADATA_BSF) += dump_extradata_bsf.o
OBJS-$(CONFIG_EXTRACT_EXTRADATA_BSF) += extract_extradata_bsf.o \
- h2645_parse.o
+ av1_parse.o h2645_parse.o
OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o
OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o
OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o
diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 0094d11496..2734a7b7d1 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -24,6 +24,8 @@
#include "libavutil/opt.h"

#include "avcodec.h"
+#include "av1.h"
+#include "av1_parse.h"
#include "bsf.h"
#include "h2645_parse.h"
#include "h264.h"
@@ -36,6 +38,9 @@ typedef struct ExtractExtradataContext {
int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
uint8_t **data, int *size);

+ /* AV1 specifc fields */
+ AV1Packet av1_pkt;
+
/* H264/HEVC specifc fields */
H2645Packet h2645_pkt;

@@ -52,6 +57,78 @@ static int val_in_array(const int *arr, int len, int val)
return 0;
}

+static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
+ uint8_t **data, int *size)
+{
+ static const int extradata_obu_types[] = {
+ AV1_OBU_SEQUENCE_HEADER, AV1_OBU_METADATA,
+ };
+ ExtractExtradataContext *s = ctx->priv_data;
+
+ int extradata_size = 0, filtered_size = 0;
+ int nb_extradata_obu_types = FF_ARRAY_ELEMS(extradata_obu_types);
+ int i, ret = 0;
+
+ ret = ff_av1_packet_split(&s->av1_pkt, pkt->data, pkt->size, ctx);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < s->av1_pkt.nb_obus; i++) {
+ AV1OBU *obu = &s->av1_pkt.obus[i];
+ if (val_in_array(extradata_obu_types, nb_extradata_obu_types, obu->type)) {
+ extradata_size += obu->raw_size;
+ } else if (s->remove) {
+ filtered_size += obu->raw_size;
+ }
+ }
+
+ if (extradata_size) {
+ AVBufferRef *filtered_buf;
+ uint8_t *extradata, *filtered_data;
+
+ if (s->remove) {
+ filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!filtered_buf) {
+ return AVERROR(ENOMEM);
+ }
+ memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
+ filtered_data = filtered_buf->data;
+ }
+
+ extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!extradata) {
+ av_buffer_unref(&filtered_buf);
+ return AVERROR(ENOMEM);
+ }
+ memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
+ *data = extradata;
+ *size = extradata_size;
+
+ for (i = 0; i < s->av1_pkt.nb_obus; i++) {
+ AV1OBU *obu = &s->av1_pkt.obus[i];
+ if (val_in_array(extradata_obu_types, nb_extradata_obu_types,
+ obu->type)) {
+ memcpy(extradata, obu->raw_data, obu->raw_size);
+ extradata += obu->raw_size;
+ } else if (s->remove) {
+ memcpy(filtered_data, obu->raw_data, obu->raw_size);
+ filtered_data += obu->raw_size;
+ }
+ }
+
+ if (s->remove) {
+ av_buffer_unref(&pkt->buf);
+ pkt->buf = filtered_buf;
+ pkt->data = filtered_buf->data;
+ pkt->size = filtered_size;
+ }
+ }
+
+ return 0;
+}
+
static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
uint8_t **data, int *size)
{
@@ -225,6 +302,7 @@ static const struct {
int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
uint8_t **data, int *size);
} extract_tab[] = {
+ { AV_CODEC_ID_AV1, extract_extradata_av1 },
{ AV_CODEC_ID_CAVS, extract_extradata_mpeg124 },
{ AV_CODEC_ID_H264, extract_extradata_h2645 },
{ AV_CODEC_ID_HEVC, extract_extradata_h2645 },
@@ -285,10 +363,12 @@ fail:
static void extract_extradata_close(AVBSFContext *ctx)
{
ExtractExtradataContext *s = ctx->priv_data;
+ ff_av1_packet_uninit(&s->av1_pkt);
ff_h2645_packet_uninit(&s->h2645_pkt);
}

static const enum AVCodecID codec_ids[] = {
+ AV_CODEC_ID_AV1,
AV_CODEC_ID_CAVS,
AV_CODEC_ID_H264,
AV_CODEC_ID_HEVC,
--
2.12.2
Luca Barbato
2018-10-03 19:15:38 UTC
Permalink
From: James Almer <***@gmail.com>

A packet may have Metadata OBUs but no Sequence Header OBU, which is
useless as extradata.

Signed-off-by: James Almer <***@gmail.com>
Signed-off-by: Luca Barbato <***@gentoo.org>
---
libavcodec/extract_extradata_bsf.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 2734a7b7d1..9ee2b28d01 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -67,7 +67,7 @@ static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,

int extradata_size = 0, filtered_size = 0;
int nb_extradata_obu_types = FF_ARRAY_ELEMS(extradata_obu_types);
- int i, ret = 0;
+ int i, has_seq = 0, ret = 0;

ret = ff_av1_packet_split(&s->av1_pkt, pkt->data, pkt->size, ctx);
if (ret < 0)
@@ -77,12 +77,14 @@ static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
AV1OBU *obu = &s->av1_pkt.obus[i];
if (val_in_array(extradata_obu_types, nb_extradata_obu_types, obu->type)) {
extradata_size += obu->raw_size;
+ if (obu->type == AV1_OBU_SEQUENCE_HEADER)
+ has_seq = 1;
} else if (s->remove) {
filtered_size += obu->raw_size;
}
}

- if (extradata_size) {
+ if (extradata_size && has_seq) {
AVBufferRef *filtered_buf;
uint8_t *extradata, *filtered_data;
--
2.12.2
James Almer
2018-10-04 02:59:54 UTC
Permalink
Post by Luca Barbato
A packet may have Metadata OBUs but no Sequence Header OBU, which is
useless as extradata.
---
libavcodec/extract_extradata_bsf.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 2734a7b7d1..9ee2b28d01 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -67,7 +67,7 @@ static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
int extradata_size = 0, filtered_size = 0;
int nb_extradata_obu_types = FF_ARRAY_ELEMS(extradata_obu_types);
- int i, ret = 0;
+ int i, has_seq = 0, ret = 0;
ret = ff_av1_packet_split(&s->av1_pkt, pkt->data, pkt->size, ctx);
if (ret < 0)
@@ -77,12 +77,14 @@ static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
AV1OBU *obu = &s->av1_pkt.obus[i];
if (val_in_array(extradata_obu_types, nb_extradata_obu_types, obu->type)) {
extradata_size += obu->raw_size;
+ if (obu->type == AV1_OBU_SEQUENCE_HEADER)
+ has_seq = 1;
} else if (s->remove) {
filtered_size += obu->raw_size;
}
}
- if (extradata_size) {
+ if (extradata_size && has_seq) {
AVBufferRef *filtered_buf;
uint8_t *extradata, *filtered_data;
Same, i think this would be better squashed with the previous commit.
Luca Barbato
2018-10-06 19:36:03 UTC
Permalink
Post by James Almer
Post by Luca Barbato
A packet may have Metadata OBUs but no Sequence Header OBU, which is
useless as extradata.
---
libavcodec/extract_extradata_bsf.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c
index 2734a7b7d1..9ee2b28d01 100644
--- a/libavcodec/extract_extradata_bsf.c
+++ b/libavcodec/extract_extradata_bsf.c
@@ -67,7 +67,7 @@ static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
int extradata_size = 0, filtered_size = 0;
int nb_extradata_obu_types = FF_ARRAY_ELEMS(extradata_obu_types);
- int i, ret = 0;
+ int i, has_seq = 0, ret = 0;
ret = ff_av1_packet_split(&s->av1_pkt, pkt->data, pkt->size, ctx);
if (ret < 0)
@@ -77,12 +77,14 @@ static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
AV1OBU *obu = &s->av1_pkt.obus[i];
if (val_in_array(extradata_obu_types, nb_extradata_obu_types, obu->type)) {
extradata_size += obu->raw_size;
+ if (obu->type == AV1_OBU_SEQUENCE_HEADER)
+ has_seq = 1;
} else if (s->remove) {
filtered_size += obu->raw_size;
}
}
- if (extradata_size) {
+ if (extradata_size && has_seq) {
AVBufferRef *filtered_buf;
uint8_t *extradata, *filtered_data;
Same, i think this would be better squashed with the previous commit.
I'll try to get all the mkv and mp4 commits in, then I'll try to squash
them all once I'm more or less sure they behave as needed.

lu
Loading...