[16842] | 1 | #------------------------------------------------------------------------------
|
---|
| 2 | # File: QuickTime.pm
|
---|
| 3 | #
|
---|
| 4 | # Description: Read QuickTime, MP4 and M4A meta information
|
---|
| 5 | #
|
---|
| 6 | # Revisions: 10/04/2005 - P. Harvey Created
|
---|
| 7 | # 12/19/2005 - P. Harvey Added MP4 support
|
---|
| 8 | # 09/22/2006 - P. Harvey Added M4A support
|
---|
[24107] | 9 | # 07/27/2010 - P. Harvey Updated to 2010-05-03 QuickTime spec
|
---|
[16842] | 10 | #
|
---|
[24107] | 11 | # References: 1) http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html
|
---|
[16842] | 12 | # 2) http://search.cpan.org/dist/MP4-Info-1.04/
|
---|
| 13 | # 3) http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
|
---|
| 14 | # 4) http://wiki.multimedia.cx/index.php?title=Apple_QuickTime
|
---|
[24107] | 15 | # 5) ISO 14496-12 (http://neuron2.net/library/avc/c041828_ISO_IEC_14496-12_2005(E).pdf)
|
---|
| 16 | # 6) ISO 14496-16 (http://www.iec-normen.de/previewpdf/info_isoiec14496-16%7Bed2.0%7Den.pdf)
|
---|
| 17 | # 7) http://atomicparsley.sourceforge.net/mpeg-4files.html
|
---|
| 18 | # 8) http://wiki.multimedia.cx/index.php?title=QuickTime_container
|
---|
| 19 | # 9) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart3.pdf (Oct 2008)
|
---|
| 20 | # 10) http://code.google.com/p/mp4v2/wiki/iTunesMetadata
|
---|
| 21 | # 11) http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf
|
---|
| 22 | # 12) QuickTime file format specification 2010-05-03
|
---|
| 23 | # 13) http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf
|
---|
| 24 | # 14) http://standards.iso.org/ittf/PubliclyAvailableStandards/c051533_ISO_IEC_14496-12_2008.zip
|
---|
[16842] | 25 | #------------------------------------------------------------------------------
|
---|
| 26 |
|
---|
| 27 | package Image::ExifTool::QuickTime;
|
---|
| 28 |
|
---|
| 29 | use strict;
|
---|
| 30 | use vars qw($VERSION);
|
---|
| 31 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
| 32 | use Image::ExifTool::Exif;
|
---|
| 33 |
|
---|
[24107] | 34 | $VERSION = '1.48';
|
---|
[16842] | 35 |
|
---|
| 36 | sub FixWrongFormat($);
|
---|
| 37 | sub ProcessMOV($$;$);
|
---|
[24107] | 38 | sub ProcessKeys($$$);
|
---|
| 39 | sub ProcessMetaData($$$);
|
---|
| 40 | sub ConvertISO6709($);
|
---|
| 41 | sub PrintGPSCoordinates($);
|
---|
[16842] | 42 |
|
---|
| 43 | # information for time/date-based tags (time zero is Jan 1, 1904)
|
---|
| 44 | my %timeInfo = (
|
---|
| 45 | # Note: This value will be in UTC if generated by a system that is aware of the time zone
|
---|
| 46 | ValueConv => 'ConvertUnixTime($val - ((66 * 365 + 17) * 24 * 3600))',
|
---|
| 47 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
[24107] | 48 | # (can't put Groups here because they aren't constant!)
|
---|
[16842] | 49 | );
|
---|
| 50 | # information for duration tags
|
---|
| 51 | my %durationInfo = (
|
---|
[24107] | 52 | ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val',
|
---|
| 53 | PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val',
|
---|
[16842] | 54 | );
|
---|
| 55 |
|
---|
[24107] | 56 | # 4-character Vendor ID codes (ref PH)
|
---|
| 57 | my %vendorID = (
|
---|
| 58 | appl => 'Apple',
|
---|
| 59 | fe20 => 'Olympus (fe20)', # (FE200)
|
---|
| 60 | FFMP => 'FFmpeg',
|
---|
| 61 | 'GIC '=> 'General Imaging Co.',
|
---|
| 62 | kdak => 'Kodak',
|
---|
| 63 | KMPI => 'Konica-Minolta',
|
---|
| 64 | mino => 'Minolta',
|
---|
| 65 | niko => 'Nikon',
|
---|
| 66 | NIKO => 'Nikon',
|
---|
| 67 | olym => 'Olympus',
|
---|
| 68 | pana => 'Panasonic',
|
---|
| 69 | pent => 'Pentax',
|
---|
| 70 | pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115)
|
---|
| 71 | sany => 'Sanyo',
|
---|
| 72 | 'SMI '=> 'Sorenson Media Inc.',
|
---|
| 73 | ZORA => 'Zoran Corporation',
|
---|
| 74 | );
|
---|
| 75 |
|
---|
| 76 | # QuickTime data atom encodings for string types (ref 12)
|
---|
| 77 | my %stringEncoding = (
|
---|
| 78 | 1 => 'UTF8',
|
---|
| 79 | 2 => 'UTF16',
|
---|
| 80 | 3 => 'ShiftJIS',
|
---|
| 81 | 4 => 'UTF8',
|
---|
| 82 | 5 => 'UTF16',
|
---|
| 83 | );
|
---|
| 84 |
|
---|
| 85 | # MIME types for all entries in the ftypLookup with file extensions
|
---|
| 86 | # (defaults to 'video/mp4' if not found in this lookup)
|
---|
| 87 | my %mimeLookup = (
|
---|
| 88 | '3G2' => 'video/3gpp2',
|
---|
| 89 | '3GP' => 'video/3gpp',
|
---|
| 90 | DVB => 'video/vnd.dvb.file',
|
---|
| 91 | F4A => 'audio/mp4',
|
---|
| 92 | F4B => 'audio/mp4',
|
---|
| 93 | JP2 => 'image/jp2',
|
---|
| 94 | JPM => 'image/jpm',
|
---|
| 95 | JPX => 'image/jpx',
|
---|
| 96 | M4A => 'audio/mp4',
|
---|
| 97 | M4B => 'audio/mp4',
|
---|
| 98 | M4P => 'audio/mp4',
|
---|
| 99 | M4V => 'video/x-m4v',
|
---|
| 100 | MOV => 'video/quicktime',
|
---|
| 101 | MQV => 'video/quicktime',
|
---|
| 102 | );
|
---|
| 103 |
|
---|
| 104 | my %graphicsMode = (
|
---|
| 105 | # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html)
|
---|
| 106 | 0x00 => 'srcCopy',
|
---|
| 107 | 0x01 => 'srcOr',
|
---|
| 108 | 0x02 => 'srcXor',
|
---|
| 109 | 0x03 => 'srcBic',
|
---|
| 110 | 0x04 => 'notSrcCopy',
|
---|
| 111 | 0x05 => 'notSrcOr',
|
---|
| 112 | 0x06 => 'notSrcXor',
|
---|
| 113 | 0x07 => 'notSrcBic',
|
---|
| 114 | 0x08 => 'patCopy',
|
---|
| 115 | 0x09 => 'patOr',
|
---|
| 116 | 0x0a => 'patXor',
|
---|
| 117 | 0x0b => 'patBic',
|
---|
| 118 | 0x0c => 'notPatCopy',
|
---|
| 119 | 0x0d => 'notPatOr',
|
---|
| 120 | 0x0e => 'notPatXor',
|
---|
| 121 | 0x0f => 'notPatBic',
|
---|
| 122 | 0x20 => 'blend',
|
---|
| 123 | 0x21 => 'addPin',
|
---|
| 124 | 0x22 => 'addOver',
|
---|
| 125 | 0x23 => 'subPin',
|
---|
| 126 | 0x24 => 'transparent',
|
---|
| 127 | 0x25 => 'addMax',
|
---|
| 128 | 0x26 => 'subOver',
|
---|
| 129 | 0x27 => 'addMin',
|
---|
| 130 | 0x31 => 'grayishTextOr',
|
---|
| 131 | 0x32 => 'hilite',
|
---|
| 132 | 0x40 => 'ditherCopy',
|
---|
| 133 | # the following ref ISO/IEC 15444-3
|
---|
| 134 | 0x100 => 'Alpha',
|
---|
| 135 | 0x101 => 'White Alpha',
|
---|
| 136 | 0x102 => 'Pre-multiplied Black Alpha',
|
---|
| 137 | 0x110 => 'Component Alpha',
|
---|
| 138 | );
|
---|
| 139 |
|
---|
| 140 | # look up file type from ftyp atom type, with MIME type in comment if known
|
---|
| 141 | # (ref http://www.ftyps.com/)
|
---|
| 142 | my %ftypLookup = (
|
---|
| 143 | '3g2a' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0', # video/3gpp2
|
---|
| 144 | '3g2b' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0', # video/3gpp2
|
---|
| 145 | '3g2c' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0', # video/3gpp2
|
---|
| 146 | '3ge6' => '3GPP (.3GP) Release 6 MBMS Extended Presentations', # video/3gpp
|
---|
| 147 | '3ge7' => '3GPP (.3GP) Release 7 MBMS Extended Presentations', # video/3gpp
|
---|
| 148 | '3gg6' => '3GPP Release 6 General Profile', # video/3gpp
|
---|
| 149 | '3gp1' => '3GPP Media (.3GP) Release 1 (probably non-existent)', # video/3gpp
|
---|
| 150 | '3gp2' => '3GPP Media (.3GP) Release 2 (probably non-existent)', # video/3gpp
|
---|
| 151 | '3gp3' => '3GPP Media (.3GP) Release 3 (probably non-existent)', # video/3gpp
|
---|
| 152 | '3gp4' => '3GPP Media (.3GP) Release 4', # video/3gpp
|
---|
| 153 | '3gp5' => '3GPP Media (.3GP) Release 5', # video/3gpp
|
---|
| 154 | '3gp6' => '3GPP Media (.3GP) Release 6 Basic Profile', # video/3gpp
|
---|
| 155 | '3gp6' => '3GPP Media (.3GP) Release 6 Progressive Download', # video/3gpp
|
---|
| 156 | '3gp6' => '3GPP Media (.3GP) Release 6 Streaming Servers', # video/3gpp
|
---|
| 157 | '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers', # video/3gpp
|
---|
| 158 | 'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]', # video/mp4
|
---|
| 159 | 'CAEP' => 'Canon Digital Camera',
|
---|
| 160 | 'caqv' => 'Casio Digital Camera',
|
---|
| 161 | 'CDes' => 'Convergent Design',
|
---|
| 162 | 'da0a' => 'DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images',
|
---|
| 163 | 'da0b' => 'DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 164 | 'da1a' => 'DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images',
|
---|
| 165 | 'da1b' => 'DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 166 | 'da2a' => 'DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images',
|
---|
| 167 | 'da2b' => 'DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 168 | 'da3a' => 'DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images',
|
---|
| 169 | 'da3b' => 'DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 170 | 'dmb1' => 'DMB MAF supporting all the components defined in the specification',
|
---|
| 171 | 'dmpf' => 'Digital Media Project', # various
|
---|
| 172 | 'drc1' => 'Dirac (wavelet compression), encapsulated in ISO base media (MP4)',
|
---|
| 173 | 'dv1a' => 'DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS',
|
---|
| 174 | 'dv1b' => 'DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 175 | 'dv2a' => 'DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS',
|
---|
| 176 | 'dv2b' => 'DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 177 | 'dv3a' => 'DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS',
|
---|
| 178 | 'dv3b' => 'DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP',
|
---|
| 179 | 'dvr1' => 'DVB (.DVB) over RTP', # video/vnd.dvb.file
|
---|
| 180 | 'dvt1' => 'DVB (.DVB) over MPEG-2 Transport Stream', # video/vnd.dvb.file
|
---|
| 181 | 'F4A ' => 'Audio for Adobe Flash Player 9+ (.F4A)', # audio/mp4
|
---|
| 182 | 'F4B ' => 'Audio Book for Adobe Flash Player 9+ (.F4B)', # audio/mp4
|
---|
| 183 | 'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4
|
---|
| 184 | 'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4
|
---|
| 185 | 'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic
|
---|
| 186 | 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4
|
---|
| 187 | 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4
|
---|
| 188 | 'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2
|
---|
| 189 | 'JP20' => 'Unknown, from GPAC samples (prob non-existent)',
|
---|
| 190 | 'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm
|
---|
| 191 | 'jpx ' => 'JPEG 2000 with extensions (.JPX) [ISO 15444-2]', # image/jpx
|
---|
| 192 | 'KDDI' => '3GPP2 EZmovie for KDDI 3G cellphones', # video/3gpp2
|
---|
| 193 | 'M4A ' => 'Apple iTunes AAC-LC (.M4A) Audio', # audio/x-m4a
|
---|
| 194 | 'M4B ' => 'Apple iTunes AAC-LC (.M4B) Audio Book', # audio/mp4
|
---|
| 195 | 'M4P ' => 'Apple iTunes AAC-LC (.M4P) AES Protected Audio', # audio/mp4
|
---|
| 196 | 'M4V ' => 'Apple iTunes Video (.M4V) Video', # video/x-m4v
|
---|
| 197 | 'M4VH' => 'Apple TV (.M4V)', # video/x-m4v
|
---|
| 198 | 'M4VP' => 'Apple iPhone (.M4V)', # video/x-m4v
|
---|
| 199 | 'mj2s' => 'Motion JPEG 2000 [ISO 15444-3] Simple Profile', # video/mj2
|
---|
| 200 | 'mjp2' => 'Motion JPEG 2000 [ISO 15444-3] General Profile', # video/mj2
|
---|
| 201 | 'mmp4' => 'MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)', # video/mp4
|
---|
| 202 | 'mp21' => 'MPEG-21 [ISO/IEC 21000-9]', # various
|
---|
| 203 | 'mp41' => 'MP4 v1 [ISO 14496-1:ch13]', # video/mp4
|
---|
| 204 | 'mp42' => 'MP4 v2 [ISO 14496-14]', # video/mp4
|
---|
| 205 | 'mp71' => 'MP4 w/ MPEG-7 Metadata [per ISO 14496-12]', # various
|
---|
| 206 | 'MPPI' => 'Photo Player, MAF [ISO/IEC 23000-3]', # various
|
---|
| 207 | 'mqt ' => 'Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)', # video/quicktime
|
---|
| 208 | 'MSNV' => 'MPEG-4 (.MP4) for SonyPSP', # audio/mp4
|
---|
| 209 | 'NDAS' => 'MP4 v2 [ISO 14496-14] Nero Digital AAC Audio', # audio/mp4
|
---|
| 210 | 'NDSC' => 'MPEG-4 (.MP4) Nero Cinema Profile', # video/mp4
|
---|
| 211 | 'NDSH' => 'MPEG-4 (.MP4) Nero HDTV Profile', # video/mp4
|
---|
| 212 | 'NDSM' => 'MPEG-4 (.MP4) Nero Mobile Profile', # video/mp4
|
---|
| 213 | 'NDSP' => 'MPEG-4 (.MP4) Nero Portable Profile', # video/mp4
|
---|
| 214 | 'NDSS' => 'MPEG-4 (.MP4) Nero Standard Profile', # video/mp4
|
---|
| 215 | 'NDXC' => 'H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile', # video/mp4
|
---|
| 216 | 'NDXH' => 'H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile', # video/mp4
|
---|
| 217 | 'NDXM' => 'H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile', # video/mp4
|
---|
| 218 | 'NDXP' => 'H.264/MPEG-4 AVC (.MP4) Nero Portable Profile', # video/mp4
|
---|
| 219 | 'NDXS' => 'H.264/MPEG-4 AVC (.MP4) Nero Standard Profile', # video/mp4
|
---|
| 220 | 'odcf' => 'OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)', # various
|
---|
| 221 | 'opf2' => 'OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)',
|
---|
| 222 | 'opx2' => 'OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)',
|
---|
| 223 | 'pana' => 'Panasonic Digital Camera',
|
---|
| 224 | 'qt ' => 'Apple QuickTime (.MOV/QT)', # video/quicktime
|
---|
| 225 | 'ROSS' => 'Ross Video',
|
---|
| 226 | 'sdv ' => 'SD Memory Card Video', # various?
|
---|
| 227 | 'ssc1' => 'Samsung stereoscopic, single stream',
|
---|
| 228 | 'ssc2' => 'Samsung stereoscopic, dual stream',
|
---|
| 229 | );
|
---|
| 230 |
|
---|
[16842] | 231 | # QuickTime atoms
|
---|
| 232 | %Image::ExifTool::QuickTime::Main = (
|
---|
[24107] | 233 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 234 | GROUPS => { 2 => 'Video' },
|
---|
| 235 | NOTES => q{
|
---|
[24107] | 236 | The QuickTime format is used for many different types of audio, video and
|
---|
| 237 | image files. Exiftool extracts meta information from the UserData atom
|
---|
| 238 | (including some proprietary manufacturer-specific information), as well as
|
---|
| 239 | extracting various audio, video and image parameters. Tags with a question
|
---|
| 240 | mark after their name are not extracted unless the Unknown option is set.
|
---|
[16842] | 241 | },
|
---|
| 242 | free => { Unknown => 1, Binary => 1 },
|
---|
| 243 | skip => { Unknown => 1, Binary => 1 },
|
---|
| 244 | wide => { Unknown => 1, Binary => 1 },
|
---|
| 245 | ftyp => { #MP4
|
---|
[24107] | 246 | Name => 'FileType',
|
---|
| 247 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileType' },
|
---|
[16842] | 248 | },
|
---|
| 249 | pnot => {
|
---|
| 250 | Name => 'Preview',
|
---|
| 251 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Preview' },
|
---|
| 252 | },
|
---|
| 253 | PICT => {
|
---|
| 254 | Name => 'PreviewPICT',
|
---|
| 255 | Binary => 1,
|
---|
| 256 | },
|
---|
[24107] | 257 | pict => { #8
|
---|
| 258 | Name => 'PreviewPICT',
|
---|
| 259 | Binary => 1,
|
---|
| 260 | },
|
---|
[16842] | 261 | moov => {
|
---|
| 262 | Name => 'Movie',
|
---|
| 263 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' },
|
---|
| 264 | },
|
---|
[24107] | 265 | mdat => { Name => 'MovieData', Unknown => 1, Binary => 1 },
|
---|
| 266 | 'mdat-size' => {
|
---|
| 267 | Name => 'MovieDataSize',
|
---|
| 268 | Notes => q{
|
---|
| 269 | not a real tag ID, this tag represents the size of the 'mdat' data in bytes
|
---|
| 270 | and is used in the AvgBitrate calculation
|
---|
| 271 | },
|
---|
| 272 | },
|
---|
| 273 | junk => { Unknown => 1, Binary => 1 }, #8
|
---|
| 274 | uuid => [
|
---|
| 275 | { #9 (MP4 files)
|
---|
| 276 | Name => 'UUID-XMP',
|
---|
| 277 | Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/',
|
---|
| 278 | SubDirectory => {
|
---|
| 279 | TagTable => 'Image::ExifTool::XMP::Main',
|
---|
| 280 | Start => 16,
|
---|
| 281 | },
|
---|
| 282 | },
|
---|
| 283 | { #11 (MP4 files)
|
---|
| 284 | Name => 'UUID-PROF',
|
---|
| 285 | Condition => '$$valPt=~/^PROF!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
|
---|
| 286 | SubDirectory => {
|
---|
| 287 | TagTable => 'Image::ExifTool::QuickTime::Profile',
|
---|
| 288 | Start => 24, # uid(16) + version(1) + flags(3) + count(4)
|
---|
| 289 | },
|
---|
| 290 | },
|
---|
| 291 | { #PH (Flip MP4 files)
|
---|
| 292 | Name => 'UUID-Flip',
|
---|
| 293 | Condition => '$$valPt=~/\x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/',
|
---|
| 294 | SubDirectory => {
|
---|
| 295 | TagTable => 'Image::ExifTool::QuickTime::Flip',
|
---|
| 296 | Start => 16,
|
---|
| 297 | },
|
---|
| 298 | },
|
---|
| 299 | # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos
|
---|
| 300 | { #8
|
---|
| 301 | Name => 'UUID-Unknown',
|
---|
| 302 | Unknown => 1,
|
---|
| 303 | Binary => 1,
|
---|
| 304 | },
|
---|
| 305 | ],
|
---|
[16842] | 306 | );
|
---|
| 307 |
|
---|
[24107] | 308 | # MPEG-4 'ftyp' atom
|
---|
| 309 | # (ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html)
|
---|
| 310 | %Image::ExifTool::QuickTime::FileType = (
|
---|
| 311 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 312 | GROUPS => { 2 => 'Video' },
|
---|
| 313 | FORMAT => 'int32u',
|
---|
| 314 | 0 => {
|
---|
| 315 | Name => 'MajorBrand',
|
---|
| 316 | Format => 'undef[4]',
|
---|
| 317 | PrintConv => \%ftypLookup,
|
---|
| 318 | },
|
---|
| 319 | 1 => {
|
---|
| 320 | Name => 'MinorVersion',
|
---|
| 321 | Format => 'undef[4]',
|
---|
| 322 | ValueConv => 'sprintf("%x.%x.%x", unpack("nCC", $val))',
|
---|
| 323 | },
|
---|
| 324 | 2 => {
|
---|
| 325 | Name => 'CompatibleBrands',
|
---|
| 326 | Format => 'undef[$size-8]',
|
---|
| 327 | # ignore any entry with a null, and return others as a list
|
---|
| 328 | ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a',
|
---|
| 329 | },
|
---|
| 330 | );
|
---|
| 331 |
|
---|
[16842] | 332 | # atoms used in QTIF files
|
---|
| 333 | %Image::ExifTool::QuickTime::ImageFile = (
|
---|
[24107] | 334 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 335 | GROUPS => { 2 => 'Image' },
|
---|
| 336 | NOTES => 'Tags used in QTIF QuickTime Image Files.',
|
---|
| 337 | idsc => {
|
---|
| 338 | Name => 'ImageDescription',
|
---|
| 339 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ImageDesc' },
|
---|
| 340 | },
|
---|
| 341 | idat => {
|
---|
| 342 | Name => 'ImageData',
|
---|
| 343 | Binary => 1,
|
---|
| 344 | },
|
---|
| 345 | iicc => {
|
---|
| 346 | Name => 'ICC_Profile',
|
---|
| 347 | SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
|
---|
| 348 | },
|
---|
| 349 | );
|
---|
| 350 |
|
---|
| 351 | # image description data block
|
---|
| 352 | %Image::ExifTool::QuickTime::ImageDesc = (
|
---|
| 353 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 354 | GROUPS => { 2 => 'Image' },
|
---|
[24107] | 355 | FORMAT => 'int16u',
|
---|
| 356 | 2 => {
|
---|
| 357 | Name => 'CompressorID',
|
---|
| 358 | Format => 'string[4]',
|
---|
| 359 | # not very useful since this isn't a complete list and name is given below
|
---|
| 360 | # # ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
|
---|
| 361 | # PrintConv => {
|
---|
| 362 | # cvid => 'Cinepak',
|
---|
| 363 | # jpeg => 'JPEG',
|
---|
| 364 | # 'smc '=> 'Graphics',
|
---|
| 365 | # 'rle '=> 'Animation',
|
---|
| 366 | # rpza => 'Apple Video',
|
---|
| 367 | # kpcd => 'Kodak Photo CD',
|
---|
| 368 | # 'png '=> 'Portable Network Graphics',
|
---|
| 369 | # mjpa => 'Motion-JPEG (format A)',
|
---|
| 370 | # mjpb => 'Motion-JPEG (format B)',
|
---|
| 371 | # SVQ1 => 'Sorenson video, version 1',
|
---|
| 372 | # SVQ3 => 'Sorenson video, version 3',
|
---|
| 373 | # mp4v => 'MPEG-4 video',
|
---|
| 374 | # 'dvc '=> 'NTSC DV-25 video',
|
---|
| 375 | # dvcp => 'PAL DV-25 video',
|
---|
| 376 | # 'gif '=> 'Compuserve Graphics Interchange Format',
|
---|
| 377 | # h263 => 'H.263 video',
|
---|
| 378 | # tiff => 'Tagged Image File Format',
|
---|
| 379 | # 'raw '=> 'Uncompressed RGB',
|
---|
| 380 | # '2vuY'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (2vuY)",
|
---|
| 381 | # 'yuv2'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (yuv2)",
|
---|
| 382 | # v308 => "Uncompressed Y'CbCr, 8-bit 4:4:4",
|
---|
| 383 | # v408 => "Uncompressed Y'CbCr, 8-bit 4:4:4:4",
|
---|
| 384 | # v216 => "Uncompressed Y'CbCr, 10, 12, 14, or 16-bit 4:2:2",
|
---|
| 385 | # v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4",
|
---|
| 386 | # v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2",
|
---|
| 387 | # },
|
---|
| 388 | },
|
---|
| 389 | 10 => {
|
---|
| 390 | Name => 'VendorID',
|
---|
| 391 | Format => 'string[4]',
|
---|
| 392 | RawConv => 'length $val ? $val : undef',
|
---|
| 393 | PrintConv => \%vendorID,
|
---|
| 394 | SeparateTable => 'VendorID',
|
---|
| 395 | },
|
---|
| 396 | # 14 - ("Quality" in QuickTime docs) ??
|
---|
| 397 | 16 => 'SourceImageWidth',
|
---|
| 398 | 17 => 'SourceImageHeight',
|
---|
| 399 | 18 => { Name => 'XResolution', Format => 'fixed32u' },
|
---|
| 400 | 20 => { Name => 'YResolution', Format => 'fixed32u' },
|
---|
| 401 | # 24 => 'FrameCount', # always 1 (what good is this?)
|
---|
| 402 | 25 => {
|
---|
| 403 | Name => 'CompressorName',
|
---|
| 404 | Format => 'string[32]',
|
---|
| 405 | # (sometimes this is a Pascal string, and sometimes it is a C string)
|
---|
| 406 | RawConv => q{
|
---|
| 407 | $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val);
|
---|
| 408 | length $val ? $val : undef;
|
---|
| 409 | },
|
---|
| 410 | },
|
---|
| 411 | 41 => 'BitDepth',
|
---|
[16842] | 412 | );
|
---|
| 413 |
|
---|
| 414 | # preview data block
|
---|
| 415 | %Image::ExifTool::QuickTime::Preview = (
|
---|
| 416 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 417 | GROUPS => { 2 => 'Image' },
|
---|
| 418 | FORMAT => 'int16u',
|
---|
| 419 | 0 => {
|
---|
| 420 | Name => 'PreviewDate',
|
---|
| 421 | Format => 'int32u',
|
---|
[24107] | 422 | Groups => { 2 => 'Time' },
|
---|
[16842] | 423 | %timeInfo,
|
---|
| 424 | },
|
---|
| 425 | 2 => 'PreviewVersion',
|
---|
| 426 | 3 => {
|
---|
| 427 | Name => 'PreviewAtomType',
|
---|
| 428 | Format => 'string[4]',
|
---|
| 429 | },
|
---|
| 430 | 5 => 'PreviewAtomIndex',
|
---|
| 431 | );
|
---|
| 432 |
|
---|
| 433 | # movie atoms
|
---|
| 434 | %Image::ExifTool::QuickTime::Movie = (
|
---|
[24107] | 435 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 436 | GROUPS => { 2 => 'Video' },
|
---|
| 437 | mvhd => {
|
---|
| 438 | Name => 'MovieHeader',
|
---|
[24107] | 439 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieHeader' },
|
---|
[16842] | 440 | },
|
---|
| 441 | trak => {
|
---|
| 442 | Name => 'Track',
|
---|
| 443 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' },
|
---|
| 444 | },
|
---|
| 445 | udta => {
|
---|
| 446 | Name => 'UserData',
|
---|
| 447 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
|
---|
| 448 | },
|
---|
[24107] | 449 | meta => { # 'meta' is found here in my EX-F1 MOV sample - PH
|
---|
| 450 | Name => 'Meta',
|
---|
| 451 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
|
---|
| 452 | },
|
---|
| 453 | iods => {
|
---|
| 454 | Name => 'InitialObjectDescriptor',
|
---|
| 455 | Flags => ['Binary','Unknown'],
|
---|
| 456 | },
|
---|
| 457 | uuid => [
|
---|
| 458 | { #11 (MP4 files) (also found in QuickTime::Track)
|
---|
| 459 | Name => 'UUID-USMT',
|
---|
| 460 | Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
|
---|
| 461 | SubDirectory => {
|
---|
| 462 | TagTable => 'Image::ExifTool::QuickTime::UserMedia',
|
---|
| 463 | Start => 16,
|
---|
| 464 | },
|
---|
| 465 | },
|
---|
| 466 | {
|
---|
| 467 | Name => 'UUID-Unknown',
|
---|
| 468 | Unknown => 1,
|
---|
| 469 | Binary => 1,
|
---|
| 470 | },
|
---|
| 471 | ],
|
---|
| 472 | # prfl - Profile (ref 12)
|
---|
| 473 | # clip - clipping --> contains crgn (clip region) (ref 12)
|
---|
| 474 | # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14)
|
---|
[16842] | 475 | );
|
---|
| 476 |
|
---|
| 477 | # movie header data block
|
---|
[24107] | 478 | %Image::ExifTool::QuickTime::MovieHeader = (
|
---|
[16842] | 479 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 480 | GROUPS => { 2 => 'Video' },
|
---|
| 481 | FORMAT => 'int32u',
|
---|
[24107] | 482 | 0 => {
|
---|
| 483 | Name => 'MovieHeaderVersion',
|
---|
| 484 | Format => 'int8u',
|
---|
| 485 | RawConv => '$$self{MovieHeaderVersion} = $val',
|
---|
| 486 | },
|
---|
[16842] | 487 | 1 => {
|
---|
| 488 | Name => 'CreateDate',
|
---|
[24107] | 489 | Groups => { 2 => 'Time' },
|
---|
[16842] | 490 | %timeInfo,
|
---|
[24107] | 491 | # this is int64u if MovieHeaderVersion == 1 (ref 13)
|
---|
| 492 | Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
[16842] | 493 | },
|
---|
| 494 | 2 => {
|
---|
| 495 | Name => 'ModifyDate',
|
---|
[24107] | 496 | Groups => { 2 => 'Time' },
|
---|
[16842] | 497 | %timeInfo,
|
---|
[24107] | 498 | # this is int64u if MovieHeaderVersion == 1 (ref 13)
|
---|
| 499 | Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
[16842] | 500 | },
|
---|
| 501 | 3 => {
|
---|
| 502 | Name => 'TimeScale',
|
---|
[24107] | 503 | RawConv => '$$self{TimeScale} = $val',
|
---|
[16842] | 504 | },
|
---|
[24107] | 505 | 4 => {
|
---|
| 506 | Name => 'Duration',
|
---|
| 507 | %durationInfo,
|
---|
| 508 | # this is int64u if MovieHeaderVersion == 1 (ref 13)
|
---|
| 509 | Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
| 510 | },
|
---|
[16842] | 511 | 5 => {
|
---|
| 512 | Name => 'PreferredRate',
|
---|
| 513 | ValueConv => '$val / 0x10000',
|
---|
| 514 | },
|
---|
| 515 | 6 => {
|
---|
| 516 | Name => 'PreferredVolume',
|
---|
| 517 | Format => 'int16u',
|
---|
| 518 | ValueConv => '$val / 256',
|
---|
| 519 | PrintConv => 'sprintf("%.2f%%", $val * 100)',
|
---|
| 520 | },
|
---|
[24107] | 521 | 9 => {
|
---|
| 522 | Name => 'MatrixStructure',
|
---|
| 523 | Format => 'fixed32s[9]',
|
---|
| 524 | # (the right column is fixed 2.30 instead of 16.16)
|
---|
| 525 | ValueConv => q{
|
---|
| 526 | my @a = split ' ',$val;
|
---|
| 527 | $_ /= 0x4000 foreach @a[2,5,8];
|
---|
| 528 | return "@a";
|
---|
| 529 | },
|
---|
| 530 | },
|
---|
[16842] | 531 | 18 => { Name => 'PreviewTime', %durationInfo },
|
---|
| 532 | 19 => { Name => 'PreviewDuration', %durationInfo },
|
---|
| 533 | 20 => { Name => 'PosterTime', %durationInfo },
|
---|
| 534 | 21 => { Name => 'SelectionTime', %durationInfo },
|
---|
| 535 | 22 => { Name => 'SelectionDuration',%durationInfo },
|
---|
| 536 | 23 => { Name => 'CurrentTime', %durationInfo },
|
---|
| 537 | 24 => 'NextTrackID',
|
---|
| 538 | );
|
---|
| 539 |
|
---|
| 540 | # track atoms
|
---|
| 541 | %Image::ExifTool::QuickTime::Track = (
|
---|
[24107] | 542 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 543 | GROUPS => { 2 => 'Video' },
|
---|
| 544 | tkhd => {
|
---|
| 545 | Name => 'TrackHeader',
|
---|
[24107] | 546 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackHeader' },
|
---|
[16842] | 547 | },
|
---|
| 548 | udta => {
|
---|
| 549 | Name => 'UserData',
|
---|
| 550 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
|
---|
| 551 | },
|
---|
| 552 | mdia => { #MP4
|
---|
| 553 | Name => 'Media',
|
---|
| 554 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Media' },
|
---|
| 555 | },
|
---|
[24107] | 556 | meta => { #PH (MOV)
|
---|
| 557 | Name => 'Meta',
|
---|
| 558 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
|
---|
| 559 | },
|
---|
| 560 | tref => {
|
---|
| 561 | Name => 'TrackRef',
|
---|
| 562 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackRef' },
|
---|
| 563 | },
|
---|
| 564 | uuid => [
|
---|
| 565 | { #11 (MP4 files) (also found in QuickTime::Movie)
|
---|
| 566 | Name => 'UUID-USMT',
|
---|
| 567 | Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
|
---|
| 568 | SubDirectory => {
|
---|
| 569 | TagTable => 'Image::ExifTool::QuickTime::UserMedia',
|
---|
| 570 | Start => 16,
|
---|
| 571 | },
|
---|
| 572 | },
|
---|
| 573 | {
|
---|
| 574 | Name => 'UUID-Unknown',
|
---|
| 575 | Unknown => 1,
|
---|
| 576 | Binary => 1,
|
---|
| 577 | },
|
---|
| 578 | ],
|
---|
| 579 | # edts - edits --> contains elst (edit list)
|
---|
| 580 | # tapt - TrackApertureModeDimensionsAID --> contains clef (TrackCleanApertureDimensionsAID),
|
---|
| 581 | # prof (TrackProductionApertureDimensionsAID), enof (TrackEncodedPixelsDimensionsAID)
|
---|
| 582 | # clip - clipping --> contains crgn (clip region)
|
---|
| 583 | # matt - track matt --> contains kmat (compressed matt)
|
---|
| 584 | # load - track loading settings
|
---|
| 585 | # imap - track input map --> contains ' in' --> contains ' ty', obid
|
---|
| 586 | # prfl - Profile (ref 12)
|
---|
[16842] | 587 | );
|
---|
| 588 |
|
---|
| 589 | # track header data block
|
---|
[24107] | 590 | %Image::ExifTool::QuickTime::TrackHeader = (
|
---|
[16842] | 591 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 592 | GROUPS => { 1 => 'Track#', 2 => 'Video' },
|
---|
| 593 | FORMAT => 'int32u',
|
---|
| 594 | 0 => {
|
---|
[24107] | 595 | Name => 'TrackHeaderVersion',
|
---|
[16842] | 596 | Format => 'int8u',
|
---|
| 597 | Priority => 0,
|
---|
[24107] | 598 | RawConv => '$$self{TrackHeaderVersion} = $val',
|
---|
[16842] | 599 | },
|
---|
| 600 | 1 => {
|
---|
| 601 | Name => 'TrackCreateDate',
|
---|
| 602 | Priority => 0,
|
---|
[24107] | 603 | Groups => { 2 => 'Time' },
|
---|
[16842] | 604 | %timeInfo,
|
---|
[24107] | 605 | # this is int64u if TrackHeaderVersion == 1 (ref 13)
|
---|
| 606 | Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
[16842] | 607 | },
|
---|
| 608 | 2 => {
|
---|
| 609 | Name => 'TrackModifyDate',
|
---|
| 610 | Priority => 0,
|
---|
[24107] | 611 | Groups => { 2 => 'Time' },
|
---|
[16842] | 612 | %timeInfo,
|
---|
[24107] | 613 | # this is int64u if TrackHeaderVersion == 1 (ref 13)
|
---|
| 614 | Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
[16842] | 615 | },
|
---|
| 616 | 3 => {
|
---|
| 617 | Name => 'TrackID',
|
---|
| 618 | Priority => 0,
|
---|
| 619 | },
|
---|
| 620 | 5 => {
|
---|
| 621 | Name => 'TrackDuration',
|
---|
| 622 | Priority => 0,
|
---|
| 623 | %durationInfo,
|
---|
[24107] | 624 | # this is int64u if TrackHeaderVersion == 1 (ref 13)
|
---|
| 625 | Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
[16842] | 626 | },
|
---|
| 627 | 8 => {
|
---|
| 628 | Name => 'TrackLayer',
|
---|
| 629 | Format => 'int16u',
|
---|
| 630 | Priority => 0,
|
---|
| 631 | },
|
---|
| 632 | 9 => {
|
---|
| 633 | Name => 'TrackVolume',
|
---|
| 634 | Format => 'int16u',
|
---|
| 635 | Priority => 0,
|
---|
| 636 | ValueConv => '$val / 256',
|
---|
| 637 | PrintConv => 'sprintf("%.2f%%", $val * 100)',
|
---|
| 638 | },
|
---|
[24107] | 639 | 10 => {
|
---|
| 640 | Name => 'MatrixStructure',
|
---|
| 641 | Format => 'fixed32s[9]',
|
---|
| 642 | # (the right column is fixed 2.30 instead of 16.16)
|
---|
| 643 | ValueConv => q{
|
---|
| 644 | my @a = split ' ',$val;
|
---|
| 645 | $_ /= 0x4000 foreach @a[2,5,8];
|
---|
| 646 | return "@a";
|
---|
| 647 | },
|
---|
| 648 | },
|
---|
[16842] | 649 | 19 => {
|
---|
| 650 | Name => 'ImageWidth',
|
---|
| 651 | Priority => 0,
|
---|
| 652 | RawConv => \&FixWrongFormat,
|
---|
| 653 | },
|
---|
| 654 | 20 => {
|
---|
| 655 | Name => 'ImageHeight',
|
---|
| 656 | Priority => 0,
|
---|
| 657 | RawConv => \&FixWrongFormat,
|
---|
| 658 | },
|
---|
| 659 | );
|
---|
| 660 |
|
---|
| 661 | # user data atoms
|
---|
| 662 | %Image::ExifTool::QuickTime::UserData = (
|
---|
[24107] | 663 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 664 | GROUPS => { 2 => 'Video' },
|
---|
| 665 | NOTES => q{
|
---|
| 666 | Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language
|
---|
[24107] | 667 | text. Alternate language tags are accessed by adding a dash followed by the
|
---|
| 668 | language/country code to the tag name. ExifTool will extract any
|
---|
| 669 | multi-language user data tags found, even if they don't exist in this table.
|
---|
[16842] | 670 | },
|
---|
[24107] | 671 | "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } },
|
---|
| 672 | "\xa9day" => {
|
---|
| 673 | Name => 'CreateDate',
|
---|
| 674 | Groups => { 2 => 'Time' },
|
---|
| 675 | # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone)
|
---|
| 676 | ValueConv => q{
|
---|
| 677 | require Image::ExifTool::XMP;
|
---|
| 678 | $val = Image::ExifTool::XMP::ConvertXMPDate($val);
|
---|
| 679 | $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
|
---|
| 680 | return $val;
|
---|
| 681 | },
|
---|
| 682 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
| 683 | },
|
---|
| 684 | "\xa9ART" => 'Artist', #PH (iTunes 8.0.2)
|
---|
| 685 | "\xa9alb" => 'Album', #PH (iTunes 8.0.2)
|
---|
| 686 | "\xa9arg" => 'Arranger', #12
|
---|
| 687 | "\xa9ark" => 'ArrangerKeywords', #12
|
---|
| 688 | "\xa9cmt" => 'Comment', #PH (iTunes 8.0.2)
|
---|
| 689 | "\xa9cok" => 'ComposerKeywords', #12
|
---|
| 690 | "\xa9com" => 'Composer', #12
|
---|
| 691 | "\xa9dir" => 'Director', #12
|
---|
[16842] | 692 | "\xa9ed1" => 'Edit1',
|
---|
| 693 | "\xa9ed2" => 'Edit2',
|
---|
| 694 | "\xa9ed3" => 'Edit3',
|
---|
| 695 | "\xa9ed4" => 'Edit4',
|
---|
| 696 | "\xa9ed5" => 'Edit5',
|
---|
| 697 | "\xa9ed6" => 'Edit6',
|
---|
| 698 | "\xa9ed7" => 'Edit7',
|
---|
| 699 | "\xa9ed8" => 'Edit8',
|
---|
| 700 | "\xa9ed9" => 'Edit9',
|
---|
| 701 | "\xa9fmt" => 'Format',
|
---|
[24107] | 702 | "\xa9gen" => 'Genre', #PH (iTunes 8.0.2)
|
---|
| 703 | "\xa9grp" => 'Grouping', #PH (NC)
|
---|
[16842] | 704 | "\xa9inf" => 'Information',
|
---|
[24107] | 705 | "\xa9isr" => 'ISRCCode', #12
|
---|
| 706 | "\xa9lab" => 'RecordLabelName', #12
|
---|
| 707 | "\xa9lal" => 'RecordLabelURL', #12
|
---|
| 708 | "\xa9lyr" => 'Lyrics', #PH (NC)
|
---|
| 709 | "\xa9mak" => 'Make', #12
|
---|
| 710 | "\xa9mal" => 'MakerURL', #12
|
---|
| 711 | "\xa9mod" => 'Model', #PH
|
---|
| 712 | "\xa9nam" => 'Title', #12
|
---|
| 713 | "\xa9pdk" => 'ProducerKeywords', #12
|
---|
| 714 | "\xa9phg" => 'RecordingCopyright', #12
|
---|
[16842] | 715 | "\xa9prd" => 'Producer',
|
---|
| 716 | "\xa9prf" => 'Performers',
|
---|
[24107] | 717 | "\xa9prk" => 'PerformerKeywords', #12
|
---|
| 718 | "\xa9prl" => 'PerformerURL',
|
---|
| 719 | "\xa9dir" => 'Director', #12
|
---|
[16842] | 720 | "\xa9req" => 'Requirements',
|
---|
[24107] | 721 | "\xa9snk" => 'SubtitleKeywords', #12
|
---|
| 722 | "\xa9snm" => 'Subtitle', #12
|
---|
| 723 | "\xa9src" => 'SourceCredits', #12
|
---|
| 724 | "\xa9swf" => 'SongWriter', #12
|
---|
| 725 | "\xa9swk" => 'SongWriterKeywords', #12
|
---|
| 726 | "\xa9swr" => 'SoftwareVersion', #12
|
---|
| 727 | "\xa9too" => 'Encoder', #PH (NC)
|
---|
| 728 | "\xa9trk" => 'Track', #PH (NC)
|
---|
| 729 | "\xa9wrt" => 'Composer',
|
---|
| 730 | "\xa9xyz" => { #PH (iPhone 3GS)
|
---|
| 731 | Name => 'GPSCoordinates',
|
---|
| 732 | Groups => { 2 => 'Location' },
|
---|
| 733 | ValueConv => \&ConvertISO6709,
|
---|
| 734 | PrintConv => \&PrintGPSCoordinates,
|
---|
| 735 | },
|
---|
[16842] | 736 | name => 'Name',
|
---|
| 737 | WLOC => {
|
---|
| 738 | Name => 'WindowLocation',
|
---|
| 739 | Format => 'int16u',
|
---|
| 740 | },
|
---|
| 741 | LOOP => {
|
---|
| 742 | Name => 'LoopStyle',
|
---|
| 743 | Format => 'int32u',
|
---|
| 744 | PrintConv => {
|
---|
| 745 | 1 => 'Normal',
|
---|
| 746 | 2 => 'Palindromic',
|
---|
| 747 | },
|
---|
| 748 | },
|
---|
| 749 | SelO => {
|
---|
| 750 | Name => 'PlaySelection',
|
---|
| 751 | Format => 'int8u',
|
---|
| 752 | },
|
---|
| 753 | AllF => {
|
---|
| 754 | Name => 'PlayAllFrames',
|
---|
| 755 | Format => 'int8u',
|
---|
| 756 | },
|
---|
| 757 | meta => {
|
---|
| 758 | Name => 'Meta',
|
---|
| 759 | SubDirectory => {
|
---|
| 760 | TagTable => 'Image::ExifTool::QuickTime::Meta',
|
---|
[24107] | 761 | Start => 4, # must skip 4-byte version number header
|
---|
[16842] | 762 | },
|
---|
| 763 | },
|
---|
[24107] | 764 | DcMD => {
|
---|
| 765 | Name => 'DcMD',
|
---|
| 766 | SubDirectory => {
|
---|
| 767 | TagTable => 'Image::ExifTool::QuickTime::DcMD',
|
---|
| 768 | },
|
---|
| 769 | },
|
---|
[16842] | 770 | 'ptv '=> {
|
---|
| 771 | Name => 'PrintToVideo',
|
---|
| 772 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' },
|
---|
| 773 | },
|
---|
[24107] | 774 | 'hnti'=> {
|
---|
| 775 | Name => 'HintInfo',
|
---|
| 776 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintInfo' },
|
---|
| 777 | },
|
---|
| 778 | 'hinf' => {
|
---|
| 779 | Name => 'HintTrackInfo',
|
---|
| 780 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintTrackInfo' },
|
---|
| 781 | },
|
---|
| 782 | TAGS => [ #PH
|
---|
| 783 | # these tags were initially discovered in a Pentax movie,
|
---|
| 784 | # but similar information is found in videos from other manufacturers
|
---|
[16842] | 785 | {
|
---|
[24107] | 786 | Name => 'KodakTags',
|
---|
| 787 | Condition => '$$valPt =~ /^EASTMAN KODAK COMPANY/',
|
---|
[16842] | 788 | SubDirectory => {
|
---|
[24107] | 789 | TagTable => 'Image::ExifTool::Kodak::MOV',
|
---|
[16842] | 790 | ByteOrder => 'LittleEndian',
|
---|
| 791 | },
|
---|
| 792 | },
|
---|
| 793 | {
|
---|
[24107] | 794 | Name => 'KonicaMinoltaTags',
|
---|
| 795 | Condition => '$$valPt =~ /^KONICA MINOLTA DIGITAL CAMERA/',
|
---|
| 796 | SubDirectory => {
|
---|
| 797 | TagTable => 'Image::ExifTool::Minolta::MOV1',
|
---|
| 798 | ByteOrder => 'LittleEndian',
|
---|
| 799 | },
|
---|
| 800 | },
|
---|
| 801 | {
|
---|
| 802 | Name => 'MinoltaTags',
|
---|
| 803 | Condition => '$$valPt =~ /^MINOLTA DIGITAL CAMERA/',
|
---|
| 804 | SubDirectory => {
|
---|
| 805 | TagTable => 'Image::ExifTool::Minolta::MOV2',
|
---|
| 806 | ByteOrder => 'LittleEndian',
|
---|
| 807 | },
|
---|
| 808 | },
|
---|
| 809 | {
|
---|
[16842] | 810 | Name => 'NikonTags',
|
---|
| 811 | Condition => '$$valPt =~ /^NIKON DIGITAL CAMERA\0/',
|
---|
| 812 | SubDirectory => {
|
---|
| 813 | TagTable => 'Image::ExifTool::Nikon::MOV',
|
---|
| 814 | ByteOrder => 'LittleEndian',
|
---|
| 815 | },
|
---|
| 816 | },
|
---|
| 817 | {
|
---|
[24107] | 818 | Name => 'OlympusTags1',
|
---|
| 819 | Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0.{9}\x01\0/s',
|
---|
| 820 | SubDirectory => {
|
---|
| 821 | TagTable => 'Image::ExifTool::Olympus::MOV1',
|
---|
| 822 | ByteOrder => 'LittleEndian',
|
---|
| 823 | },
|
---|
| 824 | },
|
---|
| 825 | {
|
---|
| 826 | Name => 'OlympusTags2',
|
---|
| 827 | Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA(?!\0.{21}\x0a\0{3})/s',
|
---|
| 828 | SubDirectory => {
|
---|
| 829 | TagTable => 'Image::ExifTool::Olympus::MOV2',
|
---|
| 830 | ByteOrder => 'LittleEndian',
|
---|
| 831 | },
|
---|
| 832 | },
|
---|
| 833 | {
|
---|
| 834 | Name => 'OlympusTags3',
|
---|
| 835 | Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0/',
|
---|
| 836 | SubDirectory => {
|
---|
| 837 | TagTable => 'Image::ExifTool::Olympus::MP4',
|
---|
| 838 | ByteOrder => 'LittleEndian',
|
---|
| 839 | },
|
---|
| 840 | },
|
---|
| 841 | {
|
---|
| 842 | Name => 'PentaxTags',
|
---|
| 843 | Condition => '$$valPt =~ /^PENTAX DIGITAL CAMERA\0/',
|
---|
| 844 | SubDirectory => {
|
---|
| 845 | TagTable => 'Image::ExifTool::Pentax::MOV',
|
---|
| 846 | ByteOrder => 'LittleEndian',
|
---|
| 847 | },
|
---|
| 848 | },
|
---|
| 849 | {
|
---|
| 850 | Name => 'SamsungTags',
|
---|
| 851 | Condition => '$$valPt =~ /^SAMSUNG DIGITAL CAMERA\0/',
|
---|
| 852 | SubDirectory => {
|
---|
| 853 | TagTable => 'Image::ExifTool::Samsung::MP4',
|
---|
| 854 | ByteOrder => 'LittleEndian',
|
---|
| 855 | },
|
---|
| 856 | },
|
---|
| 857 | {
|
---|
[16842] | 858 | Name => 'SanyoMOV',
|
---|
| 859 | Condition => q{
|
---|
| 860 | $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
|
---|
| 861 | $self->{VALUE}->{FileType} eq "MOV"
|
---|
| 862 | },
|
---|
| 863 | SubDirectory => {
|
---|
| 864 | TagTable => 'Image::ExifTool::Sanyo::MOV',
|
---|
| 865 | ByteOrder => 'LittleEndian',
|
---|
| 866 | },
|
---|
| 867 | },
|
---|
| 868 | {
|
---|
| 869 | Name => 'SanyoMP4',
|
---|
| 870 | Condition => q{
|
---|
| 871 | $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
|
---|
| 872 | $self->{VALUE}->{FileType} eq "MP4"
|
---|
| 873 | },
|
---|
| 874 | SubDirectory => {
|
---|
| 875 | TagTable => 'Image::ExifTool::Sanyo::MP4',
|
---|
| 876 | ByteOrder => 'LittleEndian',
|
---|
| 877 | },
|
---|
| 878 | },
|
---|
| 879 | {
|
---|
| 880 | Name => 'UnknownTags',
|
---|
| 881 | Unknown => 1,
|
---|
| 882 | Binary => 1
|
---|
| 883 | },
|
---|
| 884 | ],
|
---|
[24107] | 885 | NCDT => { #PH
|
---|
| 886 | Name => 'NikonNCDT',
|
---|
| 887 | SubDirectory => {
|
---|
| 888 | TagTable => 'Image::ExifTool::Nikon::NCDT',
|
---|
| 889 | ProcessProc => \&ProcessMOV,
|
---|
| 890 | },
|
---|
| 891 | },
|
---|
| 892 | QVMI => { #PH
|
---|
| 893 | Name => 'CasioQVMI',
|
---|
| 894 | # Casio stores standard EXIF-format information in MOV videos (ie. EX-S880)
|
---|
| 895 | SubDirectory => {
|
---|
| 896 | TagTable => 'Image::ExifTool::Exif::Main',
|
---|
| 897 | DirName => 'IFD0',
|
---|
| 898 | Multi => 0, # (no NextIFD pointer)
|
---|
| 899 | Start => 10,
|
---|
| 900 | ByteOrder => 'BigEndian',
|
---|
| 901 | },
|
---|
| 902 | },
|
---|
| 903 | MMA0 => { #PH (DiMage 7Hi)
|
---|
| 904 | Name => 'MinoltaMMA0',
|
---|
| 905 | SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' },
|
---|
| 906 | },
|
---|
| 907 | MMA1 => { #PH (Dimage A2)
|
---|
| 908 | Name => 'MinoltaMMA1',
|
---|
| 909 | SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' },
|
---|
| 910 | },
|
---|
| 911 | XMP_ => { #PH (Adobe CS3 Bridge)
|
---|
| 912 | Name => 'XMP',
|
---|
| 913 | SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
---|
| 914 | },
|
---|
| 915 | vndr => 'Vendor', #PH (Samsung PL70)
|
---|
| 916 | SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
|
---|
| 917 | # Canon tags
|
---|
| 918 | CNCV => 'CompressorVersion', #PH (5D Mark II)
|
---|
| 919 | CNMN => 'Model', #PH (EOS 550D)
|
---|
| 920 | CNFV => 'FirmwareVersion', #PH (EOS 550D)
|
---|
| 921 | CNTH => { #PH (PowerShot S95)
|
---|
| 922 | Name => 'CanonCNTH',
|
---|
| 923 | SubDirectory => {
|
---|
| 924 | TagTable => 'Image::ExifTool::Canon::CNTH',
|
---|
| 925 | ProcessProc => \&ProcessMOV,
|
---|
| 926 | },
|
---|
| 927 | },
|
---|
| 928 | # CNDB - 2112 bytes (550D)
|
---|
| 929 | # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95)
|
---|
| 930 | INFO => {
|
---|
| 931 | Name => 'SamsungINFO',
|
---|
| 932 | SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' },
|
---|
| 933 | },
|
---|
| 934 | FFMV => { #PH (FinePix HS20EXR)
|
---|
| 935 | Name => 'FujiFilmFFMV',
|
---|
| 936 | SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FFMV' },
|
---|
| 937 | },
|
---|
| 938 | MVTG => { #PH (FinePix HS20EXR)
|
---|
| 939 | Name => 'FujiFilmMVTG',
|
---|
| 940 | SubDirectory => {
|
---|
| 941 | TagTable => 'Image::ExifTool::Exif::Main',
|
---|
| 942 | DirName => 'IFD0',
|
---|
| 943 | Start => 16,
|
---|
| 944 | Base => '$start',
|
---|
| 945 | ByteOrder => 'LittleEndian',
|
---|
| 946 | },
|
---|
| 947 | },
|
---|
[16842] | 948 | );
|
---|
| 949 |
|
---|
[24107] | 950 | # User-specific media data atoms (ref 11)
|
---|
| 951 | %Image::ExifTool::QuickTime::UserMedia = (
|
---|
| 952 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 953 | GROUPS => { 2 => 'Video' },
|
---|
| 954 | MTDT => {
|
---|
| 955 | Name => 'MetaData',
|
---|
| 956 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaData' },
|
---|
| 957 | },
|
---|
| 958 | );
|
---|
| 959 |
|
---|
| 960 | # User-specific media data atoms (ref 11)
|
---|
| 961 | %Image::ExifTool::QuickTime::MetaData = (
|
---|
| 962 | PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMetaData,
|
---|
| 963 | GROUPS => { 2 => 'Video' },
|
---|
| 964 | TAG_PREFIX => 'MetaData',
|
---|
| 965 | 0x01 => 'Title',
|
---|
| 966 | 0x03 => {
|
---|
| 967 | Name => 'ProductionDate',
|
---|
| 968 | Groups => { 2 => 'Time' },
|
---|
| 969 | # translate from format "YYYY/mm/dd HH:MM:SS"
|
---|
| 970 | ValueConv => '$val=~tr{/}{:}; $val',
|
---|
| 971 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
| 972 | },
|
---|
| 973 | 0x04 => 'Software',
|
---|
| 974 | 0x05 => 'Product',
|
---|
| 975 | 0x0a => {
|
---|
| 976 | Name => 'TrackProperty',
|
---|
| 977 | RawConv => 'my @a=unpack("Nnn",$val); "@a"',
|
---|
| 978 | PrintConv => [
|
---|
| 979 | { 0 => 'No presentation', BITMASK => { 0 => 'Main track' } },
|
---|
| 980 | { 0 => 'No attributes', BITMASK => { 15 => 'Read only' } },
|
---|
| 981 | '"Priority $val"',
|
---|
| 982 | ],
|
---|
| 983 | },
|
---|
| 984 | 0x0b => {
|
---|
| 985 | Name => 'TimeZone',
|
---|
| 986 | Groups => { 2 => 'Time' },
|
---|
| 987 | RawConv => 'Get16s(\$val,0)',
|
---|
| 988 | PrintConv => 'TimeZoneString($val)',
|
---|
| 989 | },
|
---|
| 990 | 0x0c => {
|
---|
| 991 | Name => 'ModifyDate',
|
---|
| 992 | Groups => { 2 => 'Time' },
|
---|
| 993 | # translate from format "YYYY/mm/dd HH:MM:SS"
|
---|
| 994 | ValueConv => '$val=~tr{/}{:}; $val',
|
---|
| 995 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
| 996 | },
|
---|
| 997 | );
|
---|
| 998 |
|
---|
| 999 | # Profile atoms (ref 11)
|
---|
| 1000 | %Image::ExifTool::QuickTime::Profile = (
|
---|
| 1001 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1002 | GROUPS => { 2 => 'Video' },
|
---|
| 1003 | FPRF => {
|
---|
| 1004 | Name => 'FileGlobalProfile',
|
---|
| 1005 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileProf' },
|
---|
| 1006 | },
|
---|
| 1007 | APRF => {
|
---|
| 1008 | Name => 'AudioProfile',
|
---|
| 1009 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioProf' },
|
---|
| 1010 | },
|
---|
| 1011 | VPRF => {
|
---|
| 1012 | Name => 'VideoProfile',
|
---|
| 1013 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoProf' },
|
---|
| 1014 | },
|
---|
| 1015 | );
|
---|
| 1016 |
|
---|
| 1017 | # FPRF atom information (ref 11)
|
---|
| 1018 | %Image::ExifTool::QuickTime::FileProf = (
|
---|
| 1019 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1020 | GROUPS => { 2 => 'Video' },
|
---|
| 1021 | FORMAT => 'int32u',
|
---|
| 1022 | 0 => { Name => 'FileProfileVersion', Unknown => 1 }, # unknown = uninteresting
|
---|
| 1023 | 1 => {
|
---|
| 1024 | Name => 'FileFunctionFlags',
|
---|
| 1025 | PrintConv => { BITMASK => {
|
---|
| 1026 | 28 => 'Fragmented',
|
---|
| 1027 | 29 => 'Additional tracks',
|
---|
| 1028 | 30 => 'Edited', # (main AV track is edited)
|
---|
| 1029 | }},
|
---|
| 1030 | },
|
---|
| 1031 | # 2 - reserved
|
---|
| 1032 | );
|
---|
| 1033 |
|
---|
| 1034 | # APRF atom information (ref 11)
|
---|
| 1035 | %Image::ExifTool::QuickTime::AudioProf = (
|
---|
| 1036 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1037 | GROUPS => { 2 => 'Audio' },
|
---|
| 1038 | FORMAT => 'int32u',
|
---|
| 1039 | 0 => { Name => 'AudioProfileVersion', Unknown => 1 },
|
---|
| 1040 | 1 => 'AudioTrackID',
|
---|
| 1041 | 2 => {
|
---|
| 1042 | Name => 'AudioCodec',
|
---|
| 1043 | Format => 'undef[4]',
|
---|
| 1044 | },
|
---|
| 1045 | 3 => {
|
---|
| 1046 | Name => 'AudioCodecInfo',
|
---|
| 1047 | Unknown => 1,
|
---|
| 1048 | PrintConv => 'sprintf("0x%.4x", $val)',
|
---|
| 1049 | },
|
---|
| 1050 | 4 => {
|
---|
| 1051 | Name => 'AudioAttributes',
|
---|
| 1052 | PrintConv => { BITMASK => {
|
---|
| 1053 | 0 => 'Encrypted',
|
---|
| 1054 | 1 => 'Variable bitrate',
|
---|
| 1055 | 2 => 'Dual mono',
|
---|
| 1056 | }},
|
---|
| 1057 | },
|
---|
| 1058 | 5 => {
|
---|
| 1059 | Name => 'AudioAvgBitrate',
|
---|
| 1060 | ValueConv => '$val * 1000',
|
---|
| 1061 | PrintConv => 'ConvertBitrate($val)',
|
---|
| 1062 | },
|
---|
| 1063 | 6 => {
|
---|
| 1064 | Name => 'AudioMaxBitrate',
|
---|
| 1065 | ValueConv => '$val * 1000',
|
---|
| 1066 | PrintConv => 'ConvertBitrate($val)',
|
---|
| 1067 | },
|
---|
| 1068 | 7 => 'AudioSampleRate',
|
---|
| 1069 | 8 => 'AudioChannels',
|
---|
| 1070 | );
|
---|
| 1071 |
|
---|
| 1072 | # VPRF atom information (ref 11)
|
---|
| 1073 | %Image::ExifTool::QuickTime::VideoProf = (
|
---|
| 1074 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1075 | GROUPS => { 2 => 'Video' },
|
---|
| 1076 | FORMAT => 'int32u',
|
---|
| 1077 | 0 => { Name => 'VideoProfileVersion', Unknown => 1 },
|
---|
| 1078 | 1 => 'VideoTrackID',
|
---|
| 1079 | 2 => {
|
---|
| 1080 | Name => 'VideoCodec',
|
---|
| 1081 | Format => 'undef[4]',
|
---|
| 1082 | },
|
---|
| 1083 | 3 => {
|
---|
| 1084 | Name => 'VideoCodecInfo',
|
---|
| 1085 | Unknown => 1,
|
---|
| 1086 | PrintConv => 'sprintf("0x%.4x", $val)',
|
---|
| 1087 | },
|
---|
| 1088 | 4 => {
|
---|
| 1089 | Name => 'VideoAttributes',
|
---|
| 1090 | PrintConv => { BITMASK => {
|
---|
| 1091 | 0 => 'Encrypted',
|
---|
| 1092 | 1 => 'Variable bitrate',
|
---|
| 1093 | 2 => 'Variable frame rate',
|
---|
| 1094 | 3 => 'Interlaced',
|
---|
| 1095 | }},
|
---|
| 1096 | },
|
---|
| 1097 | 5 => {
|
---|
| 1098 | Name => 'VideoAvgBitrate',
|
---|
| 1099 | ValueConv => '$val * 1000',
|
---|
| 1100 | PrintConv => 'ConvertBitrate($val)',
|
---|
| 1101 | },
|
---|
| 1102 | 6 => {
|
---|
| 1103 | Name => 'VideoMaxBitrate',
|
---|
| 1104 | ValueConv => '$val * 1000',
|
---|
| 1105 | PrintConv => 'ConvertBitrate($val)',
|
---|
| 1106 | },
|
---|
| 1107 | 7 => {
|
---|
| 1108 | Name => 'VideoAvgFrameRate',
|
---|
| 1109 | Format => 'fixed32u',
|
---|
| 1110 | PrintConv => 'int($val * 1000 + 0.5) / 1000',
|
---|
| 1111 | },
|
---|
| 1112 | 8 => {
|
---|
| 1113 | Name => 'VideoMaxFrameRate',
|
---|
| 1114 | Format => 'fixed32u',
|
---|
| 1115 | PrintConv => 'int($val * 1000 + 0.5) / 1000',
|
---|
| 1116 | },
|
---|
| 1117 | 9 => {
|
---|
| 1118 | Name => 'VideoSize',
|
---|
| 1119 | Format => 'int16u[2]',
|
---|
| 1120 | PrintConv => '$val=~tr/ /x/; $val',
|
---|
| 1121 | },
|
---|
| 1122 | 10 => {
|
---|
| 1123 | Name => 'PixelAspectRatio',
|
---|
| 1124 | Format => 'int16u[2]',
|
---|
| 1125 | PrintConv => '$val=~tr/ /:/; $val',
|
---|
| 1126 | },
|
---|
| 1127 | );
|
---|
| 1128 |
|
---|
[16842] | 1129 | # meta atoms
|
---|
| 1130 | %Image::ExifTool::QuickTime::Meta = (
|
---|
[24107] | 1131 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 1132 | GROUPS => { 2 => 'Video' },
|
---|
| 1133 | ilst => {
|
---|
[24107] | 1134 | Name => 'ItemList',
|
---|
[16842] | 1135 | SubDirectory => {
|
---|
[24107] | 1136 | TagTable => 'Image::ExifTool::QuickTime::ItemList',
|
---|
[16842] | 1137 | HasData => 1, # process atoms as containers with 'data' elements
|
---|
| 1138 | },
|
---|
| 1139 | },
|
---|
[24107] | 1140 | # MP4 tags (ref 5)
|
---|
| 1141 | hdlr => {
|
---|
| 1142 | Name => 'Handler',
|
---|
| 1143 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
|
---|
| 1144 | },
|
---|
| 1145 | dinf => {
|
---|
| 1146 | Name => 'DataInformation',
|
---|
| 1147 | Flags => ['Binary','Unknown'],
|
---|
| 1148 | },
|
---|
| 1149 | ipmc => {
|
---|
| 1150 | Name => 'IPMPControl',
|
---|
| 1151 | Flags => ['Binary','Unknown'],
|
---|
| 1152 | },
|
---|
| 1153 | iloc => {
|
---|
| 1154 | Name => 'ItemLocation',
|
---|
| 1155 | Flags => ['Binary','Unknown'],
|
---|
| 1156 | },
|
---|
| 1157 | ipro => {
|
---|
| 1158 | Name => 'ItemProtection',
|
---|
| 1159 | Flags => ['Binary','Unknown'],
|
---|
| 1160 | },
|
---|
| 1161 | iinf => {
|
---|
| 1162 | Name => 'ItemInformation',
|
---|
| 1163 | Flags => ['Binary','Unknown'],
|
---|
| 1164 | },
|
---|
| 1165 | 'xml ' => {
|
---|
| 1166 | Name => 'XML',
|
---|
| 1167 | SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
---|
| 1168 | },
|
---|
| 1169 | 'keys' => {
|
---|
| 1170 | Name => 'Keys',
|
---|
| 1171 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Keys' },
|
---|
| 1172 | },
|
---|
| 1173 | bxml => {
|
---|
| 1174 | Name => 'BinaryXML',
|
---|
| 1175 | Flags => ['Binary','Unknown'],
|
---|
| 1176 | },
|
---|
| 1177 | pitm => {
|
---|
| 1178 | Name => 'PrimaryItemReference',
|
---|
| 1179 | Flags => ['Binary','Unknown'],
|
---|
| 1180 | },
|
---|
| 1181 | free => { #PH
|
---|
| 1182 | Name => 'Free',
|
---|
| 1183 | Flags => ['Binary','Unknown'],
|
---|
| 1184 | },
|
---|
[16842] | 1185 | );
|
---|
| 1186 |
|
---|
[24107] | 1187 | # track reference atoms
|
---|
| 1188 | %Image::ExifTool::QuickTime::TrackRef = (
|
---|
| 1189 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1190 | GROUPS => { 2 => 'Video' },
|
---|
| 1191 | chap => { Name => 'ChapterList', Format => 'int32u' },
|
---|
| 1192 | # also: tmcd, sync, scpt, ssrc, iTunesInfo
|
---|
| 1193 | );
|
---|
| 1194 |
|
---|
| 1195 | # item list atoms
|
---|
[16842] | 1196 | # -> these atoms are unique, and contain one or more 'data' atoms
|
---|
[24107] | 1197 | %Image::ExifTool::QuickTime::ItemList = (
|
---|
| 1198 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 1199 | GROUPS => { 2 => 'Audio' },
|
---|
[24107] | 1200 | NOTES => q{
|
---|
| 1201 | As well as these tags, the 'mdta' handler uses numerical tag ID's which are
|
---|
| 1202 | added dynamically to this table after processing the Meta Keys information.
|
---|
| 1203 | },
|
---|
| 1204 | # in this table, binary 1 and 2-byte "data"-type tags are interpreted as
|
---|
| 1205 | # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data
|
---|
[16842] | 1206 | "\xa9ART" => 'Artist',
|
---|
| 1207 | "\xa9alb" => 'Album',
|
---|
| 1208 | "\xa9cmt" => 'Comment',
|
---|
| 1209 | "\xa9com" => 'Composer',
|
---|
[24107] | 1210 | "\xa9day" => { Name => 'Year', Groups => { 2 => 'Time' } },
|
---|
[16842] | 1211 | "\xa9des" => 'Description', #4
|
---|
[24107] | 1212 | "\xa9enc" => 'EncodedBy', #10
|
---|
[16842] | 1213 | "\xa9gen" => 'Genre',
|
---|
| 1214 | "\xa9grp" => 'Grouping',
|
---|
| 1215 | "\xa9lyr" => 'Lyrics',
|
---|
| 1216 | "\xa9nam" => 'Title',
|
---|
[24107] | 1217 | # "\xa9st3" ? #10
|
---|
[16842] | 1218 | "\xa9too" => 'Encoder',
|
---|
| 1219 | "\xa9trk" => 'Track',
|
---|
| 1220 | "\xa9wrt" => 'Composer',
|
---|
| 1221 | '----' => {
|
---|
| 1222 | Name => 'iTunesInfo',
|
---|
| 1223 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' },
|
---|
| 1224 | },
|
---|
| 1225 | aART => 'AlbumArtist',
|
---|
| 1226 | covr => 'CoverArt',
|
---|
[24107] | 1227 | cpil => { #10
|
---|
[16842] | 1228 | Name => 'Compilation',
|
---|
| 1229 | PrintConv => { 0 => 'No', 1 => 'Yes' },
|
---|
| 1230 | },
|
---|
| 1231 | disk => {
|
---|
| 1232 | Name => 'DiskNumber',
|
---|
| 1233 | ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val',
|
---|
| 1234 | },
|
---|
[24107] | 1235 | pgap => { #10
|
---|
[16842] | 1236 | Name => 'PlayGap',
|
---|
| 1237 | PrintConv => {
|
---|
| 1238 | 0 => 'Insert Gap',
|
---|
| 1239 | 1 => 'No Gap',
|
---|
| 1240 | },
|
---|
| 1241 | },
|
---|
[24107] | 1242 | tmpo => {
|
---|
| 1243 | Name => 'BeatsPerMinute',
|
---|
| 1244 | Format => 'int16u', # marked as boolean but really int16u in my sample
|
---|
| 1245 | },
|
---|
[16842] | 1246 | trkn => {
|
---|
| 1247 | Name => 'TrackNumber',
|
---|
| 1248 | ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val',
|
---|
| 1249 | },
|
---|
[24107] | 1250 | #
|
---|
| 1251 | # Note: it is possible that the tags below are not being decoded properly
|
---|
| 1252 | # because I don't have samples to verify many of these - PH
|
---|
| 1253 | #
|
---|
| 1254 | akID => { #10
|
---|
| 1255 | Name => 'AppleStoreAccountType',
|
---|
| 1256 | PrintConv => {
|
---|
| 1257 | 0 => 'iTunes',
|
---|
| 1258 | 1 => 'AOL',
|
---|
| 1259 | },
|
---|
| 1260 | },
|
---|
| 1261 | albm => 'Album', #(ffmpeg source)
|
---|
| 1262 | apID => 'AppleStoreAccount',
|
---|
| 1263 | atID => { #10 (or TV series)
|
---|
| 1264 | Name => 'AlbumTitleID',
|
---|
| 1265 | Format => 'int32u',
|
---|
| 1266 | },
|
---|
| 1267 | auth => { Name => 'Author', Groups => { 2 => 'Author' } },
|
---|
| 1268 | catg => 'Category', #7
|
---|
| 1269 | cnID => { #10
|
---|
| 1270 | Name => 'AppleStoreCatalogID',
|
---|
| 1271 | Format => 'int32u',
|
---|
| 1272 | },
|
---|
| 1273 | cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } },
|
---|
| 1274 | dscp => 'Description',
|
---|
| 1275 | desc => 'Description', #7
|
---|
| 1276 | gnre => { #10
|
---|
| 1277 | Name => 'Genre',
|
---|
| 1278 | PrintConv => q{
|
---|
| 1279 | return $val unless $val =~ /^\d+$/;
|
---|
| 1280 | require Image::ExifTool::ID3;
|
---|
| 1281 | Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1"
|
---|
| 1282 | },
|
---|
| 1283 | },
|
---|
| 1284 | egid => 'EpisodeGlobalUniqueID', #7
|
---|
| 1285 | geID => { #10
|
---|
| 1286 | Name => 'GenreID',
|
---|
| 1287 | Format => 'int32u',
|
---|
| 1288 | # 4005 = Kids
|
---|
| 1289 | # 4010 = Teens
|
---|
| 1290 | },
|
---|
| 1291 | grup => 'Grouping', #10
|
---|
| 1292 | hdvd => { #10
|
---|
| 1293 | Name => 'HDVideo',
|
---|
| 1294 | PrintConv => { 0 => 'No', 1 => 'Yes' },
|
---|
| 1295 | },
|
---|
| 1296 | keyw => 'Keyword', #7
|
---|
| 1297 | ldes => 'LongDescription', #10
|
---|
| 1298 | pcst => { #7
|
---|
| 1299 | Name => 'Podcast',
|
---|
| 1300 | PrintConv => { 0 => 'No', 1 => 'Yes' },
|
---|
| 1301 | },
|
---|
| 1302 | perf => 'Performer',
|
---|
| 1303 | plID => { #10 (or TV season)
|
---|
| 1304 | Name => 'PlayListID',
|
---|
| 1305 | Format => 'int8u', # actually int64u, but split it up
|
---|
| 1306 | },
|
---|
| 1307 | purd => 'PurchaseDate', #7
|
---|
| 1308 | purl => 'PodcastURL', #7
|
---|
| 1309 | rtng => { #10
|
---|
| 1310 | Name => 'Rating',
|
---|
| 1311 | PrintConv => {
|
---|
| 1312 | 0 => 'none',
|
---|
| 1313 | 2 => 'Clean',
|
---|
| 1314 | 4 => 'Explicit',
|
---|
| 1315 | },
|
---|
| 1316 | },
|
---|
| 1317 | sfID => { #10
|
---|
| 1318 | Name => 'AppleStoreCountry',
|
---|
| 1319 | Format => 'int32u',
|
---|
| 1320 | PrintConv => {
|
---|
| 1321 | 143460 => 'Australia',
|
---|
| 1322 | 143445 => 'Austria',
|
---|
| 1323 | 143446 => 'Belgium',
|
---|
| 1324 | 143455 => 'Canada',
|
---|
| 1325 | 143458 => 'Denmark',
|
---|
| 1326 | 143447 => 'Finland',
|
---|
| 1327 | 143442 => 'France',
|
---|
| 1328 | 143443 => 'Germany',
|
---|
| 1329 | 143448 => 'Greece',
|
---|
| 1330 | 143449 => 'Ireland',
|
---|
| 1331 | 143450 => 'Italy',
|
---|
| 1332 | 143462 => 'Japan',
|
---|
| 1333 | 143451 => 'Luxembourg',
|
---|
| 1334 | 143452 => 'Netherlands',
|
---|
| 1335 | 143461 => 'New Zealand',
|
---|
| 1336 | 143457 => 'Norway',
|
---|
| 1337 | 143453 => 'Portugal',
|
---|
| 1338 | 143454 => 'Spain',
|
---|
| 1339 | 143456 => 'Sweden',
|
---|
| 1340 | 143459 => 'Switzerland',
|
---|
| 1341 | 143444 => 'United Kingdom',
|
---|
| 1342 | 143441 => 'United States',
|
---|
| 1343 | },
|
---|
| 1344 | },
|
---|
| 1345 | soaa => 'SortAlbumArtist', #10
|
---|
| 1346 | soal => 'SortAlbum', #10
|
---|
| 1347 | soar => 'SortArtist', #10
|
---|
| 1348 | soco => 'SortComposer', #10
|
---|
| 1349 | sonm => 'SortName', #10
|
---|
| 1350 | sosn => 'SortShow', #10
|
---|
| 1351 | stik => { #10
|
---|
| 1352 | Name => 'MediaType',
|
---|
| 1353 | PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html)
|
---|
| 1354 | 0 => 'Movie',
|
---|
| 1355 | 1 => 'Normal (Music)',
|
---|
| 1356 | 2 => 'Audiobook',
|
---|
| 1357 | 5 => 'Whacked Bookmark',
|
---|
| 1358 | 6 => 'Music Video',
|
---|
| 1359 | 9 => 'Short Film',
|
---|
| 1360 | 10 => 'TV Show',
|
---|
| 1361 | 11 => 'Booklet',
|
---|
| 1362 | 14 => 'Ringtone',
|
---|
| 1363 | },
|
---|
| 1364 | },
|
---|
| 1365 | titl => 'Title',
|
---|
| 1366 | tven => 'TVEpisodeID', #7
|
---|
| 1367 | tves => { #7/10
|
---|
| 1368 | Name => 'TVEpisode',
|
---|
| 1369 | Format => 'int32u',
|
---|
| 1370 | },
|
---|
| 1371 | tvnn => 'TVNetworkName', #7
|
---|
| 1372 | tvsh => 'TVShow', #10
|
---|
| 1373 | tvsn => { #7/10
|
---|
| 1374 | Name => 'TVSeason',
|
---|
| 1375 | Format => 'int32u',
|
---|
| 1376 | },
|
---|
| 1377 | yrrc => 'Year', #(ffmpeg source)
|
---|
[16842] | 1378 | );
|
---|
| 1379 |
|
---|
[24107] | 1380 | # item list keys (ref PH)
|
---|
| 1381 | %Image::ExifTool::QuickTime::Keys = (
|
---|
| 1382 | PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessKeys,
|
---|
| 1383 | NOTES => q{
|
---|
| 1384 | This directory contains a list of key names which are used to decode
|
---|
| 1385 | ItemList tags written by the "mdta" handler. The prefix of
|
---|
| 1386 | "com.apple.quicktime." has been removed from all TagID's below.
|
---|
| 1387 | },
|
---|
| 1388 | version => 'Version',
|
---|
| 1389 | album => 'Album',
|
---|
| 1390 | artist => { },
|
---|
| 1391 | artwork => { },
|
---|
| 1392 | author => { Name => 'Author', Groups => { 2 => 'Author' } },
|
---|
| 1393 | comment => { },
|
---|
| 1394 | copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } },
|
---|
| 1395 | creationdate=> {
|
---|
| 1396 | Name => 'CreationDate',
|
---|
| 1397 | Groups => { 2 => 'Time' },
|
---|
| 1398 | ValueConv => q{
|
---|
| 1399 | require Image::ExifTool::XMP;
|
---|
| 1400 | $val = Image::ExifTool::XMP::ConvertXMPDate($val,1);
|
---|
| 1401 | $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
|
---|
| 1402 | return $val;
|
---|
| 1403 | },
|
---|
| 1404 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
| 1405 | },
|
---|
| 1406 | description => { },
|
---|
| 1407 | director => { },
|
---|
| 1408 | genre => { },
|
---|
| 1409 | information => { },
|
---|
| 1410 | keywords => { },
|
---|
| 1411 | make => { Name => 'Make', Groups => { 2 => 'Camera' } },
|
---|
| 1412 | model => { Name => 'Model', Groups => { 2 => 'Camera' } },
|
---|
| 1413 | publisher => { },
|
---|
| 1414 | software => { },
|
---|
| 1415 | year => { Groups => { 2 => 'Time' } },
|
---|
| 1416 | 'camera.identifier' => 'CameraIdentifier', # (iPhone 4)
|
---|
| 1417 | 'camera.framereadouttimeinmicroseconds' => { # (iPhone 4)
|
---|
| 1418 | Name => 'FrameReadoutTime',
|
---|
| 1419 | ValueConv => '$val * 1e-6',
|
---|
| 1420 | PrintConv => '$val * 1e6 . " microseconds"',
|
---|
| 1421 | },
|
---|
| 1422 | 'location.ISO6709' => {
|
---|
| 1423 | Name => 'GPSCoordinates',
|
---|
| 1424 | Groups => { 2 => 'Location' },
|
---|
| 1425 | ValueConv => \&ConvertISO6709,
|
---|
| 1426 | PrintConv => \&PrintGPSCoordinates,
|
---|
| 1427 | },
|
---|
| 1428 | 'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } },
|
---|
| 1429 | 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
|
---|
| 1430 | 'location.note' => { Name => 'LocationNote', Groups => { 2 => 'Location' } },
|
---|
| 1431 | 'location.role' => {
|
---|
| 1432 | Name => 'LocationRole',
|
---|
| 1433 | Groups => { 2 => 'Location' },
|
---|
| 1434 | PrintConv => {
|
---|
| 1435 | 0 => 'Shooting Location',
|
---|
| 1436 | 1 => 'Real Location',
|
---|
| 1437 | 2 => 'Fictional Location',
|
---|
| 1438 | },
|
---|
| 1439 | },
|
---|
| 1440 | 'location.date' => {
|
---|
| 1441 | Name => 'LocationDate',
|
---|
| 1442 | Groups => { 2 => 'Time' },
|
---|
| 1443 | ValueConv => q{
|
---|
| 1444 | require Image::ExifTool::XMP;
|
---|
| 1445 | $val = Image::ExifTool::XMP::ConvertXMPDate($val);
|
---|
| 1446 | $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
|
---|
| 1447 | return $val;
|
---|
| 1448 | },
|
---|
| 1449 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
| 1450 | },
|
---|
| 1451 | 'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } },
|
---|
| 1452 | 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } },
|
---|
| 1453 | 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
|
---|
| 1454 | 'player.version' => 'PlayerVersion',
|
---|
| 1455 | 'player.movie.visual.brightness'=> 'Brightness',
|
---|
| 1456 | 'player.movie.visual.color' => 'Color',
|
---|
| 1457 | 'player.movie.visual.tint' => 'Tint',
|
---|
| 1458 | 'player.movie.visual.contrast' => 'Contrast',
|
---|
| 1459 | 'player.movie.audio.gain' => 'AudioGain',
|
---|
| 1460 | 'player.movie.audio.treble' => 'Trebel',
|
---|
| 1461 | 'player.movie.audio.bass' => 'Bass',
|
---|
| 1462 | 'player.movie.audio.balance' => 'Balance',
|
---|
| 1463 | 'player.movie.audio.pitchshift' => 'PitchShift',
|
---|
| 1464 | 'player.movie.audio.mute' => {
|
---|
| 1465 | Name => 'Mute',
|
---|
| 1466 | Format => 'int8u',
|
---|
| 1467 | PrintConv => { 0 => 'Off', 1 => 'On' },
|
---|
| 1468 | },
|
---|
| 1469 | );
|
---|
| 1470 |
|
---|
| 1471 | # iTunes info ('----') atoms
|
---|
[16842] | 1472 | %Image::ExifTool::QuickTime::iTunesInfo = (
|
---|
[24107] | 1473 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 1474 | GROUPS => { 2 => 'Audio' },
|
---|
[24107] | 1475 | # 'mean'/'name'/'data' atoms form a triplet, but unfortunately
|
---|
| 1476 | # I can't find any source for decoding 'data'.
|
---|
| 1477 | # 'mean' is normally 'com.apple.iTunes'
|
---|
| 1478 | # 'name' values: 'tool', 'iTunNORM' (volume normalization),
|
---|
| 1479 | # 'iTunSMPB', 'iTunes_CDDB_IDs', 'iTunes_CDDB_TrackNumber'
|
---|
| 1480 | mean => {
|
---|
| 1481 | Name => 'Mean',
|
---|
| 1482 | Unknown => 1,
|
---|
| 1483 | },
|
---|
| 1484 | name => {
|
---|
| 1485 | Name => 'Name',
|
---|
| 1486 | Unknown => 1,
|
---|
| 1487 | },
|
---|
| 1488 | data => {
|
---|
| 1489 | Name => 'Data',
|
---|
| 1490 | Flags => ['Binary','Unknown'],
|
---|
| 1491 | },
|
---|
[16842] | 1492 | );
|
---|
| 1493 |
|
---|
| 1494 | # print to video data block
|
---|
| 1495 | %Image::ExifTool::QuickTime::Video = (
|
---|
| 1496 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1497 | GROUPS => { 2 => 'Video' },
|
---|
| 1498 | 0 => {
|
---|
| 1499 | Name => 'DisplaySize',
|
---|
| 1500 | PrintConv => {
|
---|
| 1501 | 0 => 'Normal',
|
---|
| 1502 | 1 => 'Double Size',
|
---|
| 1503 | 2 => 'Half Size',
|
---|
| 1504 | 3 => 'Full Screen',
|
---|
| 1505 | 4 => 'Current Size',
|
---|
| 1506 | },
|
---|
| 1507 | },
|
---|
| 1508 | 6 => {
|
---|
| 1509 | Name => 'SlideShow',
|
---|
| 1510 | PrintConv => {
|
---|
| 1511 | 0 => 'No',
|
---|
| 1512 | 1 => 'Yes',
|
---|
| 1513 | },
|
---|
| 1514 | },
|
---|
| 1515 | );
|
---|
| 1516 |
|
---|
[24107] | 1517 | # 'hnti' atoms
|
---|
| 1518 | %Image::ExifTool::QuickTime::HintInfo = (
|
---|
| 1519 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1520 | GROUPS => { 2 => 'Video' },
|
---|
| 1521 | 'rtp ' => {
|
---|
| 1522 | Name => 'RealtimeStreamingProtocol',
|
---|
| 1523 | PrintConv => '$val=~s/^sdp /(SDP) /; $val',
|
---|
| 1524 | },
|
---|
| 1525 | 'sdp ' => 'StreamingDataProtocol',
|
---|
| 1526 | );
|
---|
| 1527 |
|
---|
| 1528 | # 'hinf' atoms
|
---|
| 1529 | %Image::ExifTool::QuickTime::HintTrackInfo = (
|
---|
| 1530 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1531 | GROUPS => { 2 => 'Video' },
|
---|
| 1532 | trpY => { Name => 'TotalBytes', Format => 'int64u' }, #(documented)
|
---|
| 1533 | trpy => { Name => 'TotalBytes', Format => 'int64u' }, #(observed)
|
---|
| 1534 | totl => { Name => 'TotalBytes', Format => 'int32u' },
|
---|
| 1535 | nump => { Name => 'NumPackets', Format => 'int64u' },
|
---|
| 1536 | npck => { Name => 'NumPackets', Format => 'int32u' },
|
---|
| 1537 | tpyl => { Name => 'TotalBytesNoRTPHeaders', Format => 'int64u' },
|
---|
| 1538 | tpaY => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(documented)
|
---|
| 1539 | tpay => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(observed)
|
---|
| 1540 | maxr => {
|
---|
| 1541 | Name => 'MaxDataRate',
|
---|
| 1542 | Format => 'int32u',
|
---|
| 1543 | Count => 2,
|
---|
| 1544 | PrintConv => 'my @a=split(" ",$val);sprintf("%d bytes in %.3f s",$a[1],$a[0]/1000)',
|
---|
| 1545 | },
|
---|
| 1546 | dmed => { Name => 'MediaTrackBytes', Format => 'int64u' },
|
---|
| 1547 | dimm => { Name => 'ImmediateDataBytes', Format => 'int64u' },
|
---|
| 1548 | drep => { Name => 'RepeatedDataBytes', Format => 'int64u' },
|
---|
| 1549 | tmin => {
|
---|
| 1550 | Name => 'MinTransmissionTime',
|
---|
| 1551 | Format => 'int32u',
|
---|
| 1552 | PrintConv => 'sprintf("%.3f s",$val/1000)',
|
---|
| 1553 | },
|
---|
| 1554 | tmax => {
|
---|
| 1555 | Name => 'MaxTransmissionTime',
|
---|
| 1556 | Format => 'int32u',
|
---|
| 1557 | PrintConv => 'sprintf("%.3f s",$val/1000)',
|
---|
| 1558 | },
|
---|
| 1559 | pmax => { Name => 'LargestPacketSize', Format => 'int32u' },
|
---|
| 1560 | dmax => {
|
---|
| 1561 | Name => 'LargestPacketDuration',
|
---|
| 1562 | Format => 'int32u',
|
---|
| 1563 | PrintConv => 'sprintf("%.3f s",$val/1000)',
|
---|
| 1564 | },
|
---|
| 1565 | payt => {
|
---|
| 1566 | Name => 'PayloadType',
|
---|
| 1567 | ValueConv => 'unpack("N",$val) . " " . substr($val, 5)',
|
---|
| 1568 | PrintConv => '$val=~s/ /, /;$val',
|
---|
| 1569 | },
|
---|
| 1570 | );
|
---|
| 1571 |
|
---|
| 1572 | # Kodak DcMD atoms (ref PH)
|
---|
| 1573 | %Image::ExifTool::QuickTime::DcMD = (
|
---|
| 1574 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1575 | GROUPS => { 2 => 'Video' },
|
---|
| 1576 | NOTES => 'Metadata directory found in MOV videos from some Kodak cameras.',
|
---|
| 1577 | Cmbo => {
|
---|
| 1578 | Name => 'CameraByteOrder',
|
---|
| 1579 | PrintConv => {
|
---|
| 1580 | II => 'Little-endian (Intel, II)',
|
---|
| 1581 | MM => 'Big-endian (Motorola, MM)',
|
---|
| 1582 | },
|
---|
| 1583 | },
|
---|
| 1584 | DcME => {
|
---|
| 1585 | Name => 'DcME',
|
---|
| 1586 | SubDirectory => {
|
---|
| 1587 | TagTable => 'Image::ExifTool::QuickTime::DcME',
|
---|
| 1588 | },
|
---|
| 1589 | },
|
---|
| 1590 | );
|
---|
| 1591 |
|
---|
| 1592 | # Kodak DcME atoms (ref PH)
|
---|
| 1593 | %Image::ExifTool::QuickTime::DcME = (
|
---|
| 1594 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1595 | GROUPS => { 2 => 'Video' },
|
---|
| 1596 | # Mtmd = binary data ("00 00 00 00 00 00 00 01" x 3)
|
---|
| 1597 | # Keyw = keywords? (six bytes all zero)
|
---|
| 1598 | # Rate = 2 bytes "00 00"
|
---|
| 1599 | );
|
---|
| 1600 |
|
---|
| 1601 | # MP4 media box (ref 5)
|
---|
[16842] | 1602 | %Image::ExifTool::QuickTime::Media = (
|
---|
[24107] | 1603 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 1604 | GROUPS => { 2 => 'Video' },
|
---|
[24107] | 1605 | NOTES => 'MP4 media box.',
|
---|
| 1606 | mdhd => {
|
---|
| 1607 | Name => 'MediaHeader',
|
---|
| 1608 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaHeader' },
|
---|
| 1609 | },
|
---|
| 1610 | hdlr => {
|
---|
| 1611 | Name => 'Handler',
|
---|
| 1612 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
|
---|
| 1613 | },
|
---|
[16842] | 1614 | minf => {
|
---|
[24107] | 1615 | Name => 'MediaInfo',
|
---|
| 1616 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaInfo' },
|
---|
[16842] | 1617 | },
|
---|
| 1618 | );
|
---|
| 1619 |
|
---|
[24107] | 1620 | # MP4 media header box (ref 5)
|
---|
| 1621 | %Image::ExifTool::QuickTime::MediaHeader = (
|
---|
| 1622 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
[16842] | 1623 | GROUPS => { 2 => 'Video' },
|
---|
[24107] | 1624 | FORMAT => 'int32u',
|
---|
| 1625 | 0 => {
|
---|
| 1626 | Name => 'MediaHeaderVersion',
|
---|
| 1627 | RawConv => '$$self{MediaHeaderVersion} = $val',
|
---|
| 1628 | },
|
---|
| 1629 | 1 => {
|
---|
| 1630 | Name => 'MediaCreateDate',
|
---|
| 1631 | Groups => { 2 => 'Time' },
|
---|
| 1632 | %timeInfo,
|
---|
| 1633 | # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
|
---|
| 1634 | Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
| 1635 | },
|
---|
| 1636 | 2 => {
|
---|
| 1637 | Name => 'MediaModifyDate',
|
---|
| 1638 | Groups => { 2 => 'Time' },
|
---|
| 1639 | %timeInfo,
|
---|
| 1640 | # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
|
---|
| 1641 | Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
| 1642 | },
|
---|
| 1643 | 3 => {
|
---|
| 1644 | Name => 'MediaTimeScale',
|
---|
| 1645 | RawConv => '$$self{MediaTS} = $val',
|
---|
| 1646 | },
|
---|
| 1647 | 4 => {
|
---|
| 1648 | Name => 'MediaDuration',
|
---|
| 1649 | RawConv => '$$self{MediaTS} ? $val / $$self{MediaTS} : $val',
|
---|
| 1650 | PrintConv => '$$self{MediaTS} ? ConvertDuration($val) : $val',
|
---|
| 1651 | # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
|
---|
| 1652 | Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
|
---|
| 1653 | },
|
---|
| 1654 | 5 => {
|
---|
| 1655 | Name => 'MediaLanguageCode',
|
---|
| 1656 | Format => 'int16u',
|
---|
| 1657 | RawConv => '$val ? $val : undef',
|
---|
| 1658 | # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes
|
---|
| 1659 | ValueConv => '$val < 0x400 ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0',
|
---|
| 1660 | PrintConv => q{
|
---|
| 1661 | return $val unless $val =~ /^\d+$/;
|
---|
| 1662 | require Image::ExifTool::Font;
|
---|
| 1663 | return $Image::ExifTool::Font::ttLang{Macintosh}{$val} || "Unknown ($val)";
|
---|
| 1664 | },
|
---|
| 1665 | },
|
---|
| 1666 | );
|
---|
| 1667 |
|
---|
| 1668 | # MP4 media information box (ref 5)
|
---|
| 1669 | %Image::ExifTool::QuickTime::MediaInfo = (
|
---|
| 1670 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1671 | GROUPS => { 2 => 'Video' },
|
---|
| 1672 | NOTES => 'MP4 media info box.',
|
---|
| 1673 | vmhd => {
|
---|
| 1674 | Name => 'VideoHeader',
|
---|
| 1675 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoHeader' },
|
---|
| 1676 | },
|
---|
| 1677 | smhd => {
|
---|
| 1678 | Name => 'AudioHeader',
|
---|
| 1679 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioHeader' },
|
---|
| 1680 | },
|
---|
| 1681 | hmhd => {
|
---|
| 1682 | Name => 'HintHeader',
|
---|
| 1683 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintHeader' },
|
---|
| 1684 | },
|
---|
| 1685 | nmhd => {
|
---|
| 1686 | Name => 'NullMediaHeader',
|
---|
| 1687 | Flags => ['Binary','Unknown'],
|
---|
| 1688 | },
|
---|
[16842] | 1689 | dinf => {
|
---|
[24107] | 1690 | Name => 'DataInfo',
|
---|
| 1691 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' },
|
---|
[16842] | 1692 | },
|
---|
[24107] | 1693 | gmhd => {
|
---|
| 1694 | Name => 'GenMediaHeader',
|
---|
| 1695 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaHeader' },
|
---|
| 1696 | },
|
---|
| 1697 | hdlr => { #PH
|
---|
| 1698 | Name => 'Handler',
|
---|
| 1699 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
|
---|
| 1700 | },
|
---|
[16842] | 1701 | stbl => {
|
---|
[24107] | 1702 | Name => 'SampleTable',
|
---|
| 1703 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SampleTable' },
|
---|
[16842] | 1704 | },
|
---|
| 1705 | );
|
---|
| 1706 |
|
---|
[24107] | 1707 | # MP4 video media header (ref 5)
|
---|
| 1708 | %Image::ExifTool::QuickTime::VideoHeader = (
|
---|
| 1709 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
[16842] | 1710 | GROUPS => { 2 => 'Video' },
|
---|
[24107] | 1711 | NOTES => 'MP4 video media header.',
|
---|
| 1712 | FORMAT => 'int16u',
|
---|
| 1713 | 2 => {
|
---|
| 1714 | Name => 'GraphicsMode',
|
---|
| 1715 | PrintHex => 1,
|
---|
| 1716 | SeparateTable => 'GraphicsMode',
|
---|
| 1717 | PrintConv => \%graphicsMode,
|
---|
| 1718 | },
|
---|
| 1719 | 3 => { Name => 'OpColor', Format => 'int16u[3]' },
|
---|
[16842] | 1720 | );
|
---|
| 1721 |
|
---|
[24107] | 1722 | # MP4 audio media header (ref 5)
|
---|
| 1723 | %Image::ExifTool::QuickTime::AudioHeader = (
|
---|
| 1724 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1725 | GROUPS => { 2 => 'Audio' },
|
---|
| 1726 | NOTES => 'MP4 audio media header.',
|
---|
| 1727 | FORMAT => 'int16u',
|
---|
| 1728 | 2 => { Name => 'Balance', Format => 'fixed16s' },
|
---|
| 1729 | );
|
---|
| 1730 |
|
---|
| 1731 | # MP4 hint media header (ref 5)
|
---|
| 1732 | %Image::ExifTool::QuickTime::HintHeader = (
|
---|
| 1733 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1734 | NOTES => 'MP4 hint media header.',
|
---|
| 1735 | FORMAT => 'int16u',
|
---|
| 1736 | 2 => 'MaxPDUSize',
|
---|
| 1737 | 3 => 'AvgPDUSize',
|
---|
| 1738 | 4 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
|
---|
| 1739 | 6 => { Name => 'AvgBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
|
---|
| 1740 | );
|
---|
| 1741 |
|
---|
| 1742 | # MP4 sample table box (ref 5)
|
---|
| 1743 | %Image::ExifTool::QuickTime::SampleTable = (
|
---|
| 1744 | PROCESS_PROC => \&ProcessMOV,
|
---|
[16842] | 1745 | GROUPS => { 2 => 'Video' },
|
---|
[24107] | 1746 | NOTES => 'MP4 sample table box.',
|
---|
| 1747 | stsd => [
|
---|
| 1748 | {
|
---|
| 1749 | Name => 'AudioSampleDesc',
|
---|
| 1750 | Condition => '$$self{HandlerType} and $$self{HandlerType} eq "soun"',
|
---|
| 1751 | SubDirectory => {
|
---|
| 1752 | TagTable => 'Image::ExifTool::QuickTime::AudioSampleDesc',
|
---|
| 1753 | Start => 8, # skip version number and count
|
---|
| 1754 | },
|
---|
| 1755 | },{
|
---|
| 1756 | Name => 'VideoSampleDesc',
|
---|
| 1757 | Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"',
|
---|
| 1758 | SubDirectory => {
|
---|
| 1759 | TagTable => 'Image::ExifTool::QuickTime::ImageDesc',
|
---|
| 1760 | Start => 8, # skip version number and count
|
---|
| 1761 | },
|
---|
| 1762 | },{
|
---|
| 1763 | Name => 'HintSampleDesc',
|
---|
| 1764 | Condition => '$$self{HandlerType} and $$self{HandlerType} eq "hint"',
|
---|
| 1765 | SubDirectory => {
|
---|
| 1766 | TagTable => 'Image::ExifTool::QuickTime::HintSampleDesc',
|
---|
| 1767 | Start => 8, # skip version number and count
|
---|
| 1768 | },
|
---|
| 1769 | },{
|
---|
| 1770 | Name => 'OtherSampleDesc',
|
---|
| 1771 | SubDirectory => {
|
---|
| 1772 | TagTable => 'Image::ExifTool::QuickTime::OtherSampleDesc',
|
---|
| 1773 | Start => 8, # skip version number and count
|
---|
| 1774 | },
|
---|
| 1775 | },
|
---|
| 1776 | # (Note: "alis" HandlerType handled by the parent audio or video handler)
|
---|
| 1777 | ],
|
---|
| 1778 | stts => [ # decoding time-to-sample table
|
---|
| 1779 | {
|
---|
| 1780 | Name => 'VideoFrameRate',
|
---|
| 1781 | Notes => 'average rate calculated from time-to-sample table for video media',
|
---|
| 1782 | Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"',
|
---|
| 1783 | # (must be RawConv so appropriate MediaTS is used in calculation)
|
---|
| 1784 | RawConv => 'Image::ExifTool::QuickTime::CalcSampleRate($self, \$val)',
|
---|
| 1785 | PrintConv => 'int($val * 1000 + 0.5) / 1000',
|
---|
| 1786 | },
|
---|
| 1787 | {
|
---|
| 1788 | Name => 'TimeToSampleTable',
|
---|
| 1789 | Flags => ['Binary','Unknown'],
|
---|
| 1790 | },
|
---|
| 1791 | ],
|
---|
| 1792 | ctts => {
|
---|
| 1793 | Name => 'CompositionTimeToSample',
|
---|
| 1794 | Flags => ['Binary','Unknown'],
|
---|
| 1795 | },
|
---|
| 1796 | stsc => {
|
---|
| 1797 | Name => 'SampleToChunk',
|
---|
| 1798 | Flags => ['Binary','Unknown'],
|
---|
| 1799 | },
|
---|
| 1800 | stsz => {
|
---|
| 1801 | Name => 'SampleSizes',
|
---|
| 1802 | Flags => ['Binary','Unknown'],
|
---|
| 1803 | },
|
---|
| 1804 | stz2 => {
|
---|
| 1805 | Name => 'CompactSampleSizes',
|
---|
| 1806 | Flags => ['Binary','Unknown'],
|
---|
| 1807 | },
|
---|
| 1808 | stco => {
|
---|
| 1809 | Name => 'ChunkOffset',
|
---|
| 1810 | Flags => ['Binary','Unknown'],
|
---|
| 1811 | },
|
---|
| 1812 | co64 => {
|
---|
| 1813 | Name => 'ChunkOffset64',
|
---|
| 1814 | Flags => ['Binary','Unknown'],
|
---|
| 1815 | },
|
---|
| 1816 | stss => {
|
---|
| 1817 | Name => 'SyncSampleTable',
|
---|
| 1818 | Flags => ['Binary','Unknown'],
|
---|
| 1819 | },
|
---|
| 1820 | stsh => {
|
---|
| 1821 | Name => 'ShadowSyncSampleTable',
|
---|
| 1822 | Flags => ['Binary','Unknown'],
|
---|
| 1823 | },
|
---|
| 1824 | padb => {
|
---|
| 1825 | Name => 'SamplePaddingBits',
|
---|
| 1826 | Flags => ['Binary','Unknown'],
|
---|
| 1827 | },
|
---|
| 1828 | stdp => {
|
---|
| 1829 | Name => 'SampleDegradationPriority',
|
---|
| 1830 | Flags => ['Binary','Unknown'],
|
---|
| 1831 | },
|
---|
| 1832 | sdtp => {
|
---|
| 1833 | Name => 'IdependentAndDisposableSamples',
|
---|
| 1834 | Flags => ['Binary','Unknown'],
|
---|
| 1835 | },
|
---|
| 1836 | sbgp => {
|
---|
| 1837 | Name => 'SampleToGroup',
|
---|
| 1838 | Flags => ['Binary','Unknown'],
|
---|
| 1839 | },
|
---|
| 1840 | sgpd => {
|
---|
| 1841 | Name => 'SampleGroupDescription',
|
---|
| 1842 | Flags => ['Binary','Unknown'],
|
---|
| 1843 | },
|
---|
| 1844 | subs => {
|
---|
| 1845 | Name => 'Sub-sampleInformation',
|
---|
| 1846 | Flags => ['Binary','Unknown'],
|
---|
| 1847 | },
|
---|
| 1848 | cslg => {
|
---|
| 1849 | Name => 'CompositionToDecodeTimelineMapping',
|
---|
| 1850 | Flags => ['Binary','Unknown'],
|
---|
| 1851 | },
|
---|
[16842] | 1852 | );
|
---|
| 1853 |
|
---|
[24107] | 1854 | # MP4 audio sample description box (ref 5)
|
---|
| 1855 | %Image::ExifTool::QuickTime::AudioSampleDesc = (
|
---|
| 1856 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1857 | GROUPS => { 2 => 'Audio' },
|
---|
| 1858 | FORMAT => 'int16u',
|
---|
| 1859 | NOTES => 'MP4 audio sample description.',
|
---|
| 1860 | 2 => {
|
---|
| 1861 | Name => 'AudioFormat',
|
---|
| 1862 | Format => 'undef[4]',
|
---|
| 1863 | RawConv => q{
|
---|
| 1864 | return undef unless $val =~ /^[\w ]{4}$/i;
|
---|
| 1865 | # check for protected audio format
|
---|
| 1866 | $self->OverrideFileType('M4P') if $val eq 'drms' and $$self{VALUE}{FileType} eq 'M4A';
|
---|
| 1867 | return $val;
|
---|
| 1868 | },
|
---|
| 1869 | },
|
---|
| 1870 | 10 => { #PH
|
---|
| 1871 | Name => 'AudioVendorID',
|
---|
| 1872 | Format => 'undef[4]',
|
---|
| 1873 | RawConv => '$val eq "\0\0\0\0" ? undef : $val',
|
---|
| 1874 | PrintConv => \%vendorID,
|
---|
| 1875 | SeparateTable => 'VendorID',
|
---|
| 1876 | },
|
---|
| 1877 | 12 => 'AudioChannels',
|
---|
| 1878 | 13 => 'AudioBitsPerSample',
|
---|
| 1879 | 16 => { Name => 'AudioSampleRate', Format => 'fixed32u' },
|
---|
| 1880 | 28 => { #PH
|
---|
| 1881 | Name => 'AudioFormat',
|
---|
| 1882 | Format => 'undef[4]',
|
---|
| 1883 | RawConv => '$val =~ /^[\w ]{4}$/i ? $val : undef',
|
---|
| 1884 | Notes => 'in Casio MOV videos',
|
---|
| 1885 | },
|
---|
| 1886 | );
|
---|
| 1887 |
|
---|
| 1888 | # MP4 hint sample description box (ref 5)
|
---|
| 1889 | %Image::ExifTool::QuickTime::HintSampleDesc = (
|
---|
| 1890 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1891 | FORMAT => 'int16u',
|
---|
| 1892 | NOTES => 'MP4 hint sample description.',
|
---|
| 1893 | 2 => { Name => 'HintFormat', Format => 'undef[4]' },
|
---|
| 1894 | );
|
---|
| 1895 |
|
---|
| 1896 | # MP4 generic sample description box
|
---|
| 1897 | %Image::ExifTool::QuickTime::OtherSampleDesc = (
|
---|
| 1898 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1899 | FORMAT => 'int16u',
|
---|
| 1900 | 2 => { Name => 'OtherFormat', Format => 'undef[4]' },
|
---|
| 1901 | );
|
---|
| 1902 |
|
---|
| 1903 | # MP4 data information box (ref 5)
|
---|
| 1904 | %Image::ExifTool::QuickTime::DataInfo = (
|
---|
| 1905 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1906 | NOTES => 'MP4 data information box.',
|
---|
| 1907 | dref => {
|
---|
| 1908 | Name => 'DataRef',
|
---|
| 1909 | SubDirectory => {
|
---|
| 1910 | TagTable => 'Image::ExifTool::QuickTime::DataRef',
|
---|
| 1911 | Start => 8,
|
---|
| 1912 | },
|
---|
| 1913 | },
|
---|
| 1914 | );
|
---|
| 1915 |
|
---|
| 1916 | # Generic media header
|
---|
| 1917 | %Image::ExifTool::QuickTime::GenMediaHeader = (
|
---|
| 1918 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1919 | gmin => {
|
---|
| 1920 | Name => 'GenMediaInfo',
|
---|
| 1921 | SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaInfo' },
|
---|
| 1922 | },
|
---|
| 1923 | text => {
|
---|
| 1924 | Name => 'Text',
|
---|
| 1925 | Flags => ['Binary','Unknown'],
|
---|
| 1926 | },
|
---|
| 1927 | );
|
---|
| 1928 |
|
---|
| 1929 | # Generic media info (ref http://sourceforge.jp/cvs/view/ntvrec/ntvrec/libqtime/gmin.h?view=co)
|
---|
| 1930 | %Image::ExifTool::QuickTime::GenMediaInfo = (
|
---|
| 1931 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1932 | GROUPS => { 2 => 'Video' },
|
---|
| 1933 | 0 => 'GenMediaVersion',
|
---|
| 1934 | 1 => { Name => 'GenFlags', Format => 'int8u[3]' },
|
---|
| 1935 | 4 => { Name => 'GenGraphicsMode',
|
---|
| 1936 | Format => 'int16u',
|
---|
| 1937 | PrintHex => 1,
|
---|
| 1938 | SeparateTable => 'GraphicsMode',
|
---|
| 1939 | PrintConv => \%graphicsMode,
|
---|
| 1940 | },
|
---|
| 1941 | 6 => { Name => 'GenOpColor', Format => 'int16u[3]' },
|
---|
| 1942 | 12 => { Name => 'GenBalance', Format => 'fixed16s' },
|
---|
| 1943 | );
|
---|
| 1944 |
|
---|
| 1945 | # MP4 data reference box (ref 5)
|
---|
| 1946 | %Image::ExifTool::QuickTime::DataRef = (
|
---|
| 1947 | PROCESS_PROC => \&ProcessMOV,
|
---|
| 1948 | NOTES => 'MP4 data reference box.',
|
---|
| 1949 | 'url ' => {
|
---|
| 1950 | Name => 'URL',
|
---|
| 1951 | RawConv => q{
|
---|
| 1952 | # ignore if self-contained (flags bit 0 set)
|
---|
| 1953 | return undef if unpack("N",$val) & 0x01;
|
---|
| 1954 | $_ = substr($val,4); s/\0.*//s; $_;
|
---|
| 1955 | },
|
---|
| 1956 | },
|
---|
| 1957 | 'urn ' => {
|
---|
| 1958 | Name => 'URN',
|
---|
| 1959 | RawConv => q{
|
---|
| 1960 | return undef if unpack("N",$val) & 0x01;
|
---|
| 1961 | $_ = substr($val,4); s/\0.*//s; $_;
|
---|
| 1962 | },
|
---|
| 1963 | },
|
---|
| 1964 | );
|
---|
| 1965 |
|
---|
| 1966 | # MP4 handler box (ref 5)
|
---|
| 1967 | %Image::ExifTool::QuickTime::Handler = (
|
---|
| 1968 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 1969 | GROUPS => { 2 => 'Video' },
|
---|
| 1970 | 4 => { #PH
|
---|
| 1971 | Name => 'HandlerClass',
|
---|
| 1972 | Format => 'undef[4]',
|
---|
| 1973 | RawConv => '$val eq "\0\0\0\0" ? undef : $val',
|
---|
| 1974 | PrintConv => {
|
---|
| 1975 | mhlr => 'Media Handler',
|
---|
| 1976 | dhlr => 'Data Handler',
|
---|
| 1977 | },
|
---|
| 1978 | },
|
---|
| 1979 | 8 => {
|
---|
| 1980 | Name => 'HandlerType',
|
---|
| 1981 | Format => 'undef[4]',
|
---|
| 1982 | RawConv => '$$self{HandlerType} = $val unless $val eq "alis"; $val',
|
---|
| 1983 | PrintConv => {
|
---|
| 1984 | alis => 'Alias Data', #PH
|
---|
| 1985 | crsm => 'Clock Reference', #3
|
---|
| 1986 | hint => 'Hint Track',
|
---|
| 1987 | ipsm => 'IPMP', #3
|
---|
| 1988 | m7sm => 'MPEG-7 Stream', #3
|
---|
| 1989 | mdir => 'Metadata', #3
|
---|
| 1990 | mdta => 'Metadata Tags', #PH
|
---|
| 1991 | mjsm => 'MPEG-J', #3
|
---|
| 1992 | ocsm => 'Object Content', #3
|
---|
| 1993 | odsm => 'Object Descriptor', #3
|
---|
| 1994 | sdsm => 'Scene Description', #3
|
---|
| 1995 | soun => 'Audio Track',
|
---|
| 1996 | text => 'Text', #PH (but what type? subtitle?)
|
---|
| 1997 | 'url '=> 'URL', #3
|
---|
| 1998 | vide => 'Video Track',
|
---|
| 1999 | },
|
---|
| 2000 | },
|
---|
| 2001 | 12 => { #PH
|
---|
| 2002 | Name => 'HandlerVendorID',
|
---|
| 2003 | Format => 'undef[4]',
|
---|
| 2004 | RawConv => '$val eq "\0\0\0\0" ? undef : $val',
|
---|
| 2005 | PrintConv => \%vendorID,
|
---|
| 2006 | SeparateTable => 'VendorID',
|
---|
| 2007 | },
|
---|
| 2008 | 24 => {
|
---|
| 2009 | Name => 'HandlerDescription',
|
---|
| 2010 | Format => 'string',
|
---|
| 2011 | # (sometimes this is a Pascal string, and sometimes it is a C string)
|
---|
| 2012 | RawConv => q{
|
---|
| 2013 | $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val);
|
---|
| 2014 | length $val ? $val : undef;
|
---|
| 2015 | },
|
---|
| 2016 | },
|
---|
| 2017 | );
|
---|
| 2018 |
|
---|
| 2019 | # Flip uuid data (ref PH)
|
---|
| 2020 | %Image::ExifTool::QuickTime::Flip = (
|
---|
| 2021 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
| 2022 | FORMAT => 'int32u',
|
---|
| 2023 | FIRST_ENTRY => 0,
|
---|
| 2024 | NOTES => 'Found in MP4 files from Flip Video cameras.',
|
---|
| 2025 | GROUPS => { 1 => 'MakerNotes', 2 => 'Image' },
|
---|
| 2026 | 1 => 'PreviewImageWidth',
|
---|
| 2027 | 2 => 'PreviewImageHeight',
|
---|
| 2028 | 13 => 'PreviewImageLength',
|
---|
| 2029 | 14 => { # (confirmed for FlipVideoMinoHD)
|
---|
| 2030 | Name => 'SerialNumber',
|
---|
| 2031 | Groups => { 2 => 'Camera' },
|
---|
| 2032 | Format => 'string[16]',
|
---|
| 2033 | },
|
---|
| 2034 | 28 => {
|
---|
| 2035 | Name => 'PreviewImage',
|
---|
| 2036 | Format => 'undef[$val{13}]',
|
---|
| 2037 | RawConv => '$self->ValidateImage(\$val, $tag)',
|
---|
| 2038 | },
|
---|
| 2039 | );
|
---|
| 2040 |
|
---|
| 2041 | # QuickTime composite tags
|
---|
| 2042 | %Image::ExifTool::QuickTime::Composite = (
|
---|
| 2043 | GROUPS => { 2 => 'Video' },
|
---|
| 2044 | Rotation => {
|
---|
| 2045 | Require => {
|
---|
| 2046 | 0 => 'QuickTime:MatrixStructure',
|
---|
| 2047 | 1 => 'QuickTime:HandlerType',
|
---|
| 2048 | },
|
---|
| 2049 | ValueConv => 'Image::ExifTool::QuickTime::CalcRotation($self)',
|
---|
| 2050 | },
|
---|
| 2051 | AvgBitrate => {
|
---|
| 2052 | Priority => 0, # let QuickTime::AvgBitrate take priority
|
---|
| 2053 | Require => {
|
---|
| 2054 | 0 => 'QuickTime::MovieDataSize',
|
---|
| 2055 | 1 => 'QuickTime::Duration',
|
---|
| 2056 | },
|
---|
| 2057 | RawConv => q{
|
---|
| 2058 | return undef unless $val[1];
|
---|
| 2059 | $val[1] /= $$self{TimeScale} if $$self{TimeScale};
|
---|
| 2060 | return int($val[0] * 8 / $val[1] + 0.5);
|
---|
| 2061 | },
|
---|
| 2062 | PrintConv => 'ConvertBitrate($val)',
|
---|
| 2063 | },
|
---|
| 2064 | GPSLatitude => {
|
---|
| 2065 | Require => 'QuickTime:GPSCoordinates',
|
---|
| 2066 | Groups => { 2 => 'Location' },
|
---|
| 2067 | ValueConv => 'my @c = split " ", $val; $c[0]',
|
---|
| 2068 | PrintConv => q{
|
---|
| 2069 | require Image::ExifTool::GPS;
|
---|
| 2070 | Image::ExifTool::GPS::ToDMS($self, $val, 1, 'N');
|
---|
| 2071 | },
|
---|
| 2072 | },
|
---|
| 2073 | GPSLongitude => {
|
---|
| 2074 | Require => 'QuickTime:GPSCoordinates',
|
---|
| 2075 | Groups => { 2 => 'Location' },
|
---|
| 2076 | ValueConv => 'my @c = split " ", $val; $c[1]',
|
---|
| 2077 | PrintConv => q{
|
---|
| 2078 | require Image::ExifTool::GPS;
|
---|
| 2079 | Image::ExifTool::GPS::ToDMS($self, $val, 1, 'E');
|
---|
| 2080 | },
|
---|
| 2081 | },
|
---|
| 2082 | # split altitude into GPSAltitude/GPSAltitudeRef like EXIF and XMP
|
---|
| 2083 | GPSAltitude => {
|
---|
| 2084 | Require => 'QuickTime:GPSCoordinates',
|
---|
| 2085 | Groups => { 2 => 'Location' },
|
---|
| 2086 | Priority => 0, # (because it may not exist)
|
---|
| 2087 | ValueConv => 'my @c = split " ", $val; defined $c[2] ? abs($c[2]) : undef',
|
---|
| 2088 | PrintConv => '"$val m"',
|
---|
| 2089 | },
|
---|
| 2090 | GPSAltitudeRef => {
|
---|
| 2091 | Require => 'QuickTime:GPSCoordinates',
|
---|
| 2092 | Groups => { 2 => 'Location' },
|
---|
| 2093 | Priority => 0, # (because altitude information may not exist)
|
---|
| 2094 | ValueConv => 'my @c = split " ", $val; defined $c[2] ? ($c[2] < 0 ? 1 : 0) : undef',
|
---|
| 2095 | PrintConv => {
|
---|
| 2096 | 0 => 'Above Sea Level',
|
---|
| 2097 | 1 => 'Below Sea Level',
|
---|
| 2098 | },
|
---|
| 2099 | },
|
---|
| 2100 | );
|
---|
| 2101 |
|
---|
| 2102 | # add our composite tags
|
---|
| 2103 | Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime');
|
---|
| 2104 |
|
---|
| 2105 |
|
---|
[16842] | 2106 | #------------------------------------------------------------------------------
|
---|
[24107] | 2107 | # Calculate rotation of video track
|
---|
| 2108 | # Inputs: 0) ExifTool object ref
|
---|
| 2109 | # Returns: rotation angle or undef
|
---|
| 2110 | sub CalcRotation($)
|
---|
| 2111 | {
|
---|
| 2112 | my $exifTool = shift;
|
---|
| 2113 | my $value = $$exifTool{VALUE};
|
---|
| 2114 | my ($i, $track);
|
---|
| 2115 | # get the video track family 1 group (ie. "Track1");
|
---|
| 2116 | for ($i=0; ; ++$i) {
|
---|
| 2117 | my $idx = $i ? " ($i)" : '';
|
---|
| 2118 | my $tag = "HandlerType$idx";
|
---|
| 2119 | last unless $$value{$tag};
|
---|
| 2120 | next unless $$value{$tag} eq 'vide';
|
---|
| 2121 | $track = $exifTool->GetGroup($tag, 1);
|
---|
| 2122 | last;
|
---|
| 2123 | }
|
---|
| 2124 | return undef unless $track;
|
---|
| 2125 | # get the video track matrix
|
---|
| 2126 | for ($i=0; ; ++$i) {
|
---|
| 2127 | my $idx = $i ? " ($i)" : '';
|
---|
| 2128 | my $tag = "MatrixStructure$idx";
|
---|
| 2129 | last unless $$value{$tag};
|
---|
| 2130 | next unless $exifTool->GetGroup($tag, 1) eq $track;
|
---|
| 2131 | my @a = split ' ', $$value{$tag};
|
---|
| 2132 | return undef unless $a[0] or $a[1];
|
---|
| 2133 | # calculate the rotation angle (assume uniform rotation)
|
---|
| 2134 | my $angle = atan2($a[1], $a[0]) * 180 / 3.14159;
|
---|
| 2135 | $angle += 360 if $angle < 0;
|
---|
| 2136 | return int($angle * 1000 + 0.5) / 1000;
|
---|
| 2137 | }
|
---|
| 2138 | return undef;
|
---|
| 2139 | }
|
---|
| 2140 |
|
---|
| 2141 | #------------------------------------------------------------------------------
|
---|
| 2142 | # Determine the average sample rate from a time-to-sample table
|
---|
| 2143 | # Inputs: 0) ExifTool object ref, 1) time-to-sample table data ref
|
---|
| 2144 | # Returns: average sample rate (in Hz)
|
---|
| 2145 | sub CalcSampleRate($$)
|
---|
| 2146 | {
|
---|
| 2147 | my ($exifTool, $valPt) = @_;
|
---|
| 2148 | my @dat = unpack('N*', $$valPt);
|
---|
| 2149 | my ($num, $dur) = (0, 0);
|
---|
| 2150 | my $i;
|
---|
| 2151 | for ($i=2; $i<@dat-1; $i+=2) {
|
---|
| 2152 | $num += $dat[$i]; # total number of samples
|
---|
| 2153 | $dur += $dat[$i] * $dat[$i+1]; # total sample duration
|
---|
| 2154 | }
|
---|
| 2155 | return undef unless $num and $dur and $$exifTool{MediaTS};
|
---|
| 2156 | return $num * $$exifTool{MediaTS} / $dur;
|
---|
| 2157 | }
|
---|
| 2158 |
|
---|
| 2159 | #------------------------------------------------------------------------------
|
---|
[16842] | 2160 | # Fix incorrect format for ImageWidth/Height as written by Pentax
|
---|
| 2161 | sub FixWrongFormat($)
|
---|
| 2162 | {
|
---|
| 2163 | my $val = shift;
|
---|
| 2164 | return undef unless $val;
|
---|
| 2165 | if ($val & 0xffff0000) {
|
---|
| 2166 | $val = unpack('n',pack('N',$val));
|
---|
| 2167 | }
|
---|
| 2168 | return $val;
|
---|
| 2169 | }
|
---|
| 2170 |
|
---|
| 2171 | #------------------------------------------------------------------------------
|
---|
[24107] | 2172 | # Convert ISO 6709 string to standard lag/lon format
|
---|
| 2173 | # Inputs: 0) ISO 6709 string (lat, lon, and optional alt)
|
---|
| 2174 | # Returns: position in decimal degress with altitude if available
|
---|
| 2175 | # Notes: Wikipedia indicates altitude may be in feet -- how is this specified?
|
---|
| 2176 | sub ConvertISO6709($)
|
---|
| 2177 | {
|
---|
| 2178 | my $val = shift;
|
---|
| 2179 | if ($val =~ /^([-+]\d{2}(?:\.\d*)?)([-+]\d{3}(?:\.\d*)?)([-+]\d+)?/) {
|
---|
| 2180 | $val = ($1 + 0) . ' ' . ($2 + 0);
|
---|
| 2181 | $val .= ' ' . ($3 + 0) if $3;
|
---|
| 2182 | } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+)?/) {
|
---|
| 2183 | my $lat = $2 + $3 / 60;
|
---|
| 2184 | $lat = -$lat if $1 eq '-';
|
---|
| 2185 | my $lon = $5 + $6 / 60;
|
---|
| 2186 | $lon = -$lon if $4 eq '-';
|
---|
| 2187 | $val = "$lat $lon";
|
---|
| 2188 | $val .= ' ' . ($7 + 0) if $7;
|
---|
| 2189 | } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+)?/) {
|
---|
| 2190 | my $lat = $2 + $3 / 60 + $4 / 3600;
|
---|
| 2191 | $lat = -$lat if $1 eq '-';
|
---|
| 2192 | my $lon = $6 + $7 / 60 + $8 / 3600;
|
---|
| 2193 | $lon = -$lon if $5 eq '-';
|
---|
| 2194 | $val = "$lat $lon";
|
---|
| 2195 | $val .= ' ' . ($9 + 0) if $9;
|
---|
| 2196 | }
|
---|
| 2197 | return $val;
|
---|
| 2198 | }
|
---|
| 2199 |
|
---|
| 2200 | #------------------------------------------------------------------------------
|
---|
| 2201 | # Format GPSCoordinates for printing
|
---|
| 2202 | # Inputs: 0) string with numerical lat, lon and optional alt, separated by spaces
|
---|
| 2203 | # 1) ExifTool object reference
|
---|
| 2204 | # Returns: PrintConv value
|
---|
| 2205 | sub PrintGPSCoordinates($)
|
---|
| 2206 | {
|
---|
| 2207 | my ($val, $exifTool) = @_;
|
---|
| 2208 | require Image::ExifTool::GPS;
|
---|
| 2209 | my @v = split ' ', $val;
|
---|
| 2210 | my $prt = Image::ExifTool::GPS::ToDMS($exifTool, $v[0], 1, "N") . ', ' .
|
---|
| 2211 | Image::ExifTool::GPS::ToDMS($exifTool, $v[1], 1, "E");
|
---|
| 2212 | if (defined $v[2]) {
|
---|
| 2213 | $prt .= ', ' . ($v[2] < 0 ? -$v[2] . ' m Below' : $v[2] . ' m Above') . ' Sea Level';
|
---|
| 2214 | }
|
---|
| 2215 | return $prt;
|
---|
| 2216 | }
|
---|
| 2217 |
|
---|
| 2218 | #------------------------------------------------------------------------------
|
---|
| 2219 | # Unpack packed ISO 639/T language code
|
---|
| 2220 | # Inputs: 0) packed language code (or undef)
|
---|
| 2221 | # Returns: language code, or undef for default language, or 'err' for format error
|
---|
| 2222 | sub UnpackLang($)
|
---|
| 2223 | {
|
---|
| 2224 | my $lang = shift;
|
---|
| 2225 | if ($lang) {
|
---|
| 2226 | # language code is packed in 5-bit characters
|
---|
| 2227 | $lang = pack "C*", map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0;
|
---|
| 2228 | # validate language code
|
---|
| 2229 | if ($lang =~ /^[a-z]+$/) {
|
---|
| 2230 | # treat 'eng' or 'und' as the default language
|
---|
| 2231 | undef $lang if $lang eq 'und' or $lang eq 'eng';
|
---|
| 2232 | } else {
|
---|
| 2233 | $lang = 'err'; # invalid language code
|
---|
| 2234 | }
|
---|
| 2235 | }
|
---|
| 2236 | return $lang;
|
---|
| 2237 | }
|
---|
| 2238 |
|
---|
| 2239 | #------------------------------------------------------------------------------
|
---|
| 2240 | # Process MPEG-4 MTDT atom (ref 11)
|
---|
| 2241 | # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
---|
| 2242 | # Returns: 1 on success
|
---|
| 2243 | sub ProcessMetaData($$$)
|
---|
| 2244 | {
|
---|
| 2245 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
| 2246 | my $dataPt = $$dirInfo{DataPt};
|
---|
| 2247 | my $dirLen = length $$dataPt;
|
---|
| 2248 | my $verbose = $exifTool->Options('Verbose');
|
---|
| 2249 | return 0 unless $dirLen >= 2;
|
---|
| 2250 | my $count = Get16u($dataPt, 0);
|
---|
| 2251 | $verbose and $exifTool->VerboseDir('MetaData', $count);
|
---|
| 2252 | my $i;
|
---|
| 2253 | my $pos = 2;
|
---|
| 2254 | for ($i=0; $i<$count; ++$i) {
|
---|
| 2255 | last if $pos + 10 > $dirLen;
|
---|
| 2256 | my $size = Get16u($dataPt, $pos);
|
---|
| 2257 | last if $size < 10 or $size + $pos > $dirLen;
|
---|
| 2258 | my $tag = Get32u($dataPt, $pos + 2);
|
---|
| 2259 | my $lang = Get16u($dataPt, $pos + 6);
|
---|
| 2260 | my $enc = Get16u($dataPt, $pos + 8);
|
---|
| 2261 | my $val = substr($$dataPt, $pos + 10, $size);
|
---|
| 2262 | my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
|
---|
| 2263 | if ($tagInfo) {
|
---|
| 2264 | # convert language code to ASCII (ignore read-only bit)
|
---|
| 2265 | $lang = UnpackLang($lang);
|
---|
| 2266 | # handle alternate languages
|
---|
| 2267 | if ($lang) {
|
---|
| 2268 | my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang);
|
---|
| 2269 | $tagInfo = $langInfo if $langInfo;
|
---|
| 2270 | }
|
---|
| 2271 | $verbose and $exifTool->VerboseInfo($tag, $tagInfo,
|
---|
| 2272 | Value => $val,
|
---|
| 2273 | DataPt => $dataPt,
|
---|
| 2274 | Start => $pos + 10,
|
---|
| 2275 | Size => $size - 10,
|
---|
| 2276 | );
|
---|
| 2277 | # convert from UTF-16 BE if necessary
|
---|
| 2278 | $val = $exifTool->Decode($val, 'UCS2') if $enc == 1;
|
---|
| 2279 | if ($enc == 0 and $$tagInfo{Unknown}) {
|
---|
| 2280 | # binary data
|
---|
| 2281 | $exifTool->FoundTag($tagInfo, \$val);
|
---|
| 2282 | } else {
|
---|
| 2283 | $exifTool->FoundTag($tagInfo, $val);
|
---|
| 2284 | }
|
---|
| 2285 | }
|
---|
| 2286 | $pos += $size;
|
---|
| 2287 | }
|
---|
| 2288 | return 1;
|
---|
| 2289 | }
|
---|
| 2290 |
|
---|
| 2291 | #------------------------------------------------------------------------------
|
---|
| 2292 | # Process Meta keys and add tags to the ItemList table ('mdta' handler) (ref PH)
|
---|
| 2293 | # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
---|
| 2294 | # Returns: 1 on success
|
---|
| 2295 | sub ProcessKeys($$$)
|
---|
| 2296 | {
|
---|
| 2297 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
| 2298 | my $dataPt = $$dirInfo{DataPt};
|
---|
| 2299 | my $dirLen = length $$dataPt;
|
---|
| 2300 | my $out;
|
---|
| 2301 | if ($exifTool->Options('Verbose')) {
|
---|
| 2302 | $exifTool->VerboseDir('Keys');
|
---|
| 2303 | $out = $exifTool->Options('TextOut');
|
---|
| 2304 | }
|
---|
| 2305 | my $pos = 8;
|
---|
| 2306 | my $index = 1;
|
---|
| 2307 | my $infoTable = GetTagTable('Image::ExifTool::QuickTime::ItemList');
|
---|
| 2308 | my $userTable = GetTagTable('Image::ExifTool::QuickTime::UserData');
|
---|
| 2309 | while ($pos < $dirLen - 4) {
|
---|
| 2310 | my $len = unpack("x${pos}N", $$dataPt);
|
---|
| 2311 | last if $len < 8 or $pos + $len > $dirLen;
|
---|
| 2312 | delete $$tagTablePtr{$index};
|
---|
| 2313 | my $ns = substr($$dataPt, $pos + 4, 4);
|
---|
| 2314 | my $tag = substr($$dataPt, $pos + 8, $len - 8);
|
---|
| 2315 | $tag =~ s/\0.*//s; # truncate at null
|
---|
| 2316 | if ($ns eq 'mdta') {
|
---|
| 2317 | $tag =~ s/^com\.apple\.quicktime\.//; # remove common apple quicktime domain
|
---|
| 2318 | }
|
---|
| 2319 | next unless $tag;
|
---|
| 2320 | # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
|
---|
| 2321 | my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
|
---|
| 2322 | unless ($tagInfo) {
|
---|
| 2323 | $tagInfo = $exifTool->GetTagInfo($infoTable, $tag);
|
---|
| 2324 | unless ($tagInfo) {
|
---|
| 2325 | $tagInfo = $exifTool->GetTagInfo($userTable, $tag);
|
---|
| 2326 | if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) {
|
---|
| 2327 | $tag = pack('N', unpack('V', $tag));
|
---|
| 2328 | $tagInfo = $exifTool->GetTagInfo($infoTable, $tag);
|
---|
| 2329 | $tagInfo or $tagInfo = $exifTool->GetTagInfo($userTable, $tag);
|
---|
| 2330 | }
|
---|
| 2331 | }
|
---|
| 2332 | }
|
---|
| 2333 | my $newInfo;
|
---|
| 2334 | if ($tagInfo) {
|
---|
| 2335 | $newInfo = {
|
---|
| 2336 | Name => $$tagInfo{Name},
|
---|
| 2337 | Format => $$tagInfo{Format},
|
---|
| 2338 | ValueConv => $$tagInfo{ValueConv},
|
---|
| 2339 | PrintConv => $$tagInfo{PrintConv},
|
---|
| 2340 | };
|
---|
| 2341 | my $groups = $$tagInfo{Groups};
|
---|
| 2342 | $$newInfo{Groups} = { %$groups } if $groups;
|
---|
| 2343 | } elsif ($tag =~ /^[-\w.]+$/) {
|
---|
| 2344 | # create info for tags with reasonable id's
|
---|
| 2345 | my $name = $tag;
|
---|
| 2346 | $name =~ s/\.(.)/\U$1/g;
|
---|
| 2347 | $newInfo = { Name => ucfirst($name) };
|
---|
| 2348 | }
|
---|
| 2349 | # substitute this tag in the ItemList table with the given index
|
---|
| 2350 | delete $$infoTable{$index};
|
---|
| 2351 | if ($newInfo) {
|
---|
| 2352 | Image::ExifTool::AddTagToTable($infoTable, $index, $newInfo);
|
---|
| 2353 | $out and printf $out "%sAdded ItemList Tag 0x%.4x = $tag\n", $exifTool->{INDENT}, $index;
|
---|
| 2354 | }
|
---|
| 2355 | $pos += $len;
|
---|
| 2356 | ++$index;
|
---|
| 2357 | }
|
---|
| 2358 | return 1;
|
---|
| 2359 | }
|
---|
| 2360 |
|
---|
| 2361 | #------------------------------------------------------------------------------
|
---|
[16842] | 2362 | # Process a QuickTime atom
|
---|
[24107] | 2363 | # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) optional tag table ref
|
---|
[16842] | 2364 | # Returns: 1 on success
|
---|
| 2365 | sub ProcessMOV($$;$)
|
---|
| 2366 | {
|
---|
| 2367 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
| 2368 | my $raf = $$dirInfo{RAF};
|
---|
| 2369 | my $dataPt = $$dirInfo{DataPt};
|
---|
| 2370 | my $verbose = $exifTool->Options('Verbose');
|
---|
| 2371 | my $dataPos = $$dirInfo{Base} || 0;
|
---|
| 2372 | my ($buff, $tag, $size, $track);
|
---|
| 2373 |
|
---|
| 2374 | # more convenient to package data as a RandomAccess file
|
---|
| 2375 | $raf or $raf = new File::RandomAccess($dataPt);
|
---|
[24107] | 2376 | # skip leading bytes if necessary
|
---|
| 2377 | if ($$dirInfo{DirStart}) {
|
---|
| 2378 | $raf->Seek($$dirInfo{DirStart}, 1) or return 0;
|
---|
| 2379 | $dataPos += $$dirInfo{DirStart};
|
---|
| 2380 | }
|
---|
[16842] | 2381 | # read size/tag name atom header
|
---|
| 2382 | $raf->Read($buff,8) == 8 or return 0;
|
---|
| 2383 | $dataPos += 8;
|
---|
| 2384 | $tagTablePtr or $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main');
|
---|
| 2385 | ($size, $tag) = unpack('Na4', $buff);
|
---|
| 2386 | if ($dataPt) {
|
---|
| 2387 | $verbose and $exifTool->VerboseDir($$dirInfo{DirName});
|
---|
| 2388 | } else {
|
---|
| 2389 | # check on file type if called with a RAF
|
---|
| 2390 | $$tagTablePtr{$tag} or return 0;
|
---|
| 2391 | if ($tag eq 'ftyp') {
|
---|
[24107] | 2392 | # read ahead 4 bytes to see what type of file this is
|
---|
| 2393 | my $fileType;
|
---|
[16842] | 2394 | if ($raf->Read($buff, 4) == 4) {
|
---|
| 2395 | $raf->Seek(-4, 1);
|
---|
[24107] | 2396 | # see if we know the extension for this file type
|
---|
| 2397 | $fileType = $1 if $ftypLookup{$buff} and $ftypLookup{$buff} =~ /\(\.(\w+)/;
|
---|
[16842] | 2398 | }
|
---|
[24107] | 2399 | $fileType or $fileType = 'MP4'; # default to MP4
|
---|
| 2400 | $exifTool->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4');
|
---|
[16842] | 2401 | } else {
|
---|
| 2402 | $exifTool->SetFileType(); # MOV
|
---|
| 2403 | }
|
---|
| 2404 | SetByteOrder('MM');
|
---|
| 2405 | }
|
---|
| 2406 | for (;;) {
|
---|
| 2407 | if ($size < 8) {
|
---|
| 2408 | last if $size == 0;
|
---|
| 2409 | $size == 1 or $exifTool->Warn('Invalid atom size'), last;
|
---|
| 2410 | $raf->Read($buff, 8) == 8 or last;
|
---|
| 2411 | $dataPos += 8;
|
---|
| 2412 | my ($hi, $lo) = unpack('NN', $buff);
|
---|
[24107] | 2413 | $size = $lo;
|
---|
[16842] | 2414 | if ($hi or $lo > 0x7fffffff) {
|
---|
[24107] | 2415 | if ($hi > 0x7fffffff) {
|
---|
| 2416 | $exifTool->Warn('Invalid atom size');
|
---|
| 2417 | last;
|
---|
| 2418 | } elsif (not $exifTool->Options('LargeFileSupport')) {
|
---|
| 2419 | $exifTool->Warn('End of processing at large atom (LargeFileSupport not enabled)');
|
---|
| 2420 | last;
|
---|
| 2421 | }
|
---|
[16842] | 2422 | }
|
---|
[24107] | 2423 | $size = $hi * 4294967296 + $lo;
|
---|
[16842] | 2424 | }
|
---|
| 2425 | $size -= 8;
|
---|
| 2426 | my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
|
---|
[24107] | 2427 | # allow numerical tag ID's
|
---|
| 2428 | unless ($tagInfo) {
|
---|
| 2429 | my $num = unpack('N', $tag);
|
---|
| 2430 | if ($$tagTablePtr{$num}) {
|
---|
| 2431 | $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $num);
|
---|
| 2432 | $tag = $num;
|
---|
| 2433 | }
|
---|
| 2434 | }
|
---|
[16842] | 2435 | # generate tagInfo if Unknown option set
|
---|
| 2436 | if (not defined $tagInfo and ($exifTool->{OPTIONS}->{Unknown} or
|
---|
[24107] | 2437 | $verbose or $tag =~ /^\xa9/))
|
---|
[16842] | 2438 | {
|
---|
| 2439 | my $name = $tag;
|
---|
[24107] | 2440 | my $n = ($name =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg);
|
---|
| 2441 | # print in hex if tag is numerical
|
---|
| 2442 | $name = sprintf('0x%.4x',unpack('N',$tag)) if $n > 2;
|
---|
[16842] | 2443 | if ($name =~ /^xa9(.*)/) {
|
---|
| 2444 | $tagInfo = {
|
---|
| 2445 | Name => "UserData_$1",
|
---|
| 2446 | Description => "User Data $1",
|
---|
| 2447 | };
|
---|
| 2448 | } else {
|
---|
| 2449 | $tagInfo = {
|
---|
| 2450 | Name => "Unknown_$name",
|
---|
| 2451 | Description => "Unknown $name",
|
---|
| 2452 | Unknown => 1,
|
---|
| 2453 | Binary => 1,
|
---|
| 2454 | };
|
---|
| 2455 | }
|
---|
| 2456 | Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
---|
| 2457 | }
|
---|
[24107] | 2458 | # save required tag sizes
|
---|
| 2459 | $exifTool->HandleTag($tagTablePtr, "$tag-size", $size) if $$tagTablePtr{"$tag-size"};
|
---|
[16842] | 2460 | # load values only if associated with a tag (or verbose) and < 16MB long
|
---|
| 2461 | if ((defined $tagInfo or $verbose) and $size < 0x1000000) {
|
---|
| 2462 | my $val;
|
---|
| 2463 | unless ($raf->Read($val, $size) == $size) {
|
---|
| 2464 | $exifTool->Warn("Truncated '$tag' data");
|
---|
| 2465 | last;
|
---|
| 2466 | }
|
---|
| 2467 | # use value to get tag info if necessary
|
---|
| 2468 | $tagInfo or $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag, \$val);
|
---|
[24107] | 2469 | my $hasData = ($$dirInfo{HasData} and $val =~ /\0...data\0/s);
|
---|
[16842] | 2470 | if ($verbose and not $hasData) {
|
---|
| 2471 | $exifTool->VerboseInfo($tag, $tagInfo,
|
---|
| 2472 | Value => $val,
|
---|
| 2473 | DataPt => \$val,
|
---|
| 2474 | DataPos => $dataPos,
|
---|
| 2475 | );
|
---|
| 2476 | }
|
---|
| 2477 | if ($tagInfo) {
|
---|
| 2478 | my $subdir = $$tagInfo{SubDirectory};
|
---|
| 2479 | if ($subdir) {
|
---|
[24107] | 2480 | my $start = $$subdir{Start} || 0;
|
---|
| 2481 | my ($base, $dPos) = ($dataPos, 0);
|
---|
| 2482 | if ($$subdir{Base}) {
|
---|
| 2483 | $dPos -= eval $$subdir{Base};
|
---|
| 2484 | $base -= $dPos;
|
---|
| 2485 | }
|
---|
[16842] | 2486 | my %dirInfo = (
|
---|
[24107] | 2487 | DataPt => \$val,
|
---|
| 2488 | DataLen => $size,
|
---|
| 2489 | DirStart => $start,
|
---|
| 2490 | DirLen => $size - $start,
|
---|
| 2491 | DirName => $$subdir{DirName} || $$tagInfo{Name},
|
---|
| 2492 | HasData => $$subdir{HasData},
|
---|
| 2493 | Multi => $$subdir{Multi},
|
---|
| 2494 | DataPos => $dPos,
|
---|
[16842] | 2495 | # Base needed for IsOffset tags in binary data
|
---|
[24107] | 2496 | Base => $base,
|
---|
[16842] | 2497 | );
|
---|
| 2498 | if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) {
|
---|
| 2499 | SetByteOrder('II');
|
---|
| 2500 | }
|
---|
[24107] | 2501 | my $oldGroup1 = $exifTool->{SET_GROUP1};
|
---|
[16842] | 2502 | if ($$tagInfo{Name} eq 'Track') {
|
---|
| 2503 | $track or $track = 0;
|
---|
| 2504 | $exifTool->{SET_GROUP1} = 'Track' . (++$track);
|
---|
| 2505 | }
|
---|
| 2506 | my $subTable = GetTagTable($$subdir{TagTable});
|
---|
[24107] | 2507 | my $proc = $$subdir{ProcessProc};
|
---|
| 2508 | $exifTool->ProcessDirectory(\%dirInfo, $subTable, $proc) if $size > $start;
|
---|
| 2509 | $exifTool->{SET_GROUP1} = $oldGroup1;
|
---|
[16842] | 2510 | SetByteOrder('MM');
|
---|
| 2511 | } elsif ($hasData) {
|
---|
| 2512 | # handle atoms containing 'data' tags
|
---|
[24107] | 2513 | # (currently ignore contained atoms: 'itif', 'name', etc.)
|
---|
[16842] | 2514 | my $pos = 0;
|
---|
| 2515 | for (;;) {
|
---|
| 2516 | last if $pos + 16 > $size;
|
---|
[24107] | 2517 | my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val);
|
---|
[16842] | 2518 | last if $pos + $len > $size;
|
---|
| 2519 | my $value;
|
---|
[24107] | 2520 | my $format = $$tagInfo{Format};
|
---|
[16842] | 2521 | if ($type eq 'data' and $len >= 16) {
|
---|
| 2522 | $pos += 16;
|
---|
| 2523 | $len -= 16;
|
---|
| 2524 | $value = substr($val, $pos, $len);
|
---|
[24107] | 2525 | # format flags (ref 12):
|
---|
| 2526 | # 0x0=binary, 0x1=UTF-8, 0x2=UTF-16, 0x3=ShiftJIS,
|
---|
| 2527 | # 0x4=UTF-8 0x5=UTF-16, 0xd=JPEG, 0xe=PNG,
|
---|
| 2528 | # 0x15=signed int, 0x16=unsigned int, 0x17=float,
|
---|
| 2529 | # 0x18=double, 0x1b=BMP, 0x1c='meta' atom
|
---|
| 2530 | if ($stringEncoding{$flags}) {
|
---|
| 2531 | # handle all string formats
|
---|
| 2532 | $value = $exifTool->Decode($value, $stringEncoding{$flags});
|
---|
| 2533 | } else {
|
---|
| 2534 | if (not $format) {
|
---|
| 2535 | if ($flags == 0x15 or $flags == 0x16) {
|
---|
| 2536 | $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
|
---|
| 2537 | $format .= $flags == 0x15 ? 's' : 'u' if $format;
|
---|
| 2538 | } elsif ($flags == 0x17) {
|
---|
| 2539 | $format = 'float';
|
---|
| 2540 | } elsif ($flags == 0x18) {
|
---|
| 2541 | $format = 'double';
|
---|
| 2542 | } elsif ($flags == 0x00) {
|
---|
| 2543 | # read 1 and 2-byte binary as integers
|
---|
| 2544 | if ($len == 1) {
|
---|
| 2545 | $format = 'int8u',
|
---|
| 2546 | } elsif ($len == 2) {
|
---|
| 2547 | $format = 'int16u',
|
---|
| 2548 | }
|
---|
| 2549 | }
|
---|
| 2550 | }
|
---|
| 2551 | if ($format) {
|
---|
| 2552 | $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len);
|
---|
| 2553 | } elsif (not $$tagInfo{ValueConv}) {
|
---|
| 2554 | # make binary data a scalar reference unless a ValueConv exists
|
---|
| 2555 | my $buf = $value;
|
---|
| 2556 | $value = \$buf;
|
---|
| 2557 | }
|
---|
[16842] | 2558 | }
|
---|
| 2559 | }
|
---|
[24107] | 2560 | my $langInfo;
|
---|
| 2561 | if ($ctry or $lang) {
|
---|
| 2562 | # ignore country ('ctry') and language lists ('lang') for now
|
---|
| 2563 | undef $ctry if $ctry and $ctry <= 255;
|
---|
| 2564 | undef $lang if $lang and $lang <= 255;
|
---|
| 2565 | $lang = UnpackLang($lang);
|
---|
| 2566 | # add country code if specified
|
---|
| 2567 | if ($ctry) {
|
---|
| 2568 | $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1
|
---|
| 2569 | # treat 'ZZ' like a default country (see ref 12)
|
---|
| 2570 | undef $ctry if $ctry eq 'ZZ';
|
---|
| 2571 | if ($ctry and $ctry =~ /^[A-Z]{2}$/) {
|
---|
| 2572 | $lang or $lang = 'und';
|
---|
| 2573 | $lang .= "-$ctry";
|
---|
| 2574 | }
|
---|
| 2575 | }
|
---|
| 2576 | $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang) if $lang;
|
---|
| 2577 | }
|
---|
| 2578 | $langInfo or $langInfo = $tagInfo;
|
---|
| 2579 | $exifTool->VerboseInfo($tag, $langInfo,
|
---|
| 2580 | Value => ref $value ? $$value : $value,
|
---|
| 2581 | DataPt => \$val,
|
---|
[16842] | 2582 | DataPos => $dataPos,
|
---|
[24107] | 2583 | Start => $pos,
|
---|
| 2584 | Size => $len,
|
---|
| 2585 | Format => $format,
|
---|
| 2586 | Extra => sprintf(", Type='$type', Flags=0x%x",$flags)
|
---|
[16842] | 2587 | ) if $verbose;
|
---|
[24107] | 2588 | $exifTool->FoundTag($langInfo, $value) if defined $value;
|
---|
[16842] | 2589 | $pos += $len;
|
---|
| 2590 | }
|
---|
[24107] | 2591 | } elsif ($tag =~ /^\xa9/) {
|
---|
| 2592 | # parse international text to extract all languages
|
---|
| 2593 | my $pos = 0;
|
---|
| 2594 | for (;;) {
|
---|
| 2595 | last if $pos + 4 > $size;
|
---|
| 2596 | my ($len, $lang) = unpack("x${pos}nn", $val);
|
---|
| 2597 | $pos += 4;
|
---|
| 2598 | # according to the QuickTime spec (ref 12), $len should include
|
---|
| 2599 | # 4 bytes for length and type words, but nobody (including
|
---|
| 2600 | # Apple, Pentax and Kodak) seems to add these in, so try
|
---|
| 2601 | # to allow for either
|
---|
| 2602 | if ($pos + $len > $size) {
|
---|
| 2603 | $len -= 4;
|
---|
| 2604 | last if $pos + $len > $size or $len < 0;
|
---|
| 2605 | }
|
---|
| 2606 | # ignore any empty entries (or null padding) after the first
|
---|
| 2607 | next if not $len and $pos;
|
---|
| 2608 | my $str = substr($val, $pos, $len);
|
---|
| 2609 | my $langInfo;
|
---|
| 2610 | if ($lang < 0x400) {
|
---|
| 2611 | # this is a Macintosh language code
|
---|
| 2612 | # a language code of 0 is Macintosh english, so treat as default
|
---|
| 2613 | if ($lang) {
|
---|
| 2614 | # use Font.pm to look up language string
|
---|
| 2615 | require Image::ExifTool::Font;
|
---|
| 2616 | $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang};
|
---|
| 2617 | }
|
---|
| 2618 | # the spec says only "Macintosh text encoding", so
|
---|
| 2619 | # I can only assume that it is the most common one
|
---|
| 2620 | $str = $exifTool->Decode($str, 'MacRoman');
|
---|
| 2621 | } else {
|
---|
| 2622 | # convert language code to ASCII (ignore read-only bit)
|
---|
| 2623 | $lang = UnpackLang($lang);
|
---|
| 2624 | # may be either UTF-8 or UTF-16BE
|
---|
| 2625 | my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
|
---|
| 2626 | $str = $exifTool->Decode($str, $enc);
|
---|
| 2627 | }
|
---|
| 2628 | $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang) if $lang;
|
---|
| 2629 | $exifTool->FoundTag($langInfo || $tagInfo, $str);
|
---|
| 2630 | $pos += $len;
|
---|
| 2631 | }
|
---|
[16842] | 2632 | } else {
|
---|
[24107] | 2633 | if ($$tagInfo{Format}) {
|
---|
[16842] | 2634 | $val = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val));
|
---|
| 2635 | }
|
---|
| 2636 | $exifTool->FoundTag($tagInfo, $val);
|
---|
| 2637 | }
|
---|
| 2638 | }
|
---|
| 2639 | } else {
|
---|
| 2640 | $raf->Seek($size, 1) or $exifTool->Warn("Truncated '$tag' data"), last;
|
---|
| 2641 | }
|
---|
| 2642 | $raf->Read($buff, 8) == 8 or last;
|
---|
| 2643 | $dataPos += $size + 8;
|
---|
| 2644 | ($size, $tag) = unpack('Na4', $buff);
|
---|
| 2645 | }
|
---|
| 2646 | return 1;
|
---|
| 2647 | }
|
---|
| 2648 |
|
---|
| 2649 | #------------------------------------------------------------------------------
|
---|
| 2650 | # Process a QuickTime Image File
|
---|
| 2651 | # Inputs: 0) ExifTool object reference, 1) directory information reference
|
---|
| 2652 | # Returns: 1 on success
|
---|
| 2653 | sub ProcessQTIF($$)
|
---|
| 2654 | {
|
---|
[24107] | 2655 | my ($exifTool, $dirInfo) = @_;
|
---|
[16842] | 2656 | my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile');
|
---|
[24107] | 2657 | return ProcessMOV($exifTool, $dirInfo, $table);
|
---|
[16842] | 2658 | }
|
---|
| 2659 |
|
---|
| 2660 | 1; # end
|
---|
| 2661 |
|
---|
| 2662 | __END__
|
---|
| 2663 |
|
---|
| 2664 | =head1 NAME
|
---|
| 2665 |
|
---|
| 2666 | Image::ExifTool::QuickTime - Read QuickTime and MP4 meta information
|
---|
| 2667 |
|
---|
| 2668 | =head1 SYNOPSIS
|
---|
| 2669 |
|
---|
| 2670 | This module is used by Image::ExifTool
|
---|
| 2671 |
|
---|
| 2672 | =head1 DESCRIPTION
|
---|
| 2673 |
|
---|
| 2674 | This module contains routines required by Image::ExifTool to extract
|
---|
| 2675 | information from QuickTime and MP4 video, and M4A audio files.
|
---|
| 2676 |
|
---|
| 2677 | =head1 AUTHOR
|
---|
| 2678 |
|
---|
[24107] | 2679 | Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
|
---|
[16842] | 2680 |
|
---|
| 2681 | This library is free software; you can redistribute it and/or modify it
|
---|
| 2682 | under the same terms as Perl itself.
|
---|
| 2683 |
|
---|
| 2684 | =head1 REFERENCES
|
---|
| 2685 |
|
---|
| 2686 | =over 4
|
---|
| 2687 |
|
---|
[24107] | 2688 | =item L<http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html>
|
---|
[16842] | 2689 |
|
---|
[24107] | 2690 | =item L<http://search.cpan.org/dist/MP4-Info-1.04/>
|
---|
| 2691 |
|
---|
| 2692 | =item L<http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt>
|
---|
| 2693 |
|
---|
| 2694 | =item L<http://wiki.multimedia.cx/index.php?title=Apple_QuickTime>
|
---|
| 2695 |
|
---|
| 2696 | =item L<http://atomicparsley.sourceforge.net/mpeg-4files.html>
|
---|
| 2697 |
|
---|
| 2698 | =item L<http://wiki.multimedia.cx/index.php?title=QuickTime_container>
|
---|
| 2699 |
|
---|
| 2700 | =item L<http://code.google.com/p/mp4v2/wiki/iTunesMetadata>
|
---|
| 2701 |
|
---|
| 2702 | =item L<http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf>
|
---|
| 2703 |
|
---|
| 2704 | =item L<http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf>
|
---|
| 2705 |
|
---|
[16842] | 2706 | =back
|
---|
| 2707 |
|
---|
| 2708 | =head1 SEE ALSO
|
---|
| 2709 |
|
---|
| 2710 | L<Image::ExifTool::TagNames/QuickTime Tags>,
|
---|
| 2711 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
| 2712 |
|
---|
| 2713 | =cut
|
---|
| 2714 |
|
---|