This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 3d90949d1e0b93a6435404e1b00c914ff6b65b21
Author:     Ramiro Polla <[email protected]>
AuthorDate: Tue Sep 23 17:40:10 2025 +0200
Commit:     Ramiro Polla <[email protected]>
CommitDate: Fri Feb 20 16:32:10 2026 +0100

    avcodec/mjpegdec: split mjpeg_unescape_sos() out of ff_mjpeg_find_marker()
    
    Now only the image data is unescaped (and not the SOS header). As a
    side-effect, this also provides a proper fix for decoding CJPG files
    (issue #133).
---
 libavcodec/mjpegdec.c | 64 +++++++++++++++++++++++++++------------------------
 libavcodec/mjpegdec.h |  4 +---
 libavcodec/mxpegdec.c | 13 ++++-------
 3 files changed, 40 insertions(+), 41 deletions(-)

diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index d79e4ecadc..88205ee5c7 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -55,6 +55,11 @@
 #include "put_bits.h"
 
 
+static int mjpeg_unescape_sos(MJpegDecodeContext *s,
+                              const uint8_t *buf_ptr, const uint8_t *buf_end,
+                              const uint8_t **unescaped_buf_ptr,
+                              size_t *unescaped_buf_size);
+
 static int init_default_huffman_tables(MJpegDecodeContext *s)
 {
     static const struct {
@@ -1762,12 +1767,9 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const 
uint8_t *mb_bitmask,
 
     predictor = bytestream2_get_byteu(&s->gB);  /* JPEG Ss / lossless JPEG 
predictor / JPEG-LS NEAR */
     ilv = bytestream2_get_byteu(&s->gB);        /* JPEG Se / JPEG-LS ILV */
-    if(s->avctx->codec_tag != AV_RL32("CJPG")){
         uint8_t b = bytestream2_get_byteu(&s->gB);
         prev_shift      = b >> 4;   /* Ah */
         point_transform = b & 0x0F; /* Al */
-    }else
-        prev_shift = point_transform = 0;
 
     if (nb_components > 1) {
         /* interleaved stream */
@@ -1794,7 +1796,14 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const 
uint8_t *mb_bitmask,
     if (s->mjpb_skiptosod)
         bytestream2_skip(&s->gB, s->mjpb_skiptosod);
 
-    ret = init_get_bits8(&s->gb, s->gB.buffer, 
bytestream2_get_bytes_left(&s->gB));
+    const uint8_t *unescaped_buf_ptr;
+    size_t unescaped_buf_size;
+    ret = mjpeg_unescape_sos(s, s->gB.buffer, s->gB.buffer + 
bytestream2_get_bytes_left(&s->gB),
+                             &unescaped_buf_ptr, &unescaped_buf_size);
+    if (ret < 0)
+        return ret;
+
+    ret = init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size);
     if (ret < 0)
         return ret;
 
@@ -2207,7 +2216,7 @@ static int mjpeg_decode_com(MJpegDecodeContext *s)
 
 /* return the 8 bit start code value and update the search
    state. Return -1 if no start code found */
-static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end)
+int ff_mjpeg_find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end)
 {
     const uint8_t *buf_ptr;
     int val;
@@ -2233,28 +2242,26 @@ found:
     return val;
 }
 
-int ff_mjpeg_find_marker(MJpegDecodeContext *s,
-                         const uint8_t **buf_ptr, const uint8_t *buf_end,
-                         const uint8_t **unescaped_buf_ptr,
-                         int *unescaped_buf_size)
+static int mjpeg_unescape_sos(MJpegDecodeContext *s,
+                              const uint8_t *buf_ptr, const uint8_t *buf_end,
+                              const uint8_t **unescaped_buf_ptr,
+                              size_t *unescaped_buf_size)
 {
-    int start_code;
-    start_code = find_marker(buf_ptr, buf_end);
-
-    if (start_code != SOS ||
+    if (s->avctx->codec_id == AV_CODEC_ID_MEDIA100 ||
+        s->avctx->codec_id == AV_CODEC_ID_MJPEGB ||
         s->avctx->codec_id == AV_CODEC_ID_THP) {
-        *unescaped_buf_ptr  = *buf_ptr;
-        *unescaped_buf_size = buf_end - *buf_ptr;
-        return start_code;
+        *unescaped_buf_ptr  = buf_ptr;
+        *unescaped_buf_size = buf_end - buf_ptr;
+        return 0;
     }
 
-    av_fast_padded_malloc(&s->buffer, &s->buffer_size, buf_end - *buf_ptr);
+    av_fast_padded_malloc(&s->buffer, &s->buffer_size, buf_end - buf_ptr);
     if (!s->buffer)
         return AVERROR(ENOMEM);
 
     /* unescape buffer of SOS, use special treatment for JPEG-LS */
     if (!s->ls) {
-        const uint8_t *src = *buf_ptr;
+        const uint8_t *src = buf_ptr;
         const uint8_t *ptr = src;
         uint8_t *dst = s->buffer;
 
@@ -2304,9 +2311,9 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
                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) - (dst - s->buffer));
     } else {
-        const uint8_t *src = *buf_ptr;
+        const uint8_t *src = buf_ptr;
         uint8_t *dst  = s->buffer;
         int bit_count = 0;
         int t = 0, b = 0;
@@ -2349,7 +2356,7 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
                AV_INPUT_BUFFER_PADDING_SIZE);
     }
 
-    return start_code;
+    return 0;
 }
 
 static void reset_icc_profile(MJpegDecodeContext *s)
@@ -2372,9 +2379,7 @@ int ff_mjpeg_decode_frame_from_buf(AVCodecContext *avctx, 
AVFrame *frame,
 {
     MJpegDecodeContext *s = avctx->priv_data;
     const uint8_t *buf_end, *buf_ptr;
-    const uint8_t *unescaped_buf_ptr;
     int hshift, vshift;
-    int unescaped_buf_size;
     int start_code;
     int index;
     int ret = 0;
@@ -2396,23 +2401,22 @@ redo_for_pal8:
     buf_end = buf + buf_size;
     while (buf_ptr < buf_end) {
         /* find start next marker */
-        start_code = ff_mjpeg_find_marker(s, &buf_ptr, buf_end,
-                                          &unescaped_buf_ptr,
-                                          &unescaped_buf_size);
+        start_code = ff_mjpeg_find_marker(&buf_ptr, buf_end);
         /* EOF */
         if (start_code < 0)
             break;
 
-        if (unescaped_buf_size > INT_MAX / 8) {
+        ptrdiff_t bytes_left = buf_end - buf_ptr;
+        if (bytes_left > INT_MAX / 8) {
             av_log(avctx, AV_LOG_ERROR,
-                   "MJPEG packet 0x%x too big (%d/%d), corrupt data?\n",
-                   start_code, unescaped_buf_size, buf_size);
+                   "MJPEG packet 0x%x too big (%td/%d), corrupt data?\n",
+                   start_code, bytes_left, buf_size);
             return AVERROR_INVALIDDATA;
         }
         av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%td\n",
                start_code, buf_end - buf_ptr);
 
-        bytestream2_init(&s->gB, unescaped_buf_ptr, unescaped_buf_size);
+        bytestream2_init(&s->gB, buf_ptr, bytes_left);
 
         if (avctx->debug & FF_DEBUG_STARTCODE)
             av_log(avctx, AV_LOG_DEBUG, "startcode: %X\n", start_code);
diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
index e8c6cca669..fdd1848d96 100644
--- a/libavcodec/mjpegdec.h
+++ b/libavcodec/mjpegdec.h
@@ -183,8 +183,6 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s);
 int ff_mjpeg_decode_sos(MJpegDecodeContext *s,
                         const uint8_t *mb_bitmask,int mb_bitmask_size,
                         const AVFrame *reference);
-int ff_mjpeg_find_marker(MJpegDecodeContext *s,
-                         const uint8_t **buf_ptr, const uint8_t *buf_end,
-                         const uint8_t **unescaped_buf_ptr, int 
*unescaped_buf_size);
+int ff_mjpeg_find_marker(const uint8_t **buf_ptr, const uint8_t *buf_end);
 
 #endif /* AVCODEC_MJPEGDEC_H */
diff --git a/libavcodec/mxpegdec.c b/libavcodec/mxpegdec.c
index b66bff56c9..de374a8904 100644
--- a/libavcodec/mxpegdec.c
+++ b/libavcodec/mxpegdec.c
@@ -198,8 +198,6 @@ static int mxpeg_decode_frame(AVCodecContext *avctx, 
AVFrame *rframe,
     MXpegDecodeContext *s = avctx->priv_data;
     MJpegDecodeContext *jpg = &s->jpg;
     const uint8_t *buf_end, *buf_ptr;
-    const uint8_t *unescaped_buf_ptr;
-    int unescaped_buf_size;
     int start_code;
     int ret;
 
@@ -212,15 +210,15 @@ static int mxpeg_decode_frame(AVCodecContext *avctx, 
AVFrame *rframe,
     s->got_mxm_bitmask = 0;
     s->got_sof_data = !!s->got_sof_data;
     while (buf_ptr < buf_end) {
-        start_code = ff_mjpeg_find_marker(jpg, &buf_ptr, buf_end,
-                                          &unescaped_buf_ptr, 
&unescaped_buf_size);
+        start_code = ff_mjpeg_find_marker(&buf_ptr, buf_end);
         if (start_code < 0)
             goto the_end;
 
-        bytestream2_init(&jpg->gB, unescaped_buf_ptr, unescaped_buf_size);
+        int bytes_left = buf_end - buf_ptr;
+        bytestream2_init(&jpg->gB, buf_ptr, bytes_left);
 
         if (start_code >= APP0 && start_code <= APP15) {
-            mxpeg_decode_app(s, unescaped_buf_ptr, unescaped_buf_size);
+            mxpeg_decode_app(s, buf_ptr, bytes_left);
         }
 
         switch (start_code) {
@@ -247,8 +245,7 @@ static int mxpeg_decode_frame(AVCodecContext *avctx, 
AVFrame *rframe,
             }
             break;
         case COM:
-            ret = mxpeg_decode_com(s, unescaped_buf_ptr,
-                                   unescaped_buf_size);
+            ret = mxpeg_decode_com(s, buf_ptr, bytes_left);
             if (ret < 0)
                 return ret;
             break;

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to