diff --git a/libavformat/av1.c b/libavformat/av1.c index 709484b361..1e7a67d2f2 100644 --- a/libavformat/av1.c +++ b/libavformat/av1.c @@ -29,13 +29,20 @@ #include "avio.h" #include "avio_internal.h" -int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size) +static int av1_filter_obus(AVIOContext *pb, const uint8_t *buf, + int size, int *offset) { - const uint8_t *end = buf + size; + const uint8_t *start = buf, *end = buf + size; int64_t obu_size; - int start_pos, type, temporal_id, spatial_id; + int off, start_pos, type, temporal_id, spatial_id; + enum { + START_NOT_FOUND, + START_FOUND, + END_FOUND, + OFFSET_IMPOSSIBLE, + } state = START_NOT_FOUND; - size = 0; + off = size = 0; while (buf < end) { int len = parse_obu_header(buf, end - buf, &obu_size, &start_pos, &type, &temporal_id, &spatial_id); @@ -47,8 +54,16 @@ int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size) case AV1_OBU_REDUNDANT_FRAME_HEADER: case AV1_OBU_TILE_LIST: case AV1_OBU_PADDING: + if (state == START_FOUND) + state = END_FOUND; break; default: + if (state == START_NOT_FOUND) { + off = buf - start; + state = START_FOUND; + } else if (state == END_FOUND) { + state = OFFSET_IMPOSSIBLE; + } if (pb) avio_write(pb, buf, len); size += len; @@ -57,19 +72,35 @@ int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size) buf += len; } + if (offset) + *offset = state != OFFSET_IMPOSSIBLE ? off : -1; + return size; } -int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out, int *size) +int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size) +{ + return av1_filter_obus(pb, buf, size, NULL); +} + +int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out, + int *size, int *offset) { AVIOContext pb; uint8_t *buf; - int len, ret; + int len, off, ret; - len = ret = ff_av1_filter_obus(NULL, in, *size); + len = ret = av1_filter_obus(NULL, in, *size, &off); if (ret < 0) { return ret; } + if (off >= 0) { + *out = (uint8_t *)in; + *size = len; + *offset = off; + + return 0; + } buf = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE); if (!buf) @@ -77,13 +108,14 @@ int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out, int *size) ffio_init_context(&pb, buf, len, 1, NULL, NULL, NULL, NULL); - ret = ff_av1_filter_obus(&pb, in, *size); + ret = av1_filter_obus(&pb, in, *size, NULL); av_assert1(ret == len); memset(buf + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); *out = buf; *size = len; + *offset = 0; return 0; } diff --git a/libavformat/av1.h b/libavformat/av1.h index 6cc3fcaad2..dd5b47dc25 100644 --- a/libavformat/av1.h +++ b/libavformat/av1.h @@ -56,19 +56,24 @@ typedef struct AV1SequenceParameters { int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size); /** - * Filter out AV1 OBUs not meant to be present in ISOBMFF sample data and write - * the resulting bitstream to a newly allocated data buffer. + * Filter out AV1 OBUs not meant to be present in ISOBMFF sample data and return + * the result in a data buffer, avoiding allocations and copies if possible. * * @param in input data buffer - * @param out pointer to pointer that will hold the allocated data buffer + * @param out pointer to pointer for the returned buffer. In case of success, + * it is independently allocated if and only if `*out` differs from in. * @param size size of the input data buffer. The size of the resulting output * data buffer will be written here + * @param offset offset of the returned data inside `*out`: It runs from + * `*out + offset` (inclusive) to `*out + offset + size` + * (exclusive); is zero if `*out` is independently allocated. * * @return 0 in case of success, a negative AVERROR code in case of failure. * On failure, *out and *size are unchanged * @note *out will be treated as unintialized on input and will not be freed. */ -int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out, int *size); +int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out, + int *size, int *offset); /** * Parses a Sequence Header from the the provided buffer. diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 20bad95262..618f07c769 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -2112,7 +2112,7 @@ static int mkv_write_block(AVFormatContext *s, AVIOContext *pb, /* extradata is Annex B, assume the bitstream is too and convert it */ err = ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL); } else if (par->codec_id == AV_CODEC_ID_AV1) { - err = ff_av1_filter_obus_buf(pkt->data, &data, &size); + err = ff_av1_filter_obus_buf(pkt->data, &data, &size, &offset); } else if (par->codec_id == AV_CODEC_ID_WAVPACK) { err = mkv_strip_wavpack(pkt->data, &data, &size); } else diff --git a/libavformat/movenc.c b/libavformat/movenc.c index c0a5e1f2e0..9de8a61d2e 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -5374,7 +5374,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) AVCodecParameters *par = trk->par; AVProducerReferenceTime *prft; unsigned int samples_in_chunk = 0; - int size = pkt->size, ret = 0; + int size = pkt->size, ret = 0, offset = 0; int prft_size; uint8_t *reformatted_data = NULL; @@ -5491,7 +5491,8 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } } else if (par->codec_id == AV_CODEC_ID_AV1) { if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) { - ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data, &size); + ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data, + &size, &offset); if (ret < 0) return ret; avio_write(pb, reformatted_data, size); @@ -5667,12 +5668,14 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry, - reformatted_data, size); + reformatted_data ? reformatted_data + offset + : NULL, size); end: err: - av_free(reformatted_data); + if (pkt->data != reformatted_data) + av_free(reformatted_data); return ret; }