On Tue, Aug 19, 2025 at 06:33:03PM +0300, [email protected] wrote:
> The branch, master has been updated
>        via  4c3f94f2651ce4d6834fbef10e5c287f25720ac9 (commit)
>        via  fe496b0308f1911138698b92bbafac582fa455d7 (commit)
>        via  535a07d14e16eb2930d2b1e16605eafa95959139 (commit)
>        via  8132ee046d1a03c5913759c50fce7beda8d3d627 (commit)
>        via  5d4f873ff31f86f9ae1927f37ca0fcb78da70512 (commit)
>        via  1e816ebefee0ef479fa76bd2a1fb9ec5d5e807df (commit)
>        via  93a8091015978c44462626409af71789080bbef4 (commit)
>        via  303f60684f25ce63951480ef0f759acf41aac938 (commit)
>        via  5caaadee7954f2014d9e0a17d1edfb961893bcf1 (commit)
>        via  d3190a64c366a79091fe47fddf93c09a7d988802 (commit)
>        via  44af3829796427b89c4b76b56652cc5932ada616 (commit)
>        via  f5ad1c910c168d05cb01315773ab0bd094c9372f (commit) <----------- we 
> are here
>        via  e3aa1154aab2656c91ce61915f79516d9b563b61 (commit)
>        via  c6cc2115f45ac26ae42442f8796996eb410f4028 (commit)
>        via  52dba25661305e3c4a6209d46aea43cd327c960e (commit)
>        via  bfb17d26306592c85cf0c4e909099c621177b062 (commit)
>        via  ba2ea285e0f270a0a885b414cafaace6a89b9a91 (commit)
>        via  ad77345a5d14862f4701e5ad422b03b14934a5b9 (commit)
>        via  bb90b262d6d23f1bca3587a48abc15b951cbbf05 (commit)
>        via  a99fff4e2d4058c57599ba0b968862af82bdad5b (commit)
>       from  a6b5a382dd7ecdd27c5d0ebba688e1db409d18fd (commit)
> 

[...]

> commit f5ad1c910c168d05cb01315773ab0bd094c9372f
> Author:     Leo Izen <[email protected]>
> AuthorDate: Mon Mar 17 11:51:33 2025 -0400
> Commit:     Leo Izen <[email protected]>
> CommitDate: Tue Aug 19 11:26:47 2025 -0400
> 
>     avcodec/exif: add ff_exif_get_buffer
>     
>     Add a function to allow encoders to get a self-contained EXIF
>     buffer to write into an EXIF chunk.
>     
>     Signed-off-by: Leo Izen <[email protected]>
> 
> diff --git a/libavcodec/exif.c b/libavcodec/exif.c
> index aa2246ae9a..c48eb5daa6 100644
> --- a/libavcodec/exif.c
> +++ b/libavcodec/exif.c
> @@ -29,6 +29,7 @@
>  
>  #include <inttypes.h>
>  
> +#include "libavutil/avconfig.h"
>  #include "libavutil/bprint.h"
>  #include "libavutil/display.h"
>  #include "libavutil/intreadwrite.h"
> @@ -47,6 +48,11 @@
>  #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];
> @@ -616,15 +622,19 @@ static size_t exif_get_ifd_size(const AVExifMetadata 
> *ifd)
>      return total_size;
>  }
>  
> -static int exif_write_ifd(void *logctx, PutByteContext *pb, int le, const 
> AVExifMetadata *ifd)
> +static int exif_write_ifd(void *logctx, PutByteContext *pb, int le, int 
> depth, const AVExifMetadata *ifd)
>  {
> -    int offset, ret, tell;
> -    tell = bytestream2_get_bytes_left_p(pb);
> +    int offset, ret, tell, tell2;
> +    tell = bytestream2_tell_p(pb);
>      tput16(pb, le, ifd->count);
>      offset = tell + IFD_EXTRA_SIZE + BASE_TAG_SIZE * (uint32_t) ifd->count;
>      av_log(logctx, AV_LOG_DEBUG, "writing IFD with %u entries and initial 
> offset %d\n", ifd->count, offset);
>      for (size_t i = 0; i < ifd->count; i++) {
>          const AVExifEntry *entry = &ifd->entries[i];
> +        av_log(logctx, AV_LOG_DEBUG, "writing TIFF entry: id: 0x%04" PRIx16 
> ", type: %d, count: %"
> +                                      PRIu32 ", offset: %d, offset value: 
> %d\n",
> +                                      entry->id, entry->type, entry->count,
> +                                      bytestream2_tell_p(pb), offset);
>          tput16(pb, le, entry->id);
>          if (entry->id == MAKERNOTE_TAG && entry->type == AV_TIFF_IFD) {
>              size_t ifd_size = exif_get_ifd_size(&entry->value.ifd);
> @@ -635,29 +645,30 @@ static int exif_write_ifd(void *logctx, PutByteContext 
> *pb, int le, const AVExif
>              tput32(pb, le, entry->count);
>          }
>          if (entry->type == AV_TIFF_IFD) {
> -            int tell = bytestream2_tell_p(pb);
>              tput32(pb, le, offset);
> +            tell2 = bytestream2_tell_p(pb);
>              bytestream2_seek_p(pb, offset, SEEK_SET);
>              if (entry->ifd_offset)
>                  bytestream2_put_buffer(pb, entry->ifd_lead, 
> entry->ifd_offset);
> -            ret = exif_write_ifd(logctx, pb, le, &entry->value.ifd);
> +            ret = exif_write_ifd(logctx, pb, le, depth + 1, 
> &entry->value.ifd);
>              if (ret < 0)
>                  return ret;
>              offset += ret + entry->ifd_offset;
> -            bytestream2_seek_p(pb, tell + 4, SEEK_SET);
> +            bytestream2_seek_p(pb, tell2, SEEK_SET);
>          } else {
>              size_t payload_size = entry->count * exif_sizes[entry->type];
>              if (payload_size > 4) {
> -                int tell = bytestream2_tell_p(pb);
>                  tput32(pb, le, offset);
> +                tell2 = bytestream2_tell_p(pb);
>                  bytestream2_seek_p(pb, offset, SEEK_SET);
>                  exif_write_values(pb, le, entry);
>                  offset += payload_size;
> -                bytestream2_seek_p(pb, tell + 4, SEEK_SET);
> +                bytestream2_seek_p(pb, tell2, SEEK_SET);
>              } else {
>                  /* zero uninitialized excess payload values */
>                  AV_WN32(pb->buffer, 0);
>                  exif_write_values(pb, le, entry);
> +                bytestream2_seek_p(pb, 4 - payload_size, SEEK_CUR);
>              }
>          }
>      }
> @@ -666,7 +677,7 @@ static int exif_write_ifd(void *logctx, PutByteContext 
> *pb, int le, const AVExif
>       * we write 0 if this is the top-level exif IFD
>       * indicating that there are no more IFD pointers
>       */
> -    tput32(pb, le, 0);
> +    tput32(pb, le, depth ? offset : 0);

I think, offset can point to the payload not just the next IFD


[...]
> +int ff_exif_get_buffer(void *logctx, const AVFrame *frame, AVBufferRef 
> **buffer_ptr, enum AVExifHeaderMode header_mode)
> +{
> +    int ret = 0;
> +    AVBufferRef *buffer = NULL;
> +    AVFrameSideData *sd_exif = NULL;
> +    AVFrameSideData *sd_orient = NULL;
> +    AVExifMetadata ifd = { 0 };
> +    AVExifEntry *or = NULL;
> +    AVExifEntry *iw = NULL;
> +    AVExifEntry *ih = NULL;
> +    AVExifEntry *pw = NULL;
> +    AVExifEntry *ph = NULL;
> +    AVExifMetadata *exif = NULL;
> +    uint64_t orientation = 1;
> +    uint64_t w = frame->width;
> +    uint64_t h = frame->height;
> +    int rewrite = 0;
> +
> +    if (!buffer_ptr || *buffer_ptr)
> +        return AVERROR(EINVAL);
> +
> +    sd_exif = av_frame_get_side_data(frame, AV_FRAME_DATA_EXIF);
> +    sd_orient = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);
> +
> +    if (!sd_exif && !sd_orient)
> +        return 0;
> +
> +    if (sd_orient)
> +        orientation = exif_get_orientation((int32_t *) sd_orient->data);
> +    if (orientation != 1)
> +        av_log(logctx, AV_LOG_DEBUG, "matrix contains nontrivial EXIF 
> orientation: %" PRIu64 "\n", orientation);
> +
> +    if (sd_exif) {
> +        ret = av_exif_parse_buffer(logctx, sd_exif->data, sd_exif->size, 
> &ifd, AV_EXIF_TIFF_HEADER);
> +        if (ret < 0)
> +            goto end;
> +    }
> +
> +    for (size_t i = 0; i < ifd.count; i++) {
> +        AVExifEntry *entry = &ifd.entries[i];

> +        if (entry->id == ORIENTATION_TAG && entry->count > 0 && entry->type 
> == AV_TIFF_SHORT) {
> +            or = entry;
> +            continue;
> +        }
> +        if (entry->id == IMAGE_WIDTH_TAG && entry->count > 0 && entry->type 
> == AV_TIFF_LONG) {
> +            iw = entry;
> +            continue;
> +        }
> +        if (entry->id == IMAGE_LENGTH_TAG && entry->count > 0 && entry->type 
> == AV_TIFF_LONG) {
> +            ih = entry;
> +            continue;
> +        }

This will fail if they are not AV_TIFF_SHORT or AV_TIFF_LONG as hardcoded

also this is messy, there should be just a set or switch() of ids to check for 
changes
not each id hardcoded and handled in a seperate code path


> +        if (entry->id == EXIFIFD_TAG && entry->type == AV_TIFF_IFD) {
> +            exif = &entry->value.ifd;
> +            for (size_t j = 0; j < exif->count; j++) {
> +                AVExifEntry *exifentry = &exif->entries[j];
> +                if (exifentry->id == PIXEL_X_TAG && exifentry->count > 0 && 
> exifentry->type == AV_TIFF_SHORT) {
> +                    pw = exifentry;
> +                    continue;
> +                }
> +                if (exifentry->id == PIXEL_Y_TAG && exifentry->count > 0 && 
> exifentry->type == AV_TIFF_SHORT) {
> +                    ph = exifentry;
> +                    continue;
> +                }
> +            }
> +        }
> +    }
> +
> +    if (or && or->value.uint[0] != orientation) {
> +        rewrite = 1;
> +        or->value.uint[0] = orientation;
> +    }
> +    if (iw && iw->value.uint[0] != w) {
> +        rewrite = 1;
> +        iw->value.uint[0] = w;
> +    }
> +    if (ih && ih->value.uint[0] != h) {
> +        rewrite = 1;
> +        ih->value.uint[0] = h;
> +    }
> +    if (pw && pw->value.uint[0] != w) {
> +        rewrite = 1;
> +        pw->value.uint[0] = w;
> +    }
> +    if (ph && ph->value.uint[0] != h) {
> +        rewrite = 1;
> +        ph->value.uint[0] = h;
> +    }
> +    if (!or && orientation != 1) {
> +        rewrite = 1;
> +        ret = av_exif_set_entry(logctx, &ifd, ORIENTATION_TAG, 
> AV_TIFF_SHORT, 1, NULL, 0, &orientation);
> +        if (ret < 0)
> +            goto end;
> +    }
> +    if (!iw && w) {
> +        rewrite = 1;
> +        ret = av_exif_set_entry(logctx, &ifd, IMAGE_WIDTH_TAG, AV_TIFF_LONG, 
> 1, NULL, 0, &w);
> +        if (ret < 0)
> +            goto end;
> +    }
> +    if (!ih && h) {
> +        rewrite = 1;
> +        ret = av_exif_set_entry(logctx, &ifd, IMAGE_LENGTH_TAG, 
> AV_TIFF_LONG, 1, NULL, 0, &h);
> +        if (ret < 0)
> +            goto end;
> +    }
> +    if (!pw && w && w < 0xFFFFu || !ph && h && h < 0xFFFFu) {

why is 0xFFFFu excluded ?


> +        rewrite = 1;
> +        if (!exif) {
> +            AVExifMetadata exif_new = { 0 };
> +            ret = av_exif_set_entry(logctx, &ifd, EXIFIFD_TAG, AV_TIFF_IFD, 
> 1, NULL, 0, &exif_new);
> +            if (ret < 0) {
> +                av_exif_free(&exif_new);
> +                goto end;
> +            }
> +            exif = &ifd.entries[ifd.count - 1].value.ifd;
> +        }
> +        if (!pw && w && w < 0xFFFFu) {
> +            ret = av_exif_set_entry(logctx, exif, PIXEL_X_TAG, 
> AV_TIFF_SHORT, 1, NULL, 0, &w);
> +            if (ret < 0)
> +                goto end;
> +        }
> +        if (!ph && h && h < 0xFFFFu) {
> +            ret = av_exif_set_entry(logctx, exif, PIXEL_Y_TAG, 
> AV_TIFF_SHORT, 1, NULL, 0, &h);
> +            if (ret < 0)
> +                goto end;
> +        }
> +    }
> +

> +    if (rewrite) {
> +        ret = av_exif_write(logctx, &ifd, &buffer, header_mode);
> +        if (ret < 0)
> +            goto end;
> +
> +        *buffer_ptr = buffer;
> +    } else {
> +        *buffer_ptr = av_buffer_ref(sd_exif->buf);
> +        if (!*buffer_ptr) {
> +            ret = AVERROR(ENOMEM);
> +            goto end;
> +        }
> +    }

how does this work ?
when rewrite is set header_mode is used, but when rewrite is not
set header_mode is ignored and side data is stored as if it was
in the correct mode.

I seems someone or something mixed the meaning of rewrite here
"rewrite" as in the EXIF data mismatches with real w/h
vs.
"rewrite" as in rewrite because of header_mode difference


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The smallest minority on earth is the individual. Those who deny 
individual rights cannot claim to be defenders of minorities. - Ayn Rand

Attachment: signature.asc
Description: PGP signature

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

Reply via email to