Skip to content

Fix two bugs in parseAV2SequenceHeader()#3137

Merged
wantehchang merged 1 commit intoAOMediaCodec:mainfrom
wantehchang:fix-parse-av2-seq-header
Mar 26, 2026
Merged

Fix two bugs in parseAV2SequenceHeader()#3137
wantehchang merged 1 commit intoAOMediaCodec:mainfrom
wantehchang:fix-parse-av2-seq-header

Conversation

@wantehchang
Copy link
Copy Markdown
Collaborator

Remove an early return of AVIF_FALSE in the
!header->reduced_still_picture_header case.

Save the value of the seq_tier syntax element in header->av1C.seqTier0.

Remove an early return of AVIF_FALSE in the
!header->reduced_still_picture_header case.

Save the value of the seq_tier syntax element in header->av1C.seqTier0.
@wantehchang wantehchang requested a review from y-guyon March 26, 2026 04:10
Comment thread src/obu.c
if (!header->reduced_still_picture_header) {
avifBitsRead(bits, 3); // seq_lcr_id
avifBitsRead(bits, 1); // still_picture
return AVIF_FALSE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vaguely remember this early return was here because the rest of the function was not implemented when reduced_still_picture_header is false. Is this no longer the case? Or maybe the fields have been rearranged in a way that we can skip all the remaining fields because we are only interested in the ones at the beginning of the OBU?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two problems with this return statement.

  1. It skips the rest of the function, leaving several fields in the avifSequenceHeader struct unset
  2. It returns AVIF_FALSE, which indicates failure.

Here is the corresponding code in AVM research-v13.0.0:

  if (seq_params->single_picture_header_flag) {
    seq_params->seq_lcr_id = LCR_ID_UNSPECIFIED;
    seq_params->still_picture = 1;
  } else {
    int seq_lcr_id = avm_rb_read_literal(rb, 3);
    if (seq_lcr_id > MAX_NUM_SEQ_LCR_ID) {
      avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM,
                         "Unsupported LCR id in the Sequence Header.\n");
    }
    seq_params->seq_lcr_id = seq_lcr_id;
    seq_params->still_picture = avm_rb_read_bit(rb);
  }

Note that there is no return statement in the else block.

Copy link
Copy Markdown
Contributor

@y-guyon y-guyon Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two problems with this return statement.

  1. It skips the rest of the function, leaving several fields in the avifSequenceHeader struct unset
  2. It returns AVIF_FALSE, which indicates failure.

With 2., 1. is not a problem.
I think 2. was in fact a lazy "not implemented", due to later code relying on single_picture_header_flag. But these single_picture_header_flag-dependent fields below are all skipped anyway so this PR is fine.

Comment thread src/obu.c
header->av1C.seqLevelIdx0 = (uint8_t)avifBitsRead(bits, 5);
if (header->av1C.seqLevelIdx0 > 7 && !header->reduced_still_picture_header) {
avifBitsRead(bits, 1); // single_tier_0
header->av1C.seqTier0 = avifBitsRead(bits, 1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not sure single_tier_0 is equivalent to seqTier0.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single_tier_0 may have been a typo.

Here is the corresponding code in AVM research-v13.0.0:

  if (seq_params->seq_max_level_idx >= SEQ_LEVEL_4_0 &&
      !seq_params->single_picture_header_flag)
    seq_params->seq_tier = avm_rb_read_bit(rb);
  else
    seq_params->seq_tier = 0;

Note: SEQ_LEVEL_4_0 is equal to 8.

The name of the struct member is seq_tier. The syntax element is also called seq_tier in the draft AV2 spec (v13):

  if ( seq_level_idx > 7 && !single_picture_header_flag ) {	
    seq_tier	                                               f(1)
  } else {	
    seq_tier = 0	
  }

Copy link
Copy Markdown
Collaborator Author

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

Comment thread src/obu.c
if (!header->reduced_still_picture_header) {
avifBitsRead(bits, 3); // seq_lcr_id
avifBitsRead(bits, 1); // still_picture
return AVIF_FALSE;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two problems with this return statement.

  1. It skips the rest of the function, leaving several fields in the avifSequenceHeader struct unset
  2. It returns AVIF_FALSE, which indicates failure.

Here is the corresponding code in AVM research-v13.0.0:

  if (seq_params->single_picture_header_flag) {
    seq_params->seq_lcr_id = LCR_ID_UNSPECIFIED;
    seq_params->still_picture = 1;
  } else {
    int seq_lcr_id = avm_rb_read_literal(rb, 3);
    if (seq_lcr_id > MAX_NUM_SEQ_LCR_ID) {
      avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM,
                         "Unsupported LCR id in the Sequence Header.\n");
    }
    seq_params->seq_lcr_id = seq_lcr_id;
    seq_params->still_picture = avm_rb_read_bit(rb);
  }

Note that there is no return statement in the else block.

Comment thread src/obu.c
header->av1C.seqLevelIdx0 = (uint8_t)avifBitsRead(bits, 5);
if (header->av1C.seqLevelIdx0 > 7 && !header->reduced_still_picture_header) {
avifBitsRead(bits, 1); // single_tier_0
header->av1C.seqTier0 = avifBitsRead(bits, 1);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single_tier_0 may have been a typo.

Here is the corresponding code in AVM research-v13.0.0:

  if (seq_params->seq_max_level_idx >= SEQ_LEVEL_4_0 &&
      !seq_params->single_picture_header_flag)
    seq_params->seq_tier = avm_rb_read_bit(rb);
  else
    seq_params->seq_tier = 0;

Note: SEQ_LEVEL_4_0 is equal to 8.

The name of the struct member is seq_tier. The syntax element is also called seq_tier in the draft AV2 spec (v13):

  if ( seq_level_idx > 7 && !single_picture_header_flag ) {	
    seq_tier	                                               f(1)
  } else {	
    seq_tier = 0	
  }

@wantehchang wantehchang merged commit bd4e948 into AOMediaCodec:main Mar 26, 2026
25 checks passed
@wantehchang wantehchang deleted the fix-parse-av2-seq-header branch March 26, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants