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 <andreas.rheinhardt@googlemail.com>tags/n4.2
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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; | |||
| } | |||
| @@ -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. | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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); | |||
| } | |||