[FFmpeg-cvslog] [ffmpeg] branch master updated. 5ed1d72792 avcodec/decode: remove Exif Orientation tag after adding it as display matrix

ffmpeg-git at ffmpeg.org ffmpeg-git at ffmpeg.org
Fri Aug 22 01:48:44 EEST 2025


The branch, master has been updated
       via  5ed1d7279298cfc218a9b989cad4d1b97a066e8d (commit)
       via  5a9e5d8031b98dd269033918499e9db79c0a26c1 (commit)
      from  d311382c38df9c2237b33a9e8e860a5da7d2895d (commit)


- Log -----------------------------------------------------------------
commit 5ed1d7279298cfc218a9b989cad4d1b97a066e8d
Author:     James Almer <jamrial at gmail.com>
AuthorDate: Wed Aug 20 13:03:21 2025 -0300
Commit:     Leo Izen <leo.izen at gmail.com>
CommitDate: Thu Aug 21 22:48:16 2025 +0000

    avcodec/decode: remove Exif Orientation tag after adding it as display matrix
    
    Don't replace it with a conflicting value.
    
    Signed-off-by: James Almer <jamrial at gmail.com>

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 1dbb20de0e..b0ce94cadd 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -2290,24 +2290,22 @@ static int exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMe
         if (ret < 0) {
             av_log(avctx, AV_LOG_WARNING, "unable to attach displaymatrix from EXIF\n");
         } else {
-            const AVExifEntry *cloned_orient;
             cloned = av_exif_clone_ifd(ifd);
             if (!cloned) {
                 ret = AVERROR(ENOMEM);
                 goto end;
             }
-            // will have the same offset in the clone as in the original
-            cloned_orient = &cloned->entries[orient - ifd->entries];
-            cloned_orient->value.uint[0] = 1;
+            av_exif_remove_entry(avctx, cloned, orient->id, 0);
+            ifd = cloned;
         }
     }
 
-    ret = av_exif_ifd_to_dict(avctx, cloned ? cloned : ifd, &frame->metadata);
+    ret = av_exif_ifd_to_dict(avctx, ifd, &frame->metadata);
     if (ret < 0)
         goto end;
 
     if (cloned || !og) {
-        ret = av_exif_write(avctx, cloned ? cloned : ifd, &written, AV_EXIF_TIFF_HEADER);
+        ret = av_exif_write(avctx, ifd, &written, AV_EXIF_TIFF_HEADER);
         if (ret < 0)
             goto end;
     }

commit 5a9e5d8031b98dd269033918499e9db79c0a26c1
Author:     James Almer <jamrial at gmail.com>
AuthorDate: Tue Aug 19 13:18:18 2025 -0300
Commit:     Leo Izen <leo.izen at gmail.com>
CommitDate: Thu Aug 21 22:48:16 2025 +0000

    avcodec/exif: use ff_frame_new_side_data() to export display matrix
    
    Otherwise, the user requested priority of packet side data will be ignored.
    For this, move the relevant functions to decode.c, as they need access to an
    AVCodecContext.
    
    Signed-off-by: James Almer <jamrial at gmail.com>

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 2319e76e4b..1dbb20de0e 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -47,6 +47,7 @@
 #include "codec_desc.h"
 #include "codec_internal.h"
 #include "decode.h"
+#include "exif_internal.h"
 #include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "internal.h"
@@ -2245,3 +2246,108 @@ void ff_decode_internal_uninit(AVCodecContext *avctx)
 
     av_refstruct_unref(&dc->lcevc);
 }
+
+static int attach_displaymatrix(AVCodecContext *avctx, AVFrame *frame, int orientation)
+{
+    AVFrameSideData *sd = NULL;
+    int32_t *matrix;
+    int ret;
+    /* invalid orientation */
+    if (orientation < 2 || orientation > 8)
+        return AVERROR_INVALIDDATA;
+    ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9, &sd);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame side data: %s\n", av_err2str(ret));
+        return ret;
+    }
+    if (sd) {
+        matrix = (int32_t *) sd->data;
+        ret = av_exif_orientation_to_matrix(matrix, orientation);
+    }
+
+    return ret;
+}
+
+static int exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMetadata *ifd, AVBufferRef *og)
+{
+    const AVExifEntry *orient = NULL;
+    AVFrameSideData *sd;
+    AVExifMetadata *cloned = NULL;
+    AVBufferRef *written = NULL;
+    int ret;
+
+    for (size_t i = 0; i < ifd->count; i++) {
+        const AVExifEntry *entry = &ifd->entries[i];
+        if (entry->id == ORIENTATION_TAG && entry->count > 0 && entry->type == AV_TIFF_SHORT) {
+            orient = entry;
+            break;
+        }
+    }
+
+    if (orient && orient->value.uint[0] > 1) {
+        av_log(avctx, AV_LOG_DEBUG, "found nontrivial EXIF orientation: %" PRIu64 "\n", orient->value.uint[0]);
+        ret = attach_displaymatrix(avctx, frame, orient->value.uint[0]);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_WARNING, "unable to attach displaymatrix from EXIF\n");
+        } else {
+            const AVExifEntry *cloned_orient;
+            cloned = av_exif_clone_ifd(ifd);
+            if (!cloned) {
+                ret = AVERROR(ENOMEM);
+                goto end;
+            }
+            // will have the same offset in the clone as in the original
+            cloned_orient = &cloned->entries[orient - ifd->entries];
+            cloned_orient->value.uint[0] = 1;
+        }
+    }
+
+    ret = av_exif_ifd_to_dict(avctx, cloned ? cloned : ifd, &frame->metadata);
+    if (ret < 0)
+        goto end;
+
+    if (cloned || !og) {
+        ret = av_exif_write(avctx, cloned ? cloned : ifd, &written, AV_EXIF_TIFF_HEADER);
+        if (ret < 0)
+            goto end;
+    }
+
+    sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_EXIF, written ? written : og);
+    if (!sd) {
+        if (written)
+            av_buffer_unref(&written);
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+    ret = 0;
+
+end:
+    if (og && written && ret >= 0)
+        av_buffer_unref(&og); // as though we called new_side_data on og;
+    av_exif_free(cloned);
+    av_free(cloned);
+    return ret;
+}
+
+int ff_decode_exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMetadata *ifd)
+{
+    return exif_attach_ifd(avctx, frame, ifd, NULL);
+}
+
+int ff_decode_exif_attach_buffer(AVCodecContext *avctx, AVFrame *frame, AVBufferRef *data,
+                                 enum AVExifHeaderMode header_mode)
+{
+    int ret;
+    AVExifMetadata ifd = { 0 };
+
+    ret = av_exif_parse_buffer(avctx, data->data, data->size, &ifd, header_mode);
+    if (ret < 0)
+        goto end;
+
+    ret = exif_attach_ifd(avctx, frame, &ifd, data);
+
+end:
+    av_exif_free(&ifd);
+    return ret;
+}
diff --git a/libavcodec/decode.h b/libavcodec/decode.h
index 2c3719a8d0..f285da924d 100644
--- a/libavcodec/decode.h
+++ b/libavcodec/decode.h
@@ -220,4 +220,35 @@ int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame,
 int ff_decode_content_light_new_ext(const AVCodecContext *avctx,
                                     AVFrameSideData ***sd, int *nb_sd,
                                     struct AVContentLightMetadata **clm);
+
+enum AVExifHeaderMode;
+
+/**
+ * Attach the data buffer to the frame. This is mostly a wrapper for
+ * av_side_data_new_from_buffer, but it checks if the orientation tag is
+ * present in the provided EXIF buffer. If it is, it zeroes it out and
+ * attaches that information as an AV_FRAME_DATA_DISPLAYMATRIX instead
+ * of including it in the AV_FRAME_DATA_EXIF side data buffer.
+ *
+ * On a success, the caller loses ownership of the data buffer. Either it is
+ * unrefed, or its ownership is transferred to the frame directly. On failure,
+ * the data buffer is left owned by the caller.
+ */
+int ff_decode_exif_attach_buffer(AVCodecContext *avctx, AVFrame *frame, AVBufferRef *data,
+                                 enum AVExifHeaderMode header_mode);
+
+struct AVExifMetadata;
+
+/**
+ * Attach an already-parsed EXIF metadata struct to the frame as a side data
+ * buffer. It writes the EXIF IFD into the buffer and attaches the buffer to
+ * the frame.
+ *
+ * If the metadata struct contains an orientation tag, it will be zeroed before
+ * writing, and instead, an AV_FRAME_DATA_DISPLAYMATRIX will be attached in
+ * addition to the AV_FRAME_DATA_EXIF side data.
+ */
+int ff_decode_exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame,
+                              const struct AVExifMetadata *ifd);
+
 #endif /* AVCODEC_DECODE_H */
diff --git a/libavcodec/exif.c b/libavcodec/exif.c
index 2513ee4ec0..1332fa68bb 100644
--- a/libavcodec/exif.c
+++ b/libavcodec/exif.c
@@ -46,13 +46,6 @@
 #define IFD_EXTRA_SIZE         6
 
 #define EXIF_TAG_NAME_LENGTH   32
-#define MAKERNOTE_TAG          0x927c
-#define ORIENTATION_TAG        0x112
-#define EXIFIFD_TAG            0x8769
-#define IMAGE_WIDTH_TAG        0x100
-#define IMAGE_LENGTH_TAG       0x101
-#define PIXEL_X_TAG            0xa002
-#define PIXEL_Y_TAG            0xa003
 
 struct exif_tag {
     const char name[EXIF_TAG_NAME_LENGTH];
@@ -824,23 +817,6 @@ int av_exif_parse_buffer(void *logctx, const uint8_t *buf, size_t size,
     return bytestream2_tell(&gbytes);
 }
 
-static int attach_displaymatrix(void *logctx, AVFrame *frame, int orientation)
-{
-    AVFrameSideData *sd;
-    int32_t *matrix;
-    /* invalid orientation */
-    if (orientation < 2 || orientation > 8)
-        return AVERROR_INVALIDDATA;
-    sd = av_frame_new_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9);
-    if (!sd) {
-        av_log(logctx, AV_LOG_ERROR, "Could not allocate frame side data\n");
-        return AVERROR(ENOMEM);
-    }
-    matrix = (int32_t *) sd->data;
-
-    return av_exif_orientation_to_matrix(matrix, orientation);
-}
-
 #define COLUMN_SEP(i, c) ((i) ? ((i) % (c) ? ", " : "\n") : "")
 
 static int exif_ifd_to_dict(void *logctx, const char *prefix, const AVExifMetadata *ifd, AVDictionary **metadata)
@@ -953,68 +929,6 @@ int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size,
 }
 #endif /* FF_API_OLD_EXIF */
 
-static int exif_attach_ifd(void *logctx, AVFrame *frame, const AVExifMetadata *ifd, AVBufferRef *og)
-{
-    const AVExifEntry *orient = NULL;
-    AVFrameSideData *sd;
-    AVExifMetadata *cloned = NULL;
-    AVBufferRef *written = NULL;
-    int ret;
-
-    for (size_t i = 0; i < ifd->count; i++) {
-        const AVExifEntry *entry = &ifd->entries[i];
-        if (entry->id == ORIENTATION_TAG && entry->count > 0 && entry->type == AV_TIFF_SHORT) {
-            orient = entry;
-            break;
-        }
-    }
-
-    if (orient && orient->value.uint[0] > 1) {
-        av_log(logctx, AV_LOG_DEBUG, "found nontrivial EXIF orientation: %" PRIu64 "\n", orient->value.uint[0]);
-        ret = attach_displaymatrix(logctx, frame, orient->value.uint[0]);
-        if (ret < 0) {
-            av_log(logctx, AV_LOG_WARNING, "unable to attach displaymatrix from EXIF\n");
-        } else {
-            const AVExifEntry *cloned_orient;
-            cloned = av_exif_clone_ifd(ifd);
-            if (!cloned) {
-                ret = AVERROR(ENOMEM);
-                goto end;
-            }
-            // will have the same offset in the clone as in the original
-            cloned_orient = &cloned->entries[orient - ifd->entries];
-            cloned_orient->value.uint[0] = 1;
-        }
-    }
-
-    ret = av_exif_ifd_to_dict(logctx, cloned ? cloned : ifd, &frame->metadata);
-    if (ret < 0)
-        goto end;
-
-    if (cloned || !og) {
-        ret = av_exif_write(logctx, cloned ? cloned : ifd, &written, AV_EXIF_TIFF_HEADER);
-        if (ret < 0)
-            goto end;
-    }
-
-    sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_EXIF, written ? written : og);
-    if (!sd) {
-        if (written)
-            av_buffer_unref(&written);
-        ret = AVERROR(ENOMEM);
-        goto end;
-    }
-
-    ret = 0;
-
-end:
-    if (og && written && ret >= 0)
-        av_buffer_unref(&og); // as though we called new_side_data on og;
-    av_exif_free(cloned);
-    av_free(cloned);
-    return ret;
-}
-
 #define EXIF_COPY(fname, srcname) do { \
     size_t sz; \
     if (av_size_mult(src->count, sizeof(*(fname)), &sz) < 0) { \
@@ -1250,27 +1164,6 @@ fail:
     return NULL;
 }
 
-int ff_exif_attach_ifd(void *logctx, AVFrame *frame, const AVExifMetadata *ifd)
-{
-    return exif_attach_ifd(logctx, frame, ifd, NULL);
-}
-
-int ff_exif_attach_buffer(void *logctx, AVFrame *frame, AVBufferRef *data, enum AVExifHeaderMode header_mode)
-{
-    int ret;
-    AVExifMetadata ifd = { 0 };
-
-    ret = av_exif_parse_buffer(logctx, data->data, data->size, &ifd, header_mode);
-    if (ret < 0)
-        goto end;
-
-    ret = exif_attach_ifd(logctx, frame, &ifd, data);
-
-end:
-    av_exif_free(&ifd);
-    return ret;
-}
-
 static const int rotation_lut[2][4] = {
     {1, 8, 3, 6}, {4, 7, 2, 5},
 };
diff --git a/libavcodec/exif_internal.h b/libavcodec/exif_internal.h
index de1a26e3f9..565e747353 100644
--- a/libavcodec/exif_internal.h
+++ b/libavcodec/exif_internal.h
@@ -42,29 +42,13 @@ int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size,
                            int le, int depth, AVDictionary **metadata);
 #endif /* FF_API_OLD_EXIF */
 
-/**
- * Attach the data buffer to the frame. This is mostly a wrapper for
- * av_side_data_new_from_buffer, but it checks if the orientation tag is
- * present in the provided EXIF buffer. If it is, it zeroes it out and
- * attaches that information as an AV_FRAME_DATA_DISPLAYMATRIX instead
- * of including it in the AV_FRAME_DATA_EXIF side data buffer.
- *
- * On a success, the caller loses ownership of the data buffer. Either it is
- * unrefed, or its ownership is transferred to the frame directly. On failure,
- * the data buffer is left owned by the caller.
- */
-int ff_exif_attach_buffer(void *logctx, AVFrame *frame, AVBufferRef *data, enum AVExifHeaderMode header_mode);
-
-/**
- * Attach an already-parsed EXIF metadata struct to the frame as a side data
- * buffer. It writes the EXIF IFD into the buffer and attaches the buffer to
- * the frame.
- *
- * If the metadata struct contains an orientation tag, it will be zeroed before
- * writing, and instead, an AV_FRAME_DATA_DISPLAYMATRIX will be attached in
- * addition to the AV_FRAME_DATA_EXIF side data.
- */
-int ff_exif_attach_ifd(void *logctx, AVFrame *frame, const AVExifMetadata *ifd);
+#define MAKERNOTE_TAG          0x927c
+#define ORIENTATION_TAG        0x112
+#define EXIFIFD_TAG            0x8769
+#define IMAGE_WIDTH_TAG        0x100
+#define IMAGE_LENGTH_TAG       0x101
+#define PIXEL_X_TAG            0xa002
+#define PIXEL_Y_TAG            0xa003
 
 /**
  * Compares values in the IFD with data in the provided AVFrame and sets the values
diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c
index 7ea5fc4787..31f4592d1c 100644
--- a/libavcodec/libjxldec.c
+++ b/libavcodec/libjxldec.c
@@ -516,7 +516,7 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame)
                 ret = av_exif_remove_entry(avctx, &ifd, av_exif_get_tag_id("Orientation"), 0);
                 if (ret < 0)
                     av_log(avctx, AV_LOG_WARNING, "Unable to remove orientation from EXIF buffer\n");
-                ret = ff_exif_attach_ifd(avctx, ctx->frame, &ifd);
+                ret = ff_decode_exif_attach_ifd(avctx, ctx->frame, &ifd);
                 if (ret < 0)
                     av_log(avctx, AV_LOG_ERROR, "Unable to attach EXIF ifd\n");
             }
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 46ec3eb938..4d6379805c 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -2855,7 +2855,7 @@ the_end:
     }
 
     if (s->exif_metadata.entries) {
-        ret = ff_exif_attach_ifd(avctx, frame, &s->exif_metadata);
+        ret = ff_decode_exif_attach_ifd(avctx, frame, &s->exif_metadata);
         av_exif_free(&s->exif_metadata);
         if (ret < 0)
             av_log(avctx, AV_LOG_WARNING, "couldn't attach EXIF metadata\n");
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 5e138a4f49..8a63f0ad90 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -1751,15 +1751,15 @@ exit_loop:
         handle_small_bpp(s, p);
 
     if (s->exif_data) {
-        // we swap because ff_exif_attach_buffer adds to p->metadata
+        // we swap because ff_decode_exif_attach_buffer adds to p->metadata
         FFSWAP(AVDictionary *, p->metadata, s->frame_metadata);
-        ret = ff_exif_attach_buffer(avctx, p, s->exif_data, AV_EXIF_TIFF_HEADER);
+        ret = ff_decode_exif_attach_buffer(avctx, p, s->exif_data, AV_EXIF_TIFF_HEADER);
         FFSWAP(AVDictionary *, p->metadata, s->frame_metadata);
         if (ret < 0) {
             av_log(avctx, AV_LOG_WARNING, "unable to attach EXIF buffer\n");
             return ret;
         }
-        // ff_exif_attach_buffer takes ownership so
+        // ff_decode_exif_attach_buffer takes ownership so
         // we do not want to call av_buffer_unref here
         s->exif_data = NULL;
     }
diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
index d15bc497ec..bb8120bc1b 100644
--- a/libavcodec/tiff.c
+++ b/libavcodec/tiff.c
@@ -2411,7 +2411,7 @@ again:
         }
     }
 
-    ret = ff_exif_attach_ifd(avctx, p, &s->exif_meta);
+    ret = ff_decode_exif_attach_ifd(avctx, p, &s->exif_meta);
     if (ret < 0)
         av_log(avctx, AV_LOG_ERROR, "error attaching EXIF ifd: %s\n", av_err2str(ret));
 
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 56c3ec6d28..0dca130ff3 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -1477,7 +1477,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
             memcpy(exif_buf->data, gb.buffer, chunk_size);
 
             /* if this succeeds then exif_buf is either freed or transferred to the AVFrame */
-            ret = ff_exif_attach_buffer(avctx, p, exif_buf, AV_EXIF_TIFF_HEADER);
+            ret = ff_decode_exif_attach_buffer(avctx, p, exif_buf, AV_EXIF_TIFF_HEADER);
             if (ret < 0) {
                 av_log(avctx, AV_LOG_WARNING, "unable to attach EXIF buffer\n");
                 av_buffer_unref(&exif_buf);

-----------------------------------------------------------------------

Summary of changes:
 libavcodec/decode.c        | 104 +++++++++++++++++++++++++++++++++++++++++++
 libavcodec/decode.h        |  31 +++++++++++++
 libavcodec/exif.c          | 107 ---------------------------------------------
 libavcodec/exif_internal.h |  30 +++----------
 libavcodec/libjxldec.c     |   2 +-
 libavcodec/mjpegdec.c      |   2 +-
 libavcodec/pngdec.c        |   6 +--
 libavcodec/tiff.c          |   2 +-
 libavcodec/webp.c          |   2 +-
 9 files changed, 149 insertions(+), 137 deletions(-)


hooks/post-receive
-- 



More information about the ffmpeg-cvslog mailing list