[ 
https://issues.apache.org/jira/browse/TIKA-4777?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18095262#comment-18095262
 ] 

ASF GitHub Bot commented on TIKA-4777:
--------------------------------------

tballison commented on PR #2936:
URL: https://github.com/apache/tika/pull/2936#issuecomment-4934951662

   Feedback from claude:
   
   ```
   The feature is worth having and the byte-slicing is genuinely bounds-safe (I 
traced every offset; no OOB, no infinite loops, entry counts can't run away). 
But three things
     stand out: about half the diff re-implements traversal that 
metadata-extractor already does, there are two real bugs in the edit-list 
logic, and the metadata key shape
     deserves a conversation before it becomes API.
   
     1. Most of the plumbing is redundant (verified, not guessed)
   
     Mp4MetaHandler extends Mp4MediaHandler, whose shouldAcceptContainer 
already accepts minf and stbl, and whose shouldAcceptBox already accepts stsd.
     Mp4MetaHandler.processSampleDescription(SequentialReader) is an empty 
override waiting to be filled in.
   
     I confirmed this by running the stock handler plus a one-line hdlr 
injection against the PR's own fixture:
   
     >>> injecting TracingMetaHandler at hdlr/meta
       MetaHandler.shouldAcceptContainer(minf) = true
       MetaHandler.shouldAcceptContainer(stbl) = true
       MetaHandler.shouldAcceptBox(stsd) = true
       *** Mp4MetaHandler.processSampleDescription CALLED ***
           first 16 bytes of stsd payload: 0000000000000001000000506d656278
           entry type at +12: 'mebx'
   
     So instead of the hdlr hijack that returns this and suppresses 
Mp4MetaHandler entirely, plus the global minf/stbl/stsd acceptance in 
TikaMp4BoxHandler, the PR could return
     a TikaMp4MetaHandler extends Mp4MetaHandler from the hdlr branch (passing 
in emptyEditDuration and the movie timescale) and override 
processSampleDescription. That would:
   
     - keep Mp4MetaDirectory alive rather than silently deleting it from the 
extracted directories,
     - stop TikaMp4BoxHandler from descending into minf/stbl and slurping the 
stsd payload of every track whose handler type isn't soun/vide/hint/text/meta 
(sbtl, clcp, tmcd,
     …), which it now does for no benefit,
     - delete shouldAcceptContainer's minf/stbl cases and shouldAcceptBox's 
stsd case.
   
     Only edts (container) and elst (box) genuinely need adding to 
TikaMp4BoxHandler — I confirmed the stock handler returns false for both.
   
     Separately, processMovieTimescale is dead weight: the base 
processMovieHeader already stores the movie timescale, and 
directory.getLongObject(Mp4Directory.TAG_TIME_SCALE)
     returns 600 on this exact fixture. Ten lines and a field can go.
   
     To be fair about the Mp4MetaDirectory deletion: I checked the tag IDs, and 
Mp4MetaDirectory only ever holds TAG_CREATION_TIME=101, 
TAG_MODIFICATION_TIME=102,
     TAG_LANGUAGE_CODE=104, none of which collide with the 0x01xx tags 
processActualMp4Directory reads. So there's no visible regression today. It's a 
latent one.
   
     2. Two correctness bugs in processEditList
   
     The javadoc says "leading empty edit," but the loop scans every entry and 
takes the first mediaTime == -1 wherever it appears:
   
     - Edit list [(dur=100, mt=0), (dur=740, mt=-1), (dur=1, mt=0)] — the track 
presents media starting at movie time 0, so the start is 0. The code reports 
1233333.
     - Two consecutive leading empty edits [(740, -1), (300, -1), (1, 0)] — the 
true start is 1040 ticks. The code reports 740.
   
     The fix is to only honor entry 0, and to sum consecutive leading -1 
entries. Neither shape appears in Apple's own files, but the code doesn't say 
that and nothing stops a
     fuzzer or a third-party muxer.
   
     Related, and cheaper to fix than to argue about: emptyEditDuration * 
1_000_000L overflows for a version-1 elst with a large segment_duration. A 
emptyEditDuration > 
     Long.MAX_VALUE / 1_000_000 guard costs one line.
   
     Also, resetting emptyEditDuration on tkhd assumes tkhd precedes edts. It's 
mandated, but resetting on the trak container instead (processContainer routes 
through
     processBox("trak", null, …)) is free and order-independent.
   
     3. The design question I'd want settled before merge
   
     <key>.track-start-us attaches a track-level fact to every key name the 
track declares. The PR body confirms this in practice: on the real iPhone Live 
Photo, the
     still-image-time track also declares transform keys, and all of them get a 
.track-start-us sibling.
   
     For still-image-time the statement is meaningful only because that track 
has exactly one one-tick sample, so track-start is the sample's presentation 
time. The code never
     checks the sample count — it filters on "is delayed," which correlates 
with "single sample" in Apple's output but isn't the invariant. Note the JIRA 
description explicitly
     lists stts among the boxes to correlate; the PR doesn't read it. A delayed 
multi-sample mebx track would get <key>.track-start-us on keys whose values are 
timestamped all
     over the track.
   
     Two smaller shape questions:
   
     Namespace. com.apple.quicktime.still-image-time.track-start-us is a 
Tika-invented suffix grafted into Apple's namespace. It reads like a key Apple 
defined. It doesn't
     collide with reserved Tika keys (the suffix makes that impossible), so 
it's not a trust-boundary problem in the TIKA-4769 sense — but it's the kind of 
thing that's hard to
     rename later.
   
     Absence is ambiguous. Suppressing undelayed tracks means "no 
still-image-time.track-start-us" can't distinguish "still is the first frame" 
from "not a Live Photo."
     Emitting 0 for a declared-but-undelayed still-image-time track would be 
unambiguous, at the cost of noise on the other keys — which loops back to the 
per-key question.
   
     4. Test gaps
   
     The fixture is a hand-built .mov whose minf contains only stbl and whose 
stbl contains only stsd. Real QuickTime metadata tracks have gmhd, a 
data-reference hdlr
     (dhlr/alis), and dinf inside minf, plus stts/stsc/stsz/stco inside stbl. 
The test therefore never exercises the traversal as it will actually run — in 
particular that
     inner hdlr, which under the PR's approach now reaches super.processBox and 
gets handler-type-dispatched. It works (I checked: alis falls through), but the 
test wouldn't
     catch it if it stopped working.
   
     Nothing covers: an undelayed meta track producing no key (asserted in the 
PR body, untested), a version-1 elst, a non-leading empty edit, or a video 
track with a leading
     empty edit followed by a meta track without one (the state-leak path).
   
     Nits
   
     - The shouldAcceptContainer comment says timed metadata tracks have 
handler type mdta. They have meta — mdta is the moov/meta/hdlr metadata 
handler. The code's own hdlr
     check disagrees with the comment.
     - readInt64 is defined between boxType and addLocation, far from its only 
caller.
     - tikaMetadata.set(...) here vs tikaMetadata.add(...) on the ilst path — 
two delayed tracks declaring the same key silently overwrite.
     - The fixture change also adds mvhd and a trak to a file that previously 
had neither, so testQuickTimeMetadataKeys now additionally produces 
dcterms:created,
     xmpDM:duration, and xmpDM:audioSampleRate=600 (the last being a 
pre-existing MP4Parser quirk — it maps movie timescale to audio sample rate — 
not this PR's fault).
     Existing assertions still pass; just noting the fixture is no longer inert.
   
   ```




> Extract QuickTime timed metadata (mebx) tracks
> ----------------------------------------------
>
>                 Key: TIKA-4777
>                 URL: https://issues.apache.org/jira/browse/TIKA-4777
>             Project: Tika
>          Issue Type: Improvement
>            Reporter: Dominik Schmidt
>            Priority: Major
>
> Apple Live Photo videos mark the moment the paired still image was
> captured in a timed metadata track: the sample description declares the
> format 'mebx' with a keys structure containing
> com.apple.quicktime.still-image-time. The item value itself is always -1;
> the actual time is the presentation time of that sample, derived from the
> track's sample tables.
> Everything needed lives in the moov box, no mdat access is required:
> - mdhd: track timescale
> - stsd: detect the mebx sample entry and its still-image-time key
> - stts and elst: an empty edit shifts the single one-tick sample to the
>   still moment
> Example from a real Live Photo video (iPhone 15 Pro, iOS 18.5): the
> still-image-time track has timescale 600, an edit list with an empty edit
> of 740 units followed by the sample, giving a still time of 1.2333 s.
> Neither the current MP4 handler (which reads the static keys/ilst
> metadata, TIKA-2861) nor the underlying metadata-extractor exposes timed
> metadata tracks; ExifTool only surfaces the constant -1 marker value.
> Note that the Apple maker note tag 0x0017 in the paired image
> (historically documented as "LivePhotoVideoIndex") does not encode a
> usable time on current iOS versions, so the video track is the only
> reliable source for this timestamp.
> Proposal: extend TikaMp4BoxHandler to accept the relevant trak child
> boxes, correlate mdhd/stsd/stts/elst per track, and emit the still time
> as metadata (e.g. com.apple.quicktime.still-image-time, in
> microseconds).
> Related: TIKA-2861 (QuickTime item-list metadata), TIKA-4776 (image-side
> Apple maker note, LONG8), TIKA-852.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to