[FFmpeg-devel] [PATCH] libavutil: add qtff well-known type functions (PR #20846)

2025-11-05 Thread Lukas via ffmpeg-devel
PR #20846 opened by Lukas (lholliger)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20846
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20846.patch

QuickTime File Format (QTFF/MOV) have a list of well-known datatypes
and there is currently little in place to decode or encode these
values besides a small part in mov.c. This adds the ability to encode
and decode various types for integers, floats, and strings. These
well-known types have usage to decoding some parts on the moov atom
or for metadata boxed/mebx values.

Also updated mov.c to use this function.




>From 9a4c805ea90401f8c51f31be1c4c523815dfa100 Mon Sep 17 00:00:00 2001
From: lholliger 
Date: Wed, 5 Nov 2025 14:15:08 -0500
Subject: [PATCH 1/2] libavutil: add qtff well-known type functions

QuickTime File Format (QTFF/MOV) have a list of well-known datatypes
and there is currently little in place to decode or encode these
values besides a small part in mov.c. This adds the ability to encode
and decode various types for integers, floats, and strings. These
well-known types have usage to decoding some parts on the moov atom
or for metadata boxed/mebx values.

Signed-off-by: lholliger 
---
 libavutil/Makefile |   2 +
 libavutil/qtff.c   | 380 +
 libavutil/qtff.h   |  59 +++
 3 files changed, 441 insertions(+)
 create mode 100644 libavutil/qtff.c
 create mode 100644 libavutil/qtff.h

diff --git a/libavutil/Makefile b/libavutil/Makefile
index ee77e51c08..792b587529 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -75,6 +75,7 @@ HEADERS = adler32.h   
  \
   pixdesc.h \
   pixelutils.h  \
   pixfmt.h  \
+  qtff.h\
   random_seed.h \
   rc4.h \
   rational.h\
@@ -168,6 +169,7 @@ OBJS = adler32.o
\
parseutils.o \
pixdesc.o\
pixelutils.o \
+   qtff.o   \
random_seed.o\
rational.o   \
refstruct.o  \
diff --git a/libavutil/qtff.c b/libavutil/qtff.c
new file mode 100644
index 00..a58d360958
--- /dev/null
+++ b/libavutil/qtff.c
@@ -0,0 +1,380 @@
+/*
+ * copyright (c) 2025 Lukas Holliger
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include 
+#include 
+#include 
+
+#include "qtff.h"
+#include "intfloat.h"
+#include "intreadwrite.h"
+#include "error.h"
+
+int av_qtff_convert_well_known_to_str(int data_type, const uint8_t *data, int 
data_size,
+  char *str, int str_size)
+{
+if (!data || !str || str_size <= 0)
+return AVERROR(EINVAL);
+
+switch (data_type) {
+case 0:  // Reserved
+case 2:  // UTF-16
+case 3:  // S/JIS
+case 4:  // UTF-8 sort
+case 5:  // UTF-16 sort
+case 13: // JPEG
+case 14: // PNG
+case 27: // BMP
+case 28: // QuickTime Metadata atom
+case 70: // BE PointF32
+case 71: // BE DimensionsF32
+case 72: // BE RectF32
+case 79: // AffineTransformF64
+return AVERROR_PATCHWELCOME;
+case 1: {  // UTF-8
+int len = data_size < str_size - 1 ? data_size : str_size - 1;
+memcpy(str, data, len);
+str[len] = '\0';
+break;
+}
+case 21: {  // BE Signed Integer (variable size, not usable for timed 
metadata)
+int val = 0;
+switch (data_size) {
+case 1:
+val = (int8_t)AV_RB8(data);
+break;
+case 2:
+val = (int

[FFmpeg-devel] [PATCH] WIP: Add encoder and decoder for MEBX/Metadata Boxed (PR #20775)

2025-10-28 Thread Lukas via ffmpeg-devel
PR #20775 opened by Lukas (lholliger)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20775
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20775.patch

ISO 14496-12 defines a timed metadata allowing for metadata per-frame
or sub-frame, this patch aims to implement a decoder to validate the
data in the moov atom as well as the frame data. This also implements
a basic encoder to write this data back. This also implements some
newer requirements for the dtyp and keyd atoms defined on Apple's
documentation as this format tends to currently only be used for
certain Apple videos such as subtitles on Vision Pro or Cinematic Mode
on iPhone, but this format is by no means limited to just Apple's usage.

A lot was edited here and a part of me feels like its a bit too much since
I had to go into the decode.c and others to get DATA to behave as frames,
but since this format is timed as frames was it felt necessary, but it seems
something like this hasn't been done much before so any help and teaching
is appreciated!

This is based on PR #20738 but since it changes a lot and isn't the original
idea I thought a new PR would suit this best.


>From 42d0970e24b7fe02299fde4c96fe265dbd31a136 Mon Sep 17 00:00:00 2001
From: lholliger <[email protected]>
Date: Tue, 28 Oct 2025 09:37:13 -0400
Subject: [PATCH] Add encoder and decoder for MEBX/Metadata Boxed

ISO 14496-12 defines a timed metadata allowing for metadata per-frame
or sub-frame, this patch aims to implement a decoder to validate the
data in the moov atom as well as the frame data. This also implements
a basic encoder to write this data back. This also implements some
newer requirements for the dtyp and keyd atoms defined on Apple's
documentation as this format tends to currently only be used for
certain Apple videos such as subtitles on Vision Pro or Cinematic Mode
on iPhone, but this format is by no means limited to just Apple's usage.
---
 fftools/ffmpeg_dec.c   |   2 +
 fftools/ffmpeg_enc.c   |  10 +
 fftools/ffmpeg_mux_init.c  |   3 +-
 fftools/ffprobe.c  |   1 +
 libavcodec/Makefile|   2 +
 libavcodec/allcodecs.c |   4 +
 libavcodec/codec_desc.c|   6 +
 libavcodec/codec_id.h  |   1 +
 libavcodec/decode.c|  18 +-
 libavcodec/mebxdec.c   | 449 +
 libavcodec/mebxenc.c   | 100 +
 libavcodec/tests/avcodec.c |   3 +-
 libavformat/avformat.h |   1 +
 libavformat/format.c   |   2 +
 libavformat/isom.c |   1 +
 libavformat/mov.c  |   7 +
 libavformat/movenc.c   |  44 +++-
 libavutil/frame.h  |   6 +
 18 files changed, 654 insertions(+), 6 deletions(-)
 create mode 100644 libavcodec/mebxdec.c
 create mode 100644 libavcodec/mebxenc.c

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 2f25265997..343718660e 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -791,6 +791,8 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, 
AVFrame *frame)
 dp->dec.samples_decoded += frame->nb_samples;
 
 audio_ts_process(dp, frame);
+} else if (dec->codec_type == AVMEDIA_TYPE_DATA) {
+// metadata needs to be processed, no changes needed
 } else {
 ret = video_frame_process(dp, frame, &outputs_mask);
 if (ret < 0) {
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 84e7e0ca0e..28d45a21f0 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -227,6 +227,12 @@ int enc_open(void *opaque, const AVFrame *frame)
 if (ost->type == AVMEDIA_TYPE_AUDIO || ost->type == AVMEDIA_TYPE_VIDEO) {
 enc_ctx->time_base  = frame->time_base;
 enc_ctx->framerate  = fd->frame_rate_filter;
+} else if (ost->type == AVMEDIA_TYPE_DATA) {
+// use frame timebase if available, otherwise use a default
+if (frame && frame->time_base.num > 0)
+enc_ctx->time_base = frame->time_base;
+else
+enc_ctx->time_base = AV_TIME_BASE_Q;
 }
 
 switch (enc_ctx->codec_type) {
@@ -329,6 +335,10 @@ int enc_open(void *opaque, const AVFrame *frame)
 enc_ctx->subtitle_header_size = dec->subtitle_header_size;
 }
 
+break;
+case AVMEDIA_TYPE_DATA:
+// Data streams have minimal encoding requirements
+// No special frame properties to set
 break;
 default:
 av_assert0(0);
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index c24b69f2d1..ca6e0435d2 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -79,7 +79,8 @@ static int choose_encoder(const OptionsContext *o, 
AVFormatContext *s,
 
 if (type != AVMEDIA_TYPE_VIDEO  &&
 type != AVMEDIA_TYPE_AUDIO  &&
-type != AVMEDIA_TYPE_SUBTITLE) {
+type != AVMEDIA_TYPE_SUBTITLE   &&
+type != AVMEDIA_TYPE_DATA) {
 if (codec_name && strcmp(codec_name, "copy")) {
   

[FFmpeg-devel] [PATCH] libavformat/mov: add support for name udta (PR #20802)

2025-10-31 Thread Lukas via ffmpeg-devel
PR #20802 opened by Lukas (lholliger)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20802
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20802.patch

In the QTFF documentation for udta/"user data atoms", "name" is a
valid entry for "name of object" however it is currently skipped
leading to some missing metadata when copying for some files. This
isn't classified the same as "(C)nam" which is "Title of content"
so they aren't necessarily the same.

Docs: 
https://developer.apple.com/documentation/quicktime-file-format/user_data_atoms
Fixes #20750


>From 881de845afce926482159b8d2272a6fa33fdeadd Mon Sep 17 00:00:00 2001
From: lholliger <[email protected]>
Date: Fri, 31 Oct 2025 10:21:38 -0400
Subject: [PATCH] libavformat/mov: add support for name udta

In the QTFF documentation for udta/"user data atoms", "name" is a
valid entry for "name of object" however it is currently skipped
leading to some missing metadata when copying for some files. This
isn't classified the same as "(C)nam" which is "Title of content"
so they aren't necessarily the same.
---
 libavformat/mov.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavformat/mov.c b/libavformat/mov.c
index 45c562cdc6..42062e6ba6 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -392,6 +392,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
 return mov_metadata_loci(c, pb, atom.size);
 case MKTAG( 'm','a','n','u'): key = "make"; break;
 case MKTAG( 'm','o','d','l'): key = "model"; break;
+case MKTAG( 'n','a','m','e'): key = "name"; break;
 case MKTAG( 'p','c','s','t'): key = "podcast";
 parse = mov_metadata_int8_no_padding; break;
 case MKTAG( 'p','g','a','p'): key = "gapless_playback";
-- 
2.49.1

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