Skip to content

Handling of rbsp_trailing_bits is not robust #106

@DCNick3

Description

@DCNick3

The H.264 spec defines rbsp_trailing_bits to be:

rbsp_trailing_bits( ) {
    rbsp_stop_one_bit /* equal to 1 */
    while( !byte_aligned( ) )
        rbsp_alignment_zero_bit /* equal to 0 */
}

In h264-reader this syntactic element is handled by the finish_rbsp function:

fn finish_rbsp(mut self) -> Result<(), BitReaderError> {
    // The next bit is expected to be the final one bit.
    if !self
        .reader
        .read_bit()
        .map_err(|e| BitReaderError::ReaderErrorFor("finish", e))?
    {
        // It was a zero! Determine if we're past the end or haven't reached it yet.
        match self.reader.read_unary1() {
            Err(e) => return Err(BitReaderError::ReaderErrorFor("finish", e)),
            Ok(_) => return Err(BitReaderError::RemainingData),
        }
    }
    // All remaining bits in the stream must then be zeros.
    match self.reader.read_unary1() {
        Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => Ok(()),
        Err(e) => Err(BitReaderError::ReaderErrorFor("finish", e)),
        Ok(_) => Err(BitReaderError::RemainingData),
    }
}

This function expects that SPS does not have any trailing data at the end and will crash with RemainingData if this is the case. The spec doesn't seem to mandate that this is the case though, and other decoder implementations, like ffmpeg will follow it and only consume zero bits up until the byte boundary, ignoring the rest.

Here's a file from ffmpeg's test suite that will fail to parse with h264-reader, but will otherwise play fine in libavcodec-based programs crew_cif.h264.zip. It has two extra bytes in the SPS: "\x00\x0a"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions