@@ -283,6 +283,28 @@ int ff_cbs_read(CodedBitstreamContext *ctx,
return cbs_read_fragment_content(ctx, frag);
}
+int ff_cbs_default_write_unit_data(CodedBitstreamContext *ctx,
+ CodedBitstreamUnit *unit,
+ PutBitContext *pbc)
+{
+ int err;
+
+ 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);
+
+ err = ff_cbs_alloc_unit_data(ctx, unit, put_bits_count(pbc) / 8);
+ if (err < 0)
+ return err;
+
+ memcpy(unit->data, pbc->buf, unit->data_size);
+
+ return 0;
+}
+
static int cbs_write_unit_data(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit)
{
@@ -318,22 +340,6 @@ static int cbs_write_unit_data(CodedBitstreamContext *ctx,
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;
}
@@ -1217,7 +1217,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
// OBU data must be byte-aligned.
av_assert0(put_bits_count(pbc) % 8 == 0);
- return 0;
+ return ff_cbs_default_write_unit_data(ctx, unit, pbc);
}
static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx,
@@ -1265,7 +1265,7 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx,
return AVERROR_PATCHWELCOME;
}
- return 0;
+ return ff_cbs_default_write_unit_data(ctx, unit, pbc);
}
static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx,
@@ -1377,7 +1377,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx,
return AVERROR_PATCHWELCOME;
}
- return 0;
+ return ff_cbs_default_write_unit_data(ctx, unit, pbc);
}
static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx,
@@ -44,7 +44,9 @@ typedef struct CodedBitstreamType {
int (*read_unit)(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit);
- // Write the data bitstream from unit->content into pbc.
+ // Write the data bitstream from unit->content. This includes
+ // allocating the buffer as well as setting all of unit's data-fields.
+ // The supplied PutBitContext may be used as temporary buffer.
// Return value AVERROR(ENOSPC) indicates that pbc was too small.
int (*write_unit)(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit,
@@ -60,6 +62,14 @@ typedef struct CodedBitstreamType {
} CodedBitstreamType;
+// Helper function to convert pbc's content into a unit's data.
+// Allocates and copies data and sets all of unit's data-fields.
+
+int ff_cbs_default_write_unit_data(CodedBitstreamContext *ctx,
+ CodedBitstreamUnit *unit,
+ PutBitContext *pbc);
+
+
// Helper functions for trace output.
void ff_cbs_trace_header(CodedBitstreamContext *ctx,
@@ -384,10 +384,16 @@ static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit,
PutBitContext *pbc)
{
+ int err;
+
if (unit->type == JPEG_MARKER_SOS)
- return cbs_jpeg_write_scan (ctx, unit, pbc);
+ err = cbs_jpeg_write_scan (ctx, unit, pbc);
else
- return cbs_jpeg_write_segment(ctx, unit, pbc);
+ err = cbs_jpeg_write_segment(ctx, unit, pbc);
+ if (err < 0)
+ return err;
+
+ return ff_cbs_default_write_unit_data(ctx, unit, pbc);
}
static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx,
@@ -374,10 +374,16 @@ static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit,
PutBitContext *pbc)
{
+ int err;
+
if (MPEG2_START_IS_SLICE(unit->type))
- return cbs_mpeg2_write_slice (ctx, unit, pbc);
+ err = cbs_mpeg2_write_slice (ctx, unit, pbc);
else
- return cbs_mpeg2_write_header(ctx, unit, pbc);
+ err = cbs_mpeg2_write_header(ctx, unit, pbc);
+ if (err < 0)
+ return err;
+
+ return ff_cbs_default_write_unit_data(ctx, unit, pbc);
}
static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx,
@@ -544,7 +544,7 @@ static int cbs_vp9_write_unit(CodedBitstreamContext *ctx,
skip_put_bytes(pbc, frame->data_size);
}
- return 0;
+ return ff_cbs_default_write_unit_data(ctx, unit, pbc);
}
static int cbs_vp9_assemble_fragment(CodedBitstreamContext *ctx,
when writing a unit from content. Writing a unit (i.e. assembling it from its decomposed form) currently always uses an intermediate buffer; only after the unit has been completely assembled in this buffer (so that, in particular, the needed size is known), is the final buffer allocated and the data copied. This works well for most types of units except one: The slice/frame units that usually make up the bulk of the whole data. Only their headers are reassembled from content. Their actual data are mostly just copied into the write buffer. Given that the size of the actual data is known, one has a very good estimate on the needed size after having assembled the slice/frame header only. If one allocated the necessary buffer now and directly copied the frame header and frame data into it, one can avoid copying the data into the temporary buffer. This commit lays the groundwork for doing so by moving the data buffer's allocation into the (codec-dependent) write_unit function. It does not avoid copying yet. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com> --- libavcodec/cbs.c | 38 ++++++++++++++++++++++---------------- libavcodec/cbs_av1.c | 2 +- libavcodec/cbs_h2645.c | 4 ++-- libavcodec/cbs_internal.h | 12 +++++++++++- libavcodec/cbs_jpeg.c | 10 ++++++++-- libavcodec/cbs_mpeg2.c | 10 ++++++++-- libavcodec/cbs_vp9.c | 2 +- 7 files changed, 53 insertions(+), 25 deletions(-)