PR #25040 opened by StressTestor
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25040
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25040.patch

# Summary of changes

Commits: `avformat/mxfdec: ignore a local set truncated by the end of the file`,
`avformat/mxfdec: unparse the buffer SET_UID_METADATA read into`.

When the file ends inside a local set, mxf_read_local_tags() still adds the 
set, with every
field past the cut zero. A footer copy of a header set keeps the same instance 
UID and replaces
the complete copy. The first commit drops such a set so the earlier complete 
copy stays in use;
a truncation inside a set then behaves like a truncation just before it.

Measured on fate-suite `mxf/omneon_8.3.0.0_xdcam_startc_footer.mxf` (header 
metadata repeated
in the footer), with the header's FooterPartition field set to the footer 
offset as a
closed-header writer stores it, cutting every 2 bytes inside the 82 footer sets:

```
            same as complete   degraded   fails to open
  before         2542             970         1279
  after          4122               0          669
```

No cut opens worse than before. The lavf-mxf FATE output is unchanged when cut 
at every byte of
its header and footer partitions and every 4 KiB through its essence, and so is 
every cut inside
repeated metadata of the other fate-suite MXF samples. All fate-lavf-mxf* and 
fate-mxf-* tests
pass.

The second commit is a one-line latent fix: the macro unparsed the caller's 
local `uid` instead
of its `var` argument. No effect today because every caller passes `uid`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


From 85b3f0da8d9dc1e861b8adc777c1ddf98db9510c Mon Sep 17 00:00:00 2001
From: StressTestor <[email protected]>
Date: Sun, 11 Oct 2026 23:38:12 -0600
Subject: [PATCH 1/2] avformat/mxfdec: unparse the buffer SET_UID_METADATA read
 into

The macro reads 16 bytes into its var argument and then unparses the
enclosing function's local uid instead of var. All current callers
pass uid as var, so this has no effect today, but any other caller
would publish the zero local instead of the value it read.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: StressTestor <[email protected]>
---
 libavformat/mxfdec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 280a20aad3..7b3a654f41 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -3210,7 +3210,7 @@ static int64_t mxf_timestamp_to_int64(uint64_t timestamp)
 #define SET_UID_METADATA(pb, name, var, str) do { \
     char uuid_str[2 * AV_UUID_LEN + 4 + 1]; \
     avio_read(pb, var, 16); \
-    av_uuid_unparse(uid, uuid_str); \
+    av_uuid_unparse(var, uuid_str); \
     av_dict_set(&s->metadata, name, uuid_str, 0); \
 } while (0)
 
-- 
2.52.0


From 43f4a5f679e6f3c77c8a0b8f7a87ad48e8fd6bb4 Mon Sep 17 00:00:00 2001
From: StressTestor <[email protected]>
Date: Mon, 12 Oct 2026 12:57:26 -0600
Subject: [PATCH 2/2] avformat/mxfdec: ignore a local set truncated by the end
 of the file

mxf_read_local_tags() reads the tags of a local set until the declared
set length is used up or the file ends, and then adds the set whatever
happened. When the file ends inside the set, the fields past that
point were never read: avio_read() leaves their bytes untouched in the
zero-allocated set and the avio_rb*() readers return 0. A set repeated
in a later partition, typically the footer, keeps the instance UID of
the complete header copy, so the truncated copy replaces it and its
zero fields are used: descriptors without a codec UL or picture size,
unresolvable strong references, wrong track numbers.

Drop a set that the end of the file cut short, so an earlier complete
copy stays in use. A truncation inside a set now behaves like a
truncation just before it.

Index table segments are left as they are: they are not copies of
header metadata, and a partial segment is already handled the same
way as the complete one.

Measured on fate-suite mxf/omneon_8.3.0.0_xdcam_startc_footer.mxf,
which repeats its header metadata in the footer, with the header
partition's FooterPartition field set to the footer offset as a
closed-header writer would store it, cutting every 2 bytes inside the
82 footer sets (4791 cuts) and comparing ffprobe's streams against the
complete file:

            same as complete   degraded   fails to open
  before         2542             970         1279
  after          4122               0          669

No cut opens worse than before. The lavf-mxf FATE output gives the same
result as before when cut at every byte of its header and footer
partitions and every 4 KiB through its essence, and so does every cut
inside repeated metadata of the other fate-suite MXF samples.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: StressTestor <[email protected]>
---
 libavformat/mxfdec.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 7b3a654f41..4e094a99ea 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -3408,6 +3408,17 @@ static int mxf_read_local_tags(MXFContext *mxf, 
KLVPacket *klv, MXFMetadataReadF
         } else if (avio_tell(pb) <= next)   /* only seek forward, else this 
can loop for a long time */
             avio_seek(pb, next, SEEK_SET);
     }
+    if (meta && type != IndexTableSegment && avio_feof(pb)) {
+        /* The file ends inside this set. Its fields past that point were
+         * never read, so do not let it replace a complete copy of the
+         * same set from an earlier partition. Index table segments are
+         * not copies of header metadata and keep being added as before. */
+        av_log(mxf->fc, AV_LOG_WARNING,
+               "local set @ %#"PRIx64" truncated by end of file, ignored\n",
+               klv->offset);
+        mxf_free_metadataset(&meta, type);
+        return 0;
+    }
     return meta ? mxf_add_metadata_set(mxf, &meta, type) : 0;
 }
 
-- 
2.52.0

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

Reply via email to