diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index e55bd00183..53d9bfed79 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -1050,6 +1050,64 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, return 0; } +static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, + PutBitContext *pbc, const uint8_t *data, + size_t data_size, int data_bit_start) +{ + size_t rest = data_size - (data_bit_start + 7) / 8; + const uint8_t *pos = data + data_bit_start / 8; + + av_assert0(data_bit_start >= 0 && + 8 * data_size > data_bit_start); + + if (data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + if (!rest) + goto rbsp_stop_one_bit; + + // First copy the remaining bits of the first byte + // The above check ensures that we do not accidentally + // copy beyond the rbsp_stop_one_bit. + if (data_bit_start % 8) + put_bits(pbc, 8 - data_bit_start % 8, + *pos++ & MAX_UINT_BITS(8 - data_bit_start % 8)); + + if (put_bits_count(pbc) % 8 == 0) { + // If the writer is aligned at this point, + // memcpy can be used to improve performance. + // This happens normally for CABAC. + flush_put_bits(pbc); + memcpy(put_bits_ptr(pbc), pos, rest); + skip_put_bytes(pbc, rest); + } else { + // If not, we have to copy manually. + // rbsp_stop_one_bit forces us to special-case + // the last byte. + uint8_t temp; + int i; + + for (; rest > 4; rest -= 4, pos += 4) + put_bits32(pbc, AV_RB32(pos)); + + for (; rest > 1; rest--, pos++) + put_bits(pbc, 8, *pos); + + rbsp_stop_one_bit: + temp = rest ? *pos : *pos & MAX_UINT_BITS(8 - data_bit_start % 8); + + av_assert0(temp); + i = ff_ctz(*pos); + temp = temp >> i; + i = rest ? (8 - i) : (8 - i - data_bit_start % 8); + put_bits(pbc, i, temp); + if (put_bits_count(pbc) % 8) + put_bits(pbc, 8 - put_bits_count(pbc) % 8, 0); + } + + return 0; +} + static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc) @@ -1100,37 +1158,17 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, case H264_NAL_AUXILIARY_SLICE: { H264RawSlice *slice = unit->content; - GetBitContext gbc; - int bits_left, end, zeroes; err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); if (err < 0) return err; if (slice->data) { - if (slice->data_size * 8 + 8 > put_bits_left(pbc)) - return AVERROR(ENOSPC); - - init_get_bits(&gbc, slice->data, slice->data_size * 8); - skip_bits_long(&gbc, slice->data_bit_start); - - // Copy in two-byte blocks, but stop before copying the - // rbsp_stop_one_bit in the final byte. - while (get_bits_left(&gbc) > 23) - put_bits(pbc, 16, get_bits(&gbc, 16)); - - bits_left = get_bits_left(&gbc); - end = get_bits(&gbc, bits_left); - - // rbsp_stop_one_bit must be present here. - av_assert0(end); - zeroes = ff_ctz(end); - if (bits_left > zeroes + 1) - put_bits(pbc, bits_left - zeroes - 1, - end >> (zeroes + 1)); - put_bits(pbc, 1, 1); - while (put_bits_count(pbc) % 8 != 0) - put_bits(pbc, 1, 0); + err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; } else { // No slice data - that was just the header. // (Bitstream may be unaligned!) @@ -1254,37 +1292,17 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, case HEVC_NAL_CRA_NUT: { H265RawSlice *slice = unit->content; - GetBitContext gbc; - int bits_left, end, zeroes; err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); if (err < 0) return err; if (slice->data) { - if (slice->data_size * 8 + 8 > put_bits_left(pbc)) - return AVERROR(ENOSPC); - - init_get_bits(&gbc, slice->data, slice->data_size * 8); - skip_bits_long(&gbc, slice->data_bit_start); - - // Copy in two-byte blocks, but stop before copying the - // rbsp_stop_one_bit in the final byte. - while (get_bits_left(&gbc) > 23) - put_bits(pbc, 16, get_bits(&gbc, 16)); - - bits_left = get_bits_left(&gbc); - end = get_bits(&gbc, bits_left); - - // rbsp_stop_one_bit must be present here. - av_assert0(end); - zeroes = ff_ctz(end); - if (bits_left > zeroes + 1) - put_bits(pbc, bits_left - zeroes - 1, - end >> (zeroes + 1)); - put_bits(pbc, 1, 1); - while (put_bits_count(pbc) % 8 != 0) - put_bits(pbc, 1, 0); + err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; } else { // No slice data - that was just the header. }