From b8c45bbcbc207293f955e838ea66106f4b65b1ac Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Mon, 11 Feb 2019 23:47:43 +0100 Subject: libavcodec/cbs: Stop needlessly reallocating the units array Currently, a fragment's unit array is constantly reallocated during splitting of a packet. This commit changes this: One can keep the units array by distinguishing between the number of allocated and the number of valid units in the units array. The more units a packet is split into, the bigger the benefit. So MPEG-2 benefits the most; for a video coming from an NTSC-DVD (usually 32 units per frame) the average cost of cbs_insert_unit (for a single unit) went down from 6717 decicycles to 450 decicycles (based upon 10 runs with 4194304 runs each); if each packet consists of only one unit, it went down from 2425 to 448; for a H.264 video where most packets contain nine units, it went from 4431 to 450. Signed-off-by: Andreas Rheinhardt --- libavcodec/av1_metadata_bsf.c | 6 ++-- libavcodec/av1_parser.c | 5 +-- libavcodec/cbs.c | 62 +++++++++++++++++++++---------------- libavcodec/cbs.h | 33 +++++++++++++++++--- libavcodec/filter_units_bsf.c | 7 +++-- libavcodec/h264_metadata_bsf.c | 6 ++-- libavcodec/h264_redundant_pps_bsf.c | 6 ++-- libavcodec/h265_metadata_bsf.c | 6 ++-- libavcodec/mpeg2_metadata_bsf.c | 6 ++-- libavcodec/trace_headers_bsf.c | 5 +-- libavcodec/vaapi_encode_h264.c | 9 +++--- libavcodec/vaapi_encode_h265.c | 9 +++--- libavcodec/vaapi_encode_mjpeg.c | 3 +- libavcodec/vaapi_encode_mpeg2.c | 5 +-- libavcodec/vp9_metadata_bsf.c | 4 ++- 15 files changed, 113 insertions(+), 59 deletions(-) diff --git a/libavcodec/av1_metadata_bsf.c b/libavcodec/av1_metadata_bsf.c index 52d383661f..2b74b697e4 100644 --- a/libavcodec/av1_metadata_bsf.c +++ b/libavcodec/av1_metadata_bsf.c @@ -170,7 +170,7 @@ static int av1_metadata_filter(AVBSFContext *bsf, AVPacket *out) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); if (err < 0) av_packet_unref(out); @@ -215,13 +215,15 @@ static int av1_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); return err; } static void av1_metadata_close(AVBSFContext *bsf) { AV1MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/av1_parser.c b/libavcodec/av1_parser.c index 8df66498f4..bb8737a393 100644 --- a/libavcodec/av1_parser.c +++ b/libavcodec/av1_parser.c @@ -72,7 +72,7 @@ static int av1_parser_parse(AVCodecParserContext *ctx, goto end; } - ff_cbs_fragment_uninit(s->cbc, td); + ff_cbs_fragment_reset(s->cbc, td); } ret = ff_cbs_read(s->cbc, td, data, size); @@ -159,7 +159,7 @@ static int av1_parser_parse(AVCodecParserContext *ctx, } end: - ff_cbs_fragment_uninit(s->cbc, td); + ff_cbs_fragment_reset(s->cbc, td); s->cbc->log_ctx = NULL; @@ -193,6 +193,7 @@ static void av1_parser_close(AVCodecParserContext *ctx) { AV1ParseContext *s = ctx->priv_data; + ff_cbs_fragment_free(s->cbc, &s->temporal_unit); ff_cbs_close(&s->cbc); } diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index ecbf57c293..c388be896b 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -136,14 +136,13 @@ static void cbs_unit_uninit(CodedBitstreamContext *ctx, unit->data_bit_padding = 0; } -void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag) +void ff_cbs_fragment_reset(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { int i; for (i = 0; i < frag->nb_units; i++) cbs_unit_uninit(ctx, &frag->units[i]); - av_freep(&frag->units); frag->nb_units = 0; av_buffer_unref(&frag->data_ref); @@ -152,6 +151,15 @@ void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, frag->data_bit_padding = 0; } +void ff_cbs_fragment_free(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + ff_cbs_fragment_reset(ctx, frag); + + av_freep(&frag->units); + frag->nb_units_allocated = 0; +} + static int cbs_read_fragment_content(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { @@ -216,8 +224,6 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, { int err; - memset(frag, 0, sizeof(*frag)); - err = cbs_fill_fragment_data(ctx, frag, par->extradata, par->extradata_size); if (err < 0) @@ -236,8 +242,6 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, { int err; - memset(frag, 0, sizeof(*frag)); - if (pkt->buf) { frag->data_ref = av_buffer_ref(pkt->buf); if (!frag->data_ref) @@ -265,8 +269,6 @@ int ff_cbs_read(CodedBitstreamContext *ctx, { int err; - memset(frag, 0, sizeof(*frag)); - err = cbs_fill_fragment_data(ctx, frag, data, size); if (err < 0) return err; @@ -548,20 +550,34 @@ static int cbs_insert_unit(CodedBitstreamContext *ctx, { CodedBitstreamUnit *units; - units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); - if (!units) - return AVERROR(ENOMEM); + if (frag->nb_units < frag->nb_units_allocated) { + units = frag->units; + + if (position < frag->nb_units) + memmove(units + position + 1, units + position, + (frag->nb_units - position) * sizeof(*units)); + } else { + units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); + if (!units) + return AVERROR(ENOMEM); + + ++frag->nb_units_allocated; - if (position > 0) - memcpy(units, frag->units, position * sizeof(*units)); - if (position < frag->nb_units) - memcpy(units + position + 1, frag->units + position, - (frag->nb_units - position) * sizeof(*units)); + if (position > 0) + memcpy(units, frag->units, position * sizeof(*units)); + + if (position < frag->nb_units) + memcpy(units + position + 1, frag->units + position, + (frag->nb_units - position) * sizeof(*units)); + } memset(units + position, 0, sizeof(*units)); - av_freep(&frag->units); - frag->units = units; + if (units != frag->units) { + av_free(frag->units); + frag->units = units; + } + ++frag->nb_units; return 0; @@ -652,16 +668,10 @@ int ff_cbs_delete_unit(CodedBitstreamContext *ctx, --frag->nb_units; - if (frag->nb_units == 0) { - av_freep(&frag->units); - - } else { + if (frag->nb_units > 0) memmove(frag->units + position, frag->units + position + 1, (frag->nb_units - position) * sizeof(*frag->units)); - // Don't bother reallocating the unit array. - } - return 0; } diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index 53ac360bb1..967dcd1468 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -145,10 +145,19 @@ typedef struct CodedBitstreamFragment { * and has not been decomposed. */ int nb_units; + + /** + * Number of allocated units. + * + * Must always be >= nb_units; designed for internal use by cbs. + */ + int nb_units_allocated; + /** - * Pointer to an array of units of length nb_units. + * Pointer to an array of units of length nb_units_allocated. + * Only the first nb_units are valid. * - * Must be NULL if nb_units is zero. + * Must be NULL if nb_units_allocated is zero. */ CodedBitstreamUnit *units; } CodedBitstreamFragment; @@ -231,6 +240,9 @@ void ff_cbs_close(CodedBitstreamContext **ctx); * This also updates the internal state, so will need to be called for * codecs with extradata to read parameter sets necessary for further * parsing even if the fragment itself is not desired. + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. */ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, @@ -243,6 +255,9 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, * This also updates the internal state of the coded bitstream context * with any persistent data from the fragment which may be required to * read following fragments (e.g. parameter sets). + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. */ int ff_cbs_read_packet(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, @@ -255,6 +270,9 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, * This also updates the internal state of the coded bitstream context * with any persistent data from the fragment which may be required to * read following fragments (e.g. parameter sets). + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. */ int ff_cbs_read(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, @@ -294,11 +312,18 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, /** - * Free all allocated memory in a fragment. + * Free the units contained in a fragment as well as the fragment's + * own data buffer, but not the units array itself. */ -void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, +void ff_cbs_fragment_reset(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag); +/** + * Free the units array of a fragment in addition to what + * ff_cbs_fragment_reset does. + */ +void ff_cbs_fragment_free(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); /** * Allocate a new internal content buffer of the given size in the unit. diff --git a/libavcodec/filter_units_bsf.c b/libavcodec/filter_units_bsf.c index 0500dea6b2..bc2ca288dd 100644 --- a/libavcodec/filter_units_bsf.c +++ b/libavcodec/filter_units_bsf.c @@ -139,7 +139,7 @@ static int filter_units_filter(AVBSFContext *bsf, AVPacket *out) // Don't return packets with nothing in them. av_packet_free(&in); - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); } err = ff_cbs_write_packet(ctx->cbc, out, frag); @@ -153,7 +153,7 @@ static int filter_units_filter(AVBSFContext *bsf, AVPacket *out) goto fail; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); av_packet_free(&in); return err; @@ -210,7 +210,7 @@ static int filter_units_init(AVBSFContext *bsf) av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); } - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); } return err; @@ -222,6 +222,7 @@ static void filter_units_close(AVBSFContext *bsf) av_freep(&ctx->type_list); + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c index e674f2a88d..a17987a06c 100644 --- a/libavcodec/h264_metadata_bsf.c +++ b/libavcodec/h264_metadata_bsf.c @@ -604,7 +604,7 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); av_freep(&displaymatrix_side_data); if (err < 0) @@ -648,13 +648,15 @@ static int h264_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); return err; } static void h264_metadata_close(AVBSFContext *bsf) { H264MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/h264_redundant_pps_bsf.c b/libavcodec/h264_redundant_pps_bsf.c index 0b7888c97e..db8717d69a 100644 --- a/libavcodec/h264_redundant_pps_bsf.c +++ b/libavcodec/h264_redundant_pps_bsf.c @@ -118,7 +118,7 @@ static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) err = 0; fail: - ff_cbs_fragment_uninit(ctx->output, au); + ff_cbs_fragment_reset(ctx->output, au); av_packet_free(&in); if (err < 0) av_packet_unref(out); @@ -167,7 +167,7 @@ static int h264_redundant_pps_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->output, au); + ff_cbs_fragment_reset(ctx->output, au); return err; } @@ -180,6 +180,8 @@ static void h264_redundant_pps_flush(AVBSFContext *bsf) static void h264_redundant_pps_close(AVBSFContext *bsf) { H264RedundantPPSContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->input, &ctx->access_unit); ff_cbs_close(&ctx->input); ff_cbs_close(&ctx->output); } diff --git a/libavcodec/h265_metadata_bsf.c b/libavcodec/h265_metadata_bsf.c index 26eb2d05d0..0683cc2f9d 100644 --- a/libavcodec/h265_metadata_bsf.c +++ b/libavcodec/h265_metadata_bsf.c @@ -322,7 +322,7 @@ static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); if (err < 0) av_packet_unref(out); @@ -370,13 +370,15 @@ static int h265_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); return err; } static void h265_metadata_close(AVBSFContext *bsf) { H265MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c index e787cb3782..ba3a74afda 100644 --- a/libavcodec/mpeg2_metadata_bsf.c +++ b/libavcodec/mpeg2_metadata_bsf.c @@ -214,7 +214,7 @@ static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *out) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); if (err < 0) av_packet_unref(out); @@ -255,13 +255,15 @@ static int mpeg2_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); return err; } static void mpeg2_metadata_close(AVBSFContext *bsf) { MPEG2MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c index 61284e615e..3ec78fe822 100644 --- a/libavcodec/trace_headers_bsf.c +++ b/libavcodec/trace_headers_bsf.c @@ -51,7 +51,7 @@ static int trace_headers_init(AVBSFContext *bsf) err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in); - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); } return err; @@ -61,6 +61,7 @@ static void trace_headers_close(AVBSFContext *bsf) { TraceHeadersContext *ctx = bsf->priv_data; + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } @@ -95,7 +96,7 @@ static int trace_headers(AVBSFContext *bsf, AVPacket *pkt) err = ff_cbs_read_packet(ctx->cbc, frag, pkt); - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); if (err < 0) av_packet_unref(pkt); diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 4ea62d96f3..9f984ec60d 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -174,7 +174,7 @@ static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx, err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -200,7 +200,7 @@ static int vaapi_encode_h264_write_slice_header(AVCodecContext *avctx, err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -264,7 +264,7 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, if (err < 0) goto fail; - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); *type = VAEncPackedHeaderRawData; return 0; @@ -286,7 +286,7 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, } fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -1233,6 +1233,7 @@ static av_cold int vaapi_encode_h264_close(AVCodecContext *avctx) { VAAPIEncodeH264Context *priv = avctx->priv_data; + ff_cbs_fragment_free(priv->cbc, &priv->current_access_unit); ff_cbs_close(&priv->cbc); av_freep(&priv->sei_identifier_string); diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 19e7104e9e..9e32cd285b 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -159,7 +159,7 @@ static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -185,7 +185,7 @@ static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -242,7 +242,7 @@ static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx, if (err < 0) goto fail; - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); *type = VAEncPackedHeaderRawData; return 0; @@ -251,7 +251,7 @@ static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx, } fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -1182,6 +1182,7 @@ static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) { VAAPIEncodeH265Context *priv = avctx->priv_data; + ff_cbs_fragment_free(priv->cbc, &priv->current_access_unit); ff_cbs_close(&priv->cbc); return ff_vaapi_encode_close(avctx); diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index f0ea292098..72e794604a 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -142,7 +142,7 @@ static int vaapi_encode_mjpeg_write_image_header(AVCodecContext *avctx, err = 0; fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(priv->cbc, frag); return err; } @@ -515,6 +515,7 @@ static av_cold int vaapi_encode_mjpeg_close(AVCodecContext *avctx) { VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + ff_cbs_fragment_free(priv->cbc, &priv->current_fragment); ff_cbs_close(&priv->cbc); return ff_vaapi_encode_close(avctx); diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 9d42c3e644..ccea251f87 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -135,7 +135,7 @@ static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(priv->cbc, frag); return 0; } @@ -159,7 +159,7 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(priv->cbc, frag); return 0; } @@ -628,6 +628,7 @@ static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) { VAAPIEncodeMPEG2Context *priv = avctx->priv_data; + ff_cbs_fragment_free(priv->cbc, &priv->current_fragment); ff_cbs_close(&priv->cbc); return ff_vaapi_encode_close(avctx); diff --git a/libavcodec/vp9_metadata_bsf.c b/libavcodec/vp9_metadata_bsf.c index be010edc3f..b79f08af6c 100644 --- a/libavcodec/vp9_metadata_bsf.c +++ b/libavcodec/vp9_metadata_bsf.c @@ -86,7 +86,7 @@ static int vp9_metadata_filter(AVBSFContext *bsf, AVPacket *out) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); if (err < 0) av_packet_unref(out); @@ -105,6 +105,8 @@ static int vp9_metadata_init(AVBSFContext *bsf) static void vp9_metadata_close(AVBSFContext *bsf) { VP9MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } -- cgit v1.2.3