[FFmpeg-devel] [PATCH 2/3] lavc: Add coded bitstream read/write support for AV1
James Almer
jamrial at gmail.com
Mon Sep 10 02:40:36 EEST 2018
On 9/9/2018 7:08 PM, Mark Thompson wrote:
> ---
> Against versions which people might have seen before:
> * Removed all of the vestigial annex B support (not useful, we are going to ensure that AVPackets in FFmpeg never hold annex B data).
> * gm_params subexp parsing made sensible - it doesn't compute the actual gm_params values any more, but the code actually makes sense rather than being opaque pasta from the standard.
> * Metadata support added.
> * Tile-group / tile-info / frame-with-tiles OBUs are combined in a hopefully better way.
> * Miscellaneous small fixes.
>
> Thanks to James Almer for testing and various fixes incorporated into this.
>
>
> configure | 2 +
> libavcodec/Makefile | 1 +
> libavcodec/av1.h | 88 ++
> libavcodec/cbs.c | 6 +
> libavcodec/cbs_av1.c | 1293 ++++++++++++++++++++
> libavcodec/cbs_av1.h | 429 +++++++
> libavcodec/cbs_av1_syntax_template.c | 1676 ++++++++++++++++++++++++++
> libavcodec/cbs_internal.h | 1 +
> 8 files changed, 3496 insertions(+)
> create mode 100644 libavcodec/cbs_av1.c
> create mode 100644 libavcodec/cbs_av1.h
> create mode 100644 libavcodec/cbs_av1_syntax_template.c
[...]
> +static int cbs_av1_split_fragment(CodedBitstreamContext *ctx,
> + CodedBitstreamFragment *frag,
> + int header)
> +{
> + GetBitContext gbc;
> + uint8_t *data;
> + size_t size;
> + uint64_t obu_length;
> + int pos, err;
> +
> + data = frag->data;
> + size = frag->data_size;
> +
> + while (size > 0) {
> + AV1RawOBUHeader header;
> + uint64_t obu_size;
> +
> + init_get_bits(&gbc, data, 8 * size);
> +
> + err = cbs_av1_read_obu_header(ctx, &gbc, &header);
This is generating a lot of noise when using the trace_headers bsf.
Basically printing the header fields twice per OBU, first when
splitting, then again when decomposing.
You can get rid of that and simplify this function a lot if you use the
ff_av1_packet_split() API from av1_parse.h doing more or less the same
to what you're doing for h2645:
static int cbs_av1_split_fragment(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag,
int header)
{
CodedBitstreamAV1Context *priv = ctx->priv_data;
int err;
err = ff_av1_packet_split(&priv->read_packet,
frag->data, frag->data_size,
ctx->log_ctx);
if (err < 0)
return err;
for (int i = 0; i < priv->read_packet.nb_obus; i++) {
const AV1OBU *obu = &priv->read_packet.obus[i];
uint8_t *data = (uint8_t *)obu->raw_data;
size_t size = obu->raw_size;
err = ff_cbs_insert_unit_data(ctx, frag, -1, obu->type,
data, size, frag->data_ref);
if (err < 0)
return err;
}
return 0;
}
[...]
> +static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw,
> + AV1RawFrameHeader *current)
> +{
> + CodedBitstreamAV1Context *priv = ctx->priv_data;
> + const AV1RawSequenceHeader *seq;
> + int id_len, all_frames, frame_is_intra, order_hint_bits;
> + int i, err;
> +
> + if (!priv->sequence_header) {
> + av_log(ctx->log_ctx, AV_LOG_ERROR, "No sequence header available: "
> + "unable to decode frame header.\n");
> + return AVERROR_INVALIDDATA;
> + }
> + seq = priv->sequence_header;
> +
> + id_len = seq->additional_frame_id_length_minus_1 +
> + seq->delta_frame_id_length_minus_2 + 3;
> + all_frames = (1 << AV1_NUM_REF_FRAMES) - 1;
> +
> + if (seq->reduced_still_picture_header) {
> + infer(show_existing_frame, 0);
> + infer(frame_type, AV1_FRAME_KEY);
> + infer(show_frame, 1);
> + infer(showable_frame, 0);
> + frame_is_intra = 1;
> +
> + } else {
> + flag(show_existing_frame);
> +
> + if (current->show_existing_frame) {
> + AV1ReferenceFrameState *frame;
> +
> + fb(3, frame_to_show_map_idx);
> + frame = &priv->ref[current->frame_to_show_map_idx];
> +
> + if (seq->decoder_model_info_present_flag &&
> + !seq->timing_info.equal_picture_interval) {
> + fb(seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1,
> + frame_presentation_time);
> + }
> +
> + if (seq->frame_id_numbers_present_flag)
> + fb(id_len, display_frame_id);
> +
> + if (frame->frame_type == AV1_FRAME_KEY)
> + infer(refresh_frame_flags, all_frames);
> + else
> + infer(refresh_frame_flags, 0);
> +
> + return 0;
> + }
> +
> + fb(2, frame_type);
> + frame_is_intra = (current->frame_type == AV1_FRAME_INTRA_ONLY ||
> + current->frame_type == AV1_FRAME_KEY);
> +
> + flag(show_frame);
> + if (current->show_frame &&
> + seq->decoder_model_info_present_flag &&
> + !seq->timing_info.equal_picture_interval) {
> + fb(seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1,
> + frame_presentation_time);
> + }
> + if (current->show_frame)
> + infer(showable_frame, current->frame_type != AV1_FRAME_KEY);
> + else
> + flag(showable_frame);
> +
> + if (current->frame_type == AV1_FRAME_SWITCH ||
> + (current->frame_type == AV1_FRAME_KEY && current->show_frame))
> + infer(error_resilient_mode, 1);
> + else
> + flag(error_resilient_mode);
> + }
> +
> + if (current->frame_type == AV1_FRAME_KEY && current->show_frame) {
> + for (i = 0; i < AV1_NUM_REF_FRAMES; i++) {
> + priv->ref[i].valid = 0;
> + priv->ref[i].order_hint = 0;
> + }
> + }
> +
> + flag(disable_cdf_update);
> +
> + if (seq->seq_force_screen_content_tools ==
> + AV1_SELECT_SCREEN_CONTENT_TOOLS) {
> + flag(allow_screen_content_tools);
> + } else {
> + infer(allow_screen_content_tools,
> + seq->seq_force_screen_content_tools);
> + }
> + if (current->allow_screen_content_tools) {
> + if (seq->seq_force_integer_mv == AV1_SELECT_INTEGER_MV)
> + flag(force_integer_mv);
> + else
> + infer(force_integer_mv, seq->seq_force_integer_mv);
> + } else {
> + infer(force_integer_mv, 0);
> + }
> +
> + if (seq->frame_id_numbers_present_flag)
> + fb(id_len, current_frame_id);
At this point you should call a mark_ref_frames() function that compares
current_frame_id with that of reference frames, which can result in any
of those references set as invalid.
Looks good otherwise. Couldn't find other issues after a quick glance,
and it works with all the samples i tried. Great work!
More information about the ffmpeg-devel
mailing list