This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new c3655a9694 TIKA-4800: Expose the MP4 frame rate, audio channels and
sample size (#2982)
c3655a9694 is described below
commit c3655a96947facd71f7fdc17478fd074c8b23a61
Author: Dominik Schmidt <[email protected]>
AuthorDate: Thu Aug 6 02:24:45 2026 +0200
TIKA-4800: Expose the MP4 frame rate, audio channels and sample size (#2982)
* TIKA-4800: Add video:frame-rate from the MP4 video track
* TIKA-4800: Add audio:channels from the MP4 sound track
* TIKA-4800: Add audio:bits-per-sample from the MP4 sound track
---
.../main/java/org/apache/tika/metadata/Audio.java | 12 ++++++++
.../main/java/org/apache/tika/metadata/Video.java | 33 +++++++++++++++++++++
.../java/org/apache/tika/parser/mp4/MP4Parser.java | 11 +++++++
.../org/apache/tika/parser/mp4/MP4ParserTest.java | 12 +++++++-
.../test/resources/test-documents/testMP4Video.mp4 | Bin 0 -> 1810 bytes
5 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Audio.java
b/tika-core/src/main/java/org/apache/tika/metadata/Audio.java
index 9b84b0eb3f..90232d45da 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/Audio.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/Audio.java
@@ -71,4 +71,16 @@ public interface Audio {
* protected audio track sets it. Only set when protection is detected.
*/
Property HAS_DRM = Property.internalBoolean("audio:has-drm");
+
+ /**
+ * Number of audio channels (e.g. 2 for stereo). {@link
XMPDM#AUDIO_CHANNEL_TYPE}
+ * only distinguishes Mono from Stereo and cannot represent more than two
+ * channels. A per-stream value, see {@link #BITRATE}.
+ */
+ Property CHANNELS = Property.internalInteger("audio:channels");
+
+ /**
+ * Audio sample size in bits (e.g. 16). A per-stream value, see {@link
#BITRATE}.
+ */
+ Property BITS_PER_SAMPLE =
Property.internalInteger("audio:bits-per-sample");
}
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Video.java
b/tika-core/src/main/java/org/apache/tika/metadata/Video.java
new file mode 100644
index 0000000000..6dc90345b5
--- /dev/null
+++ b/tika-core/src/main/java/org/apache/tika/metadata/Video.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata;
+
+/**
+ * Video metadata properties that have no suitable XMPDM equivalent.
+ * See TIKA-4800.
+ *
+ * @since Apache Tika 4.0.0
+ */
+public interface Video {
+
+ /**
+ * Frame rate in frames per second. {@link XMPDM#VIDEO_FRAME_RATE} is a
+ * closed-choice text field (24, NTSC, PAL) and cannot carry an arbitrary
+ * measured rate.
+ */
+ Property FRAME_RATE = Property.internalReal("video:frame-rate");
+}
diff --git
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp4/MP4Parser.java
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp4/MP4Parser.java
index e450c1675b..b146a8bab4 100644
---
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp4/MP4Parser.java
+++
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp4/MP4Parser.java
@@ -45,9 +45,11 @@ import org.apache.tika.annotation.TikaComponent;
import org.apache.tika.exception.RuntimeSAXException;
import org.apache.tika.exception.TikaException;
import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.Audio;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.Property;
import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.metadata.Video;
import org.apache.tika.metadata.XMPDM;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.ParseContext;
@@ -158,6 +160,12 @@ public class MP4Parser implements Parser {
String compressor =
mp4Directory.getString(Mp4VideoDirectory.TAG_COMPRESSOR_NAME);
metadata.set(XMPDM.VIDEO_COMPRESSOR, compressor);
}
+ Float frameRate =
mp4Directory.getFloatObject(Mp4VideoDirectory.TAG_FRAME_RATE);
+ if (frameRate != null) {
+ // set as the float's own string: set(Property, double) would
widen it
+ // and print the double-rounding artefact (e.g. 29.969999...).
+ metadata.set(Video.FRAME_RATE, frameRate.toString());
+ }
}
/**
@@ -188,9 +196,12 @@ public class MP4Parser implements Parser {
Metadata metadata) {
addInt(mp4SoundDirectory, metadata,
Mp4SoundDirectory.TAG_AUDIO_SAMPLE_RATE,
XMPDM.AUDIO_SAMPLE_RATE);
+ addInt(mp4SoundDirectory, metadata,
Mp4SoundDirectory.TAG_AUDIO_SAMPLE_SIZE,
+ Audio.BITS_PER_SAMPLE);
try {
int numChannels =
mp4SoundDirectory.getInt(Mp4SoundDirectory.TAG_NUMBER_OF_CHANNELS);
+ metadata.set(Audio.CHANNELS, numChannels);
if (numChannels == 1) {
metadata.set(XMPDM.AUDIO_CHANNEL_TYPE, "Mono");
diff --git
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp4/MP4ParserTest.java
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp4/MP4ParserTest.java
index 2a8f9fcecb..0e3cbe1e3a 100644
---
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp4/MP4ParserTest.java
+++
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp4/MP4ParserTest.java
@@ -46,6 +46,7 @@ import org.apache.tika.metadata.Audio;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.QuickTime;
import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.metadata.Video;
import org.apache.tika.metadata.XMP;
import org.apache.tika.metadata.XMPDM;
import org.apache.tika.parser.ParseContext;
@@ -121,6 +122,8 @@ public class MP4ParserTest extends TikaTest {
assertEquals("44100", metadata.get(XMPDM.AUDIO_SAMPLE_RATE));
assertEquals("Stereo", metadata.get(XMPDM.AUDIO_CHANNEL_TYPE));
+ assertEquals("2", metadata.get(Audio.CHANNELS));
+ assertEquals("16", metadata.get(Audio.BITS_PER_SAMPLE));
assertEquals("M4A", metadata.get(XMPDM.AUDIO_COMPRESSOR));
assertEquals("0.07", metadata.get(XMPDM.DURATION));
@@ -179,8 +182,15 @@ public class MP4ParserTest extends TikaTest {
back.get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
}
- // TODO Test a MP4 Video file
// TODO Test an old QuickTime Video File
+ @Test
+ public void testVideoFrameRate() throws Exception {
+ // a 10 fps H.264 clip generated with ffmpeg (color source, 16x16, 1s)
+ XMLResult r = getXML("testMP4Video.mp4");
+ assertEquals("video/mp4", r.metadata.get(Metadata.CONTENT_TYPE));
+ assertEquals("10.0", r.metadata.get(Video.FRAME_RATE));
+ }
+
@Test
@Timeout(30000)
public void testInfiniteLoop() throws Exception {
diff --git
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP4Video.mp4
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP4Video.mp4
new file mode 100644
index 0000000000..1daaa0daf4
Binary files /dev/null and
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP4Video.mp4
differ