This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit cad555d0a49155252eac0c57fe1c4733eb6adbf6 Author: Ramiro Polla <[email protected]> AuthorDate: Fri Sep 19 16:53:49 2025 +0200 Commit: Ramiro Polla <[email protected]> CommitDate: Fri Feb 20 16:32:10 2026 +0100 avcodec/mjpegdec: improve unescaping of SOS fields For non-jpegls: Changes the behaviour to be more in line with IJG's reference implementation: - optional 0xFF fill bytes in a stuffed zero byte sequence (which is an invalid pattern according to the standard) are now discarded: "FF (FF)? 00" => "FF" instead of "FF 00" - sequences with optional 0xFF fill bytes and a marker are no longer copied: "FF (FF)? XX" => "" instead of "FF XX" - a trailing 0xFF byte is no longer issued when a valid "0xFF 0xXX" marker is found: "FF XX" => "" instead of "FF" For jpegls: Changes the behaviour to be more in line with IJG's (non-jpegls) reference implementation, similar to the changes above: - optional 0xFF fill bytes in a stuffed zero bit sequence (which is an invalid pattern according to the standard) are now discarded: "FF (FF)? 0b0xxxxxxx" => "FF 0bxxxxxxx" instead of "FF 7F XX" - sequences with optional 0xFF fill bytes and a marker are no longer copied: "FF (FF)? 0b1xxxxxxx" => "" instead of "FF 7F" Unescaping for jpegls is now done in one pass instead of two. The first pass used to detect the length of the buffer, while the second pass would copy up to the detected length. Note that jpegls restart markers are still not supported. There is also a speed up with the new implementations, mostly due to the usage of memchr() as suggested by Andreas Rheinhardt <[email protected]> --- libavcodec/mjpegdec.c | 135 ++++++++++++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 69 deletions(-) diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index cd36bc6022..ef8c694a76 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -2256,94 +2256,91 @@ static int mjpeg_unescape_sos(MJpegDecodeContext *s) const uint8_t *src = buf_ptr; const uint8_t *ptr = src; uint8_t *dst = s->buffer; - - #define copy_data_segment(skip) do { \ - ptrdiff_t length = (ptr - src) - (skip); \ - if (length > 0) { \ - memcpy(dst, src, length); \ - dst += length; \ - src = ptr; \ - } \ - } while (0) - - while (ptr < buf_end) { - uint8_t x = *(ptr++); - - if (x == 0xff) { - ptrdiff_t skip = 0; - while (ptr < buf_end && x == 0xff) { - x = *(ptr++); - skip++; - } - - /* 0xFF, 0xFF, ... */ - if (skip > 1) { - copy_data_segment(skip); - - /* decrement src as it is equal to ptr after the - * copy_data_segment macro and we might want to - * copy the current value of x later on */ - src--; - } - - if (x < RST0 || x > RST7) { - copy_data_segment(1); - if (x) - break; - } + PutByteContext pb; + + bytestream2_init_writer(&pb, dst, buf_end - src); + + while ((ptr = memchr(ptr, 0xff, buf_end - ptr))) { + ptr++; + if (ptr < buf_end) { + /* Copy verbatim data. */ + ptrdiff_t length = (ptr - 1) - src; + if (length > 0) + bytestream2_put_bufferu(&pb, src, length); + + uint8_t x = *ptr++; + /* Discard multiple optional 0xFF fill bytes. */ + while (x == 0xff && ptr < buf_end) + x = *ptr++; + + src = ptr; + if (x == 0) { + /* Stuffed zero byte */ + bytestream2_put_byteu(&pb, 0xff); + } else if (x >= RST0 && x <= RST7) { + /* Restart marker */ + bytestream2_put_be16u(&pb, 0xff00 | x); + } else { + /* Non-restart marker */ + goto found; } } - if (src < ptr) - copy_data_segment(0); - #undef copy_data_segment + } + /* Copy remaining verbatim data. */ + ptr = buf_end; + ptrdiff_t length = ptr - src; + if (length > 0) + bytestream2_put_bufferu(&pb, src, length); +found: unescaped_buf_ptr = s->buffer; - unescaped_buf_size = dst - s->buffer; + unescaped_buf_size = bytestream2_tell_p(&pb); memset(s->buffer + unescaped_buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); av_log(s->avctx, AV_LOG_DEBUG, "escaping removed %td bytes\n", - (buf_end - buf_ptr) - (dst - s->buffer)); + (buf_end - buf_ptr) - (unescaped_buf_size)); } else { const uint8_t *src = buf_ptr; + const uint8_t *ptr = src; uint8_t *dst = s->buffer; - int bit_count = 0; - int t = 0, b = 0; PutBitContext pb; - /* find marker */ - while (src + t < buf_end) { - uint8_t x = src[t++]; - if (x == 0xff) { - while ((src + t < buf_end) && x == 0xff) - x = src[t++]; - if (x & 0x80) { - t -= FFMIN(2, t); - break; - } - } - } - bit_count = t * 8; - init_put_bits(&pb, dst, t); - - /* unescape bitstream */ - while (b < t) { - uint8_t x = src[b++]; - put_bits(&pb, 8, x); - if (x == 0xFF && b < t) { - x = src[b++]; - if (x & 0x80) { - av_log(s->avctx, AV_LOG_WARNING, "Invalid escape sequence\n"); - x &= 0x7f; + init_put_bits(&pb, dst, buf_end - src); + + while ((ptr = memchr(ptr, 0xff, buf_end - ptr))) { + ptr++; + if (ptr < buf_end) { + /* Copy verbatim data. */ + ptrdiff_t length = (ptr - 1) - src; + if (length > 0) + ff_copy_bits(&pb, src, length * 8); + + uint8_t x = *ptr++; + /* Discard multiple optional 0xFF fill bytes. */ + while (x == 0xff && ptr < buf_end) + x = *ptr++; + + src = ptr; + if (!(x & 0x80)) { + /* Stuffed zero bit */ + put_bits(&pb, 15, 0x7f80 | x); + } else { + goto found_ls; } - put_bits(&pb, 7, x); - bit_count--; } } + /* Copy remaining verbatim data. */ + ptr = buf_end; + ptrdiff_t length = ptr - src; + if (length > 0) + ff_copy_bits(&pb, src, length * 8); + +found_ls: flush_put_bits(&pb); unescaped_buf_ptr = dst; - unescaped_buf_size = (bit_count + 7) >> 3; + unescaped_buf_size = put_bytes_output(&pb); memset(s->buffer + unescaped_buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); } _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
