All cbs-functions to write units share a common pattern:
1. They check whether they have a write buffer (that is used to store
the unit's data until the needed size becomes known after writing the
unit when a dedicated buffer will be allocated).
2. They use this buffer for a PutBitContext.
3. The (codec-specific) writing takes place through the PutBitContext.
4. The return value is checked. AVERROR(ENOSPC) here always indicates
that the buffer was too small and leads to a reallocation of said
buffer.
5. The final buffer will be allocated and the data copied.
This commit factors this common code out in a single function in cbs.c.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
(cherry picked from commit 7c92eaace2)
tags/n4.2.2
| @@ -95,10 +95,12 @@ int ff_cbs_init(CodedBitstreamContext **ctx_ptr, | |||||
| ctx->log_ctx = log_ctx; | ctx->log_ctx = log_ctx; | ||||
| ctx->codec = type; | ctx->codec = type; | ||||
| ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); | |||||
| if (!ctx->priv_data) { | |||||
| av_freep(&ctx); | |||||
| return AVERROR(ENOMEM); | |||||
| if (type->priv_data_size) { | |||||
| ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); | |||||
| if (!ctx->priv_data) { | |||||
| av_freep(&ctx); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| } | } | ||||
| ctx->decompose_unit_types = NULL; | ctx->decompose_unit_types = NULL; | ||||
| @@ -120,6 +122,7 @@ void ff_cbs_close(CodedBitstreamContext **ctx_ptr) | |||||
| if (ctx->codec && ctx->codec->close) | if (ctx->codec && ctx->codec->close) | ||||
| ctx->codec->close(ctx); | ctx->codec->close(ctx); | ||||
| av_freep(&ctx->write_buffer); | |||||
| av_freep(&ctx->priv_data); | av_freep(&ctx->priv_data); | ||||
| av_freep(ctx_ptr); | av_freep(ctx_ptr); | ||||
| } | } | ||||
| @@ -280,6 +283,57 @@ int ff_cbs_read(CodedBitstreamContext *ctx, | |||||
| return cbs_read_fragment_content(ctx, frag); | return cbs_read_fragment_content(ctx, frag); | ||||
| } | } | ||||
| static int cbs_write_unit_data(CodedBitstreamContext *ctx, | |||||
| CodedBitstreamUnit *unit) | |||||
| { | |||||
| PutBitContext pbc; | |||||
| int ret; | |||||
| if (!ctx->write_buffer) { | |||||
| // Initial write buffer size is 1MB. | |||||
| ctx->write_buffer_size = 1024 * 1024; | |||||
| reallocate_and_try_again: | |||||
| ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size); | |||||
| if (ret < 0) { | |||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " | |||||
| "sufficiently large write buffer (last attempt " | |||||
| "%"SIZE_SPECIFIER" bytes).\n", ctx->write_buffer_size); | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size); | |||||
| ret = ctx->codec->write_unit(ctx, unit, &pbc); | |||||
| if (ret < 0) { | |||||
| if (ret == AVERROR(ENOSPC)) { | |||||
| // Overflow. | |||||
| ctx->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| // Write failed for some other reason. | |||||
| return ret; | |||||
| } | |||||
| // Overflow but we didn't notice. | |||||
| av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size); | |||||
| if (put_bits_count(&pbc) % 8) | |||||
| unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; | |||||
| else | |||||
| unit->data_bit_padding = 0; | |||||
| flush_put_bits(&pbc); | |||||
| ret = ff_cbs_alloc_unit_data(ctx, unit, put_bits_count(&pbc) / 8); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| memcpy(unit->data, ctx->write_buffer, unit->data_size); | |||||
| return 0; | |||||
| } | |||||
| int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, | int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamFragment *frag) | CodedBitstreamFragment *frag) | ||||
| @@ -295,7 +349,7 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, | |||||
| av_buffer_unref(&unit->data_ref); | av_buffer_unref(&unit->data_ref); | ||||
| unit->data = NULL; | unit->data = NULL; | ||||
| err = ctx->codec->write_unit(ctx, unit); | |||||
| err = cbs_write_unit_data(ctx, unit); | |||||
| if (err < 0) { | if (err < 0) { | ||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " | av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " | ||||
| "(type %"PRIu32").\n", i, unit->type); | "(type %"PRIu32").\n", i, unit->type); | ||||
| @@ -210,6 +210,13 @@ typedef struct CodedBitstreamContext { | |||||
| * From AV_LOG_*; defaults to AV_LOG_TRACE. | * From AV_LOG_*; defaults to AV_LOG_TRACE. | ||||
| */ | */ | ||||
| int trace_level; | int trace_level; | ||||
| /** | |||||
| * Write buffer. Used as intermediate buffer when writing units. | |||||
| * For internal use of cbs only. | |||||
| */ | |||||
| uint8_t *write_buffer; | |||||
| size_t write_buffer_size; | |||||
| } CodedBitstreamContext; | } CodedBitstreamContext; | ||||
| @@ -1205,66 +1205,19 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, | |||||
| return AVERROR(ENOSPC); | return AVERROR(ENOSPC); | ||||
| if (obu->obu_size > 0) { | if (obu->obu_size > 0) { | ||||
| memmove(priv->write_buffer + data_pos, | |||||
| priv->write_buffer + start_pos, header_size); | |||||
| memmove(pbc->buf + data_pos, | |||||
| pbc->buf + start_pos, header_size); | |||||
| skip_put_bytes(pbc, header_size); | skip_put_bytes(pbc, header_size); | ||||
| if (td) { | if (td) { | ||||
| memcpy(priv->write_buffer + data_pos + header_size, | |||||
| memcpy(pbc->buf + data_pos + header_size, | |||||
| td->data, td->data_size); | td->data, td->data_size); | ||||
| skip_put_bytes(pbc, td->data_size); | skip_put_bytes(pbc, td->data_size); | ||||
| } | } | ||||
| } | } | ||||
| return 0; | |||||
| } | |||||
| static int cbs_av1_write_unit(CodedBitstreamContext *ctx, | |||||
| CodedBitstreamUnit *unit) | |||||
| { | |||||
| CodedBitstreamAV1Context *priv = ctx->priv_data; | |||||
| PutBitContext pbc; | |||||
| int err; | |||||
| if (!priv->write_buffer) { | |||||
| // Initial write buffer size is 1MB. | |||||
| priv->write_buffer_size = 1024 * 1024; | |||||
| reallocate_and_try_again: | |||||
| err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); | |||||
| if (err < 0) { | |||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " | |||||
| "sufficiently large write buffer (last attempt " | |||||
| "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); | |||||
| return err; | |||||
| } | |||||
| } | |||||
| init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); | |||||
| err = cbs_av1_write_obu(ctx, unit, &pbc); | |||||
| if (err == AVERROR(ENOSPC)) { | |||||
| // Overflow. | |||||
| priv->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| if (err < 0) | |||||
| return err; | |||||
| // Overflow but we didn't notice. | |||||
| av_assert0(put_bits_count(&pbc) <= 8 * priv->write_buffer_size); | |||||
| // OBU data must be byte-aligned. | // OBU data must be byte-aligned. | ||||
| av_assert0(put_bits_count(&pbc) % 8 == 0); | |||||
| unit->data_size = put_bits_count(&pbc) / 8; | |||||
| flush_put_bits(&pbc); | |||||
| err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); | |||||
| if (err < 0) | |||||
| return err; | |||||
| memcpy(unit->data, priv->write_buffer, unit->data_size); | |||||
| av_assert0(put_bits_count(pbc) % 8 == 0); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -1303,8 +1256,6 @@ static void cbs_av1_close(CodedBitstreamContext *ctx) | |||||
| av_buffer_unref(&priv->sequence_header_ref); | av_buffer_unref(&priv->sequence_header_ref); | ||||
| av_buffer_unref(&priv->frame_header_ref); | av_buffer_unref(&priv->frame_header_ref); | ||||
| av_freep(&priv->write_buffer); | |||||
| } | } | ||||
| const CodedBitstreamType ff_cbs_type_av1 = { | const CodedBitstreamType ff_cbs_type_av1 = { | ||||
| @@ -1314,7 +1265,7 @@ const CodedBitstreamType ff_cbs_type_av1 = { | |||||
| .split_fragment = &cbs_av1_split_fragment, | .split_fragment = &cbs_av1_split_fragment, | ||||
| .read_unit = &cbs_av1_read_unit, | .read_unit = &cbs_av1_read_unit, | ||||
| .write_unit = &cbs_av1_write_unit, | |||||
| .write_unit = &cbs_av1_write_obu, | |||||
| .assemble_fragment = &cbs_av1_assemble_fragment, | .assemble_fragment = &cbs_av1_assemble_fragment, | ||||
| .close = &cbs_av1_close, | .close = &cbs_av1_close, | ||||
| @@ -444,10 +444,6 @@ typedef struct CodedBitstreamAV1Context { | |||||
| AV1ReferenceFrameState *ref; | AV1ReferenceFrameState *ref; | ||||
| AV1ReferenceFrameState read_ref[AV1_NUM_REF_FRAMES]; | AV1ReferenceFrameState read_ref[AV1_NUM_REF_FRAMES]; | ||||
| AV1ReferenceFrameState write_ref[AV1_NUM_REF_FRAMES]; | AV1ReferenceFrameState write_ref[AV1_NUM_REF_FRAMES]; | ||||
| // Write buffer. | |||||
| uint8_t *write_buffer; | |||||
| size_t write_buffer_size; | |||||
| } CodedBitstreamAV1Context; | } CodedBitstreamAV1Context; | ||||
| @@ -1380,65 +1380,6 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int cbs_h2645_write_nal_unit(CodedBitstreamContext *ctx, | |||||
| CodedBitstreamUnit *unit) | |||||
| { | |||||
| CodedBitstreamH2645Context *priv = ctx->priv_data; | |||||
| enum AVCodecID codec_id = ctx->codec->codec_id; | |||||
| PutBitContext pbc; | |||||
| int err; | |||||
| if (!priv->write_buffer) { | |||||
| // Initial write buffer size is 1MB. | |||||
| priv->write_buffer_size = 1024 * 1024; | |||||
| reallocate_and_try_again: | |||||
| err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); | |||||
| if (err < 0) { | |||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " | |||||
| "sufficiently large write buffer (last attempt " | |||||
| "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); | |||||
| return err; | |||||
| } | |||||
| } | |||||
| init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); | |||||
| if (codec_id == AV_CODEC_ID_H264) | |||||
| err = cbs_h264_write_nal_unit(ctx, unit, &pbc); | |||||
| else | |||||
| err = cbs_h265_write_nal_unit(ctx, unit, &pbc); | |||||
| if (err == AVERROR(ENOSPC)) { | |||||
| // Overflow. | |||||
| priv->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| // Overflow but we didn't notice. | |||||
| av_assert0(put_bits_count(&pbc) <= 8 * priv->write_buffer_size); | |||||
| if (err < 0) { | |||||
| // Write failed for some other reason. | |||||
| return err; | |||||
| } | |||||
| if (put_bits_count(&pbc) % 8) | |||||
| unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; | |||||
| else | |||||
| unit->data_bit_padding = 0; | |||||
| unit->data_size = (put_bits_count(&pbc) + 7) / 8; | |||||
| flush_put_bits(&pbc); | |||||
| err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); | |||||
| if (err < 0) | |||||
| return err; | |||||
| memcpy(unit->data, priv->write_buffer, unit->data_size); | |||||
| return 0; | |||||
| } | |||||
| static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, | static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamFragment *frag) | CodedBitstreamFragment *frag) | ||||
| { | { | ||||
| @@ -1533,8 +1474,6 @@ static void cbs_h264_close(CodedBitstreamContext *ctx) | |||||
| ff_h2645_packet_uninit(&h264->common.read_packet); | ff_h2645_packet_uninit(&h264->common.read_packet); | ||||
| av_freep(&h264->common.write_buffer); | |||||
| for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) | for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) | ||||
| av_buffer_unref(&h264->sps_ref[i]); | av_buffer_unref(&h264->sps_ref[i]); | ||||
| for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) | for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) | ||||
| @@ -1548,8 +1487,6 @@ static void cbs_h265_close(CodedBitstreamContext *ctx) | |||||
| ff_h2645_packet_uninit(&h265->common.read_packet); | ff_h2645_packet_uninit(&h265->common.read_packet); | ||||
| av_freep(&h265->common.write_buffer); | |||||
| for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) | for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) | ||||
| av_buffer_unref(&h265->vps_ref[i]); | av_buffer_unref(&h265->vps_ref[i]); | ||||
| for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) | for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) | ||||
| @@ -1565,7 +1502,7 @@ const CodedBitstreamType ff_cbs_type_h264 = { | |||||
| .split_fragment = &cbs_h2645_split_fragment, | .split_fragment = &cbs_h2645_split_fragment, | ||||
| .read_unit = &cbs_h264_read_nal_unit, | .read_unit = &cbs_h264_read_nal_unit, | ||||
| .write_unit = &cbs_h2645_write_nal_unit, | |||||
| .write_unit = &cbs_h264_write_nal_unit, | |||||
| .assemble_fragment = &cbs_h2645_assemble_fragment, | .assemble_fragment = &cbs_h2645_assemble_fragment, | ||||
| .close = &cbs_h264_close, | .close = &cbs_h264_close, | ||||
| @@ -1578,7 +1515,7 @@ const CodedBitstreamType ff_cbs_type_h265 = { | |||||
| .split_fragment = &cbs_h2645_split_fragment, | .split_fragment = &cbs_h2645_split_fragment, | ||||
| .read_unit = &cbs_h265_read_nal_unit, | .read_unit = &cbs_h265_read_nal_unit, | ||||
| .write_unit = &cbs_h2645_write_nal_unit, | |||||
| .write_unit = &cbs_h265_write_nal_unit, | |||||
| .assemble_fragment = &cbs_h2645_assemble_fragment, | .assemble_fragment = &cbs_h2645_assemble_fragment, | ||||
| .close = &cbs_h265_close, | .close = &cbs_h265_close, | ||||
| @@ -19,9 +19,6 @@ | |||||
| #ifndef AVCODEC_CBS_H2645_H | #ifndef AVCODEC_CBS_H2645_H | ||||
| #define AVCODEC_CBS_H2645_H | #define AVCODEC_CBS_H2645_H | ||||
| #include <stddef.h> | |||||
| #include <stdint.h> | |||||
| #include "h2645_parse.h" | #include "h2645_parse.h" | ||||
| @@ -33,10 +30,6 @@ typedef struct CodedBitstreamH2645Context { | |||||
| int nal_length_size; | int nal_length_size; | ||||
| // Packet reader. | // Packet reader. | ||||
| H2645Packet read_packet; | H2645Packet read_packet; | ||||
| // Write buffer | |||||
| uint8_t *write_buffer; | |||||
| size_t write_buffer_size; | |||||
| } CodedBitstreamH2645Context; | } CodedBitstreamH2645Context; | ||||
| @@ -44,9 +44,11 @@ typedef struct CodedBitstreamType { | |||||
| int (*read_unit)(CodedBitstreamContext *ctx, | int (*read_unit)(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamUnit *unit); | CodedBitstreamUnit *unit); | ||||
| // Write the unit->data bitstream from unit->content. | |||||
| // Write the data bitstream from unit->content into pbc. | |||||
| // Return value AVERROR(ENOSPC) indicates that pbc was too small. | |||||
| int (*write_unit)(CodedBitstreamContext *ctx, | int (*write_unit)(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamUnit *unit); | |||||
| CodedBitstreamUnit *unit, | |||||
| PutBitContext *pbc); | |||||
| // Read the data from all of frag->units and assemble it into | // Read the data from all of frag->units and assemble it into | ||||
| // a bitstream for the whole fragment. | // a bitstream for the whole fragment. | ||||
| @@ -377,58 +377,13 @@ static int cbs_jpeg_write_segment(CodedBitstreamContext *ctx, | |||||
| } | } | ||||
| static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, | static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamUnit *unit) | |||||
| CodedBitstreamUnit *unit, | |||||
| PutBitContext *pbc) | |||||
| { | { | ||||
| CodedBitstreamJPEGContext *priv = ctx->priv_data; | |||||
| PutBitContext pbc; | |||||
| int err; | |||||
| if (!priv->write_buffer) { | |||||
| // Initial write buffer size is 1MB. | |||||
| priv->write_buffer_size = 1024 * 1024; | |||||
| reallocate_and_try_again: | |||||
| err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); | |||||
| if (err < 0) { | |||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " | |||||
| "sufficiently large write buffer (last attempt " | |||||
| "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); | |||||
| return err; | |||||
| } | |||||
| } | |||||
| init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); | |||||
| if (unit->type == JPEG_MARKER_SOS) | if (unit->type == JPEG_MARKER_SOS) | ||||
| err = cbs_jpeg_write_scan(ctx, unit, &pbc); | |||||
| else | |||||
| err = cbs_jpeg_write_segment(ctx, unit, &pbc); | |||||
| if (err == AVERROR(ENOSPC)) { | |||||
| // Overflow. | |||||
| priv->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| if (err < 0) { | |||||
| // Write failed for some other reason. | |||||
| return err; | |||||
| } | |||||
| if (put_bits_count(&pbc) % 8) | |||||
| unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; | |||||
| return cbs_jpeg_write_scan (ctx, unit, pbc); | |||||
| else | else | ||||
| unit->data_bit_padding = 0; | |||||
| unit->data_size = (put_bits_count(&pbc) + 7) / 8; | |||||
| flush_put_bits(&pbc); | |||||
| err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); | |||||
| if (err < 0) | |||||
| return err; | |||||
| memcpy(unit->data, priv->write_buffer, unit->data_size); | |||||
| return 0; | |||||
| return cbs_jpeg_write_segment(ctx, unit, pbc); | |||||
| } | } | ||||
| static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, | static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, | ||||
| @@ -499,22 +454,11 @@ static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static void cbs_jpeg_close(CodedBitstreamContext *ctx) | |||||
| { | |||||
| CodedBitstreamJPEGContext *priv = ctx->priv_data; | |||||
| av_freep(&priv->write_buffer); | |||||
| } | |||||
| const CodedBitstreamType ff_cbs_type_jpeg = { | const CodedBitstreamType ff_cbs_type_jpeg = { | ||||
| .codec_id = AV_CODEC_ID_MJPEG, | .codec_id = AV_CODEC_ID_MJPEG, | ||||
| .priv_data_size = sizeof(CodedBitstreamJPEGContext), | |||||
| .split_fragment = &cbs_jpeg_split_fragment, | .split_fragment = &cbs_jpeg_split_fragment, | ||||
| .read_unit = &cbs_jpeg_read_unit, | .read_unit = &cbs_jpeg_read_unit, | ||||
| .write_unit = &cbs_jpeg_write_unit, | .write_unit = &cbs_jpeg_write_unit, | ||||
| .assemble_fragment = &cbs_jpeg_assemble_fragment, | .assemble_fragment = &cbs_jpeg_assemble_fragment, | ||||
| .close = &cbs_jpeg_close, | |||||
| }; | }; | ||||
| @@ -120,11 +120,4 @@ typedef struct JPEGRawComment { | |||||
| } JPEGRawComment; | } JPEGRawComment; | ||||
| typedef struct CodedBitstreamJPEGContext { | |||||
| // Write buffer. | |||||
| uint8_t *write_buffer; | |||||
| size_t write_buffer_size; | |||||
| } CodedBitstreamJPEGContext; | |||||
| #endif /* AVCODEC_CBS_JPEG_H */ | #endif /* AVCODEC_CBS_JPEG_H */ | ||||
| @@ -335,58 +335,13 @@ static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, | |||||
| } | } | ||||
| static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, | static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamUnit *unit) | |||||
| CodedBitstreamUnit *unit, | |||||
| PutBitContext *pbc) | |||||
| { | { | ||||
| CodedBitstreamMPEG2Context *priv = ctx->priv_data; | |||||
| PutBitContext pbc; | |||||
| int err; | |||||
| if (!priv->write_buffer) { | |||||
| // Initial write buffer size is 1MB. | |||||
| priv->write_buffer_size = 1024 * 1024; | |||||
| reallocate_and_try_again: | |||||
| err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); | |||||
| if (err < 0) { | |||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " | |||||
| "sufficiently large write buffer (last attempt " | |||||
| "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); | |||||
| return err; | |||||
| } | |||||
| } | |||||
| init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); | |||||
| if (MPEG2_START_IS_SLICE(unit->type)) | if (MPEG2_START_IS_SLICE(unit->type)) | ||||
| err = cbs_mpeg2_write_slice(ctx, unit, &pbc); | |||||
| else | |||||
| err = cbs_mpeg2_write_header(ctx, unit, &pbc); | |||||
| if (err == AVERROR(ENOSPC)) { | |||||
| // Overflow. | |||||
| priv->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| if (err < 0) { | |||||
| // Write failed for some other reason. | |||||
| return err; | |||||
| } | |||||
| if (put_bits_count(&pbc) % 8) | |||||
| unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; | |||||
| return cbs_mpeg2_write_slice (ctx, unit, pbc); | |||||
| else | else | ||||
| unit->data_bit_padding = 0; | |||||
| unit->data_size = (put_bits_count(&pbc) + 7) / 8; | |||||
| flush_put_bits(&pbc); | |||||
| err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); | |||||
| if (err < 0) | |||||
| return err; | |||||
| memcpy(unit->data, priv->write_buffer, unit->data_size); | |||||
| return 0; | |||||
| return cbs_mpeg2_write_header(ctx, unit, pbc); | |||||
| } | } | ||||
| static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, | static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, | ||||
| @@ -426,13 +381,6 @@ static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static void cbs_mpeg2_close(CodedBitstreamContext *ctx) | |||||
| { | |||||
| CodedBitstreamMPEG2Context *priv = ctx->priv_data; | |||||
| av_freep(&priv->write_buffer); | |||||
| } | |||||
| const CodedBitstreamType ff_cbs_type_mpeg2 = { | const CodedBitstreamType ff_cbs_type_mpeg2 = { | ||||
| .codec_id = AV_CODEC_ID_MPEG2VIDEO, | .codec_id = AV_CODEC_ID_MPEG2VIDEO, | ||||
| @@ -442,6 +390,4 @@ const CodedBitstreamType ff_cbs_type_mpeg2 = { | |||||
| .read_unit = &cbs_mpeg2_read_unit, | .read_unit = &cbs_mpeg2_read_unit, | ||||
| .write_unit = &cbs_mpeg2_write_unit, | .write_unit = &cbs_mpeg2_write_unit, | ||||
| .assemble_fragment = &cbs_mpeg2_assemble_fragment, | .assemble_fragment = &cbs_mpeg2_assemble_fragment, | ||||
| .close = &cbs_mpeg2_close, | |||||
| }; | }; | ||||
| @@ -219,10 +219,6 @@ typedef struct CodedBitstreamMPEG2Context { | |||||
| uint8_t scalable_mode; | uint8_t scalable_mode; | ||||
| uint8_t progressive_sequence; | uint8_t progressive_sequence; | ||||
| uint8_t number_of_frame_centre_offsets; | uint8_t number_of_frame_centre_offsets; | ||||
| // Write buffer. | |||||
| uint8_t *write_buffer; | |||||
| size_t write_buffer_size; | |||||
| } CodedBitstreamMPEG2Context; | } CodedBitstreamMPEG2Context; | ||||
| @@ -528,62 +528,28 @@ static int cbs_vp9_read_unit(CodedBitstreamContext *ctx, | |||||
| } | } | ||||
| static int cbs_vp9_write_unit(CodedBitstreamContext *ctx, | static int cbs_vp9_write_unit(CodedBitstreamContext *ctx, | ||||
| CodedBitstreamUnit *unit) | |||||
| CodedBitstreamUnit *unit, | |||||
| PutBitContext *pbc) | |||||
| { | { | ||||
| CodedBitstreamVP9Context *priv = ctx->priv_data; | |||||
| VP9RawFrame *frame = unit->content; | VP9RawFrame *frame = unit->content; | ||||
| PutBitContext pbc; | |||||
| int err; | int err; | ||||
| if (!priv->write_buffer) { | |||||
| // Initial write buffer size is 1MB. | |||||
| priv->write_buffer_size = 1024 * 1024; | |||||
| reallocate_and_try_again: | |||||
| err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); | |||||
| if (err < 0) { | |||||
| av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " | |||||
| "sufficiently large write buffer (last attempt " | |||||
| "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); | |||||
| return err; | |||||
| } | |||||
| } | |||||
| init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); | |||||
| err = cbs_vp9_write_frame(ctx, &pbc, frame); | |||||
| if (err == AVERROR(ENOSPC)) { | |||||
| priv->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| err = cbs_vp9_write_frame(ctx, pbc, frame); | |||||
| if (err < 0) | if (err < 0) | ||||
| return err; | return err; | ||||
| // Frame must be byte-aligned. | // Frame must be byte-aligned. | ||||
| av_assert0(put_bits_count(&pbc) % 8 == 0); | |||||
| unit->data_size = put_bits_count(&pbc) / 8; | |||||
| unit->data_bit_padding = 0; | |||||
| flush_put_bits(&pbc); | |||||
| av_assert0(put_bits_count(pbc) % 8 == 0); | |||||
| if (frame->data) { | if (frame->data) { | ||||
| if (unit->data_size + frame->data_size > | |||||
| priv->write_buffer_size) { | |||||
| priv->write_buffer_size *= 2; | |||||
| goto reallocate_and_try_again; | |||||
| } | |||||
| if (frame->data_size > put_bits_left(pbc) / 8) | |||||
| return AVERROR(ENOSPC); | |||||
| memcpy(priv->write_buffer + unit->data_size, | |||||
| frame->data, frame->data_size); | |||||
| unit->data_size += frame->data_size; | |||||
| flush_put_bits(pbc); | |||||
| memcpy(put_bits_ptr(pbc), frame->data, frame->data_size); | |||||
| skip_put_bytes(pbc, frame->data_size); | |||||
| } | } | ||||
| err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); | |||||
| if (err < 0) | |||||
| return err; | |||||
| memcpy(unit->data, priv->write_buffer, unit->data_size); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -677,13 +643,6 @@ static int cbs_vp9_assemble_fragment(CodedBitstreamContext *ctx, | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static void cbs_vp9_close(CodedBitstreamContext *ctx) | |||||
| { | |||||
| CodedBitstreamVP9Context *priv = ctx->priv_data; | |||||
| av_freep(&priv->write_buffer); | |||||
| } | |||||
| const CodedBitstreamType ff_cbs_type_vp9 = { | const CodedBitstreamType ff_cbs_type_vp9 = { | ||||
| .codec_id = AV_CODEC_ID_VP9, | .codec_id = AV_CODEC_ID_VP9, | ||||
| @@ -693,6 +652,4 @@ const CodedBitstreamType ff_cbs_type_vp9 = { | |||||
| .read_unit = &cbs_vp9_read_unit, | .read_unit = &cbs_vp9_read_unit, | ||||
| .write_unit = &cbs_vp9_write_unit, | .write_unit = &cbs_vp9_write_unit, | ||||
| .assemble_fragment = &cbs_vp9_assemble_fragment, | .assemble_fragment = &cbs_vp9_assemble_fragment, | ||||
| .close = &cbs_vp9_close, | |||||
| }; | }; | ||||
| @@ -207,10 +207,6 @@ typedef struct CodedBitstreamVP9Context { | |||||
| int bit_depth; | int bit_depth; | ||||
| VP9ReferenceFrameState ref[VP9_NUM_REF_FRAMES]; | VP9ReferenceFrameState ref[VP9_NUM_REF_FRAMES]; | ||||
| // Write buffer. | |||||
| uint8_t *write_buffer; | |||||
| size_t write_buffer_size; | |||||
| } CodedBitstreamVP9Context; | } CodedBitstreamVP9Context; | ||||