source: gs2-extensions/parallel-building/trunk/src/perllib/cpan/Image/ExifTool/Real.pm@ 24626

Last change on this file since 24626 was 24626, checked in by jmt12, 13 years ago

An (almost) complete copy of the perllib directory from a (circa SEP2011) head checkout from Greenstone 2 trunk - in order to try and make merging in this extension a little easier later on (as there have been some major changes to buildcol.pl commited in the main trunk but not in the x64 branch)

File size: 27.0 KB
Line 
1#------------------------------------------------------------------------------
2# File: Real.pm
3#
4# Description: Read Real audio/video meta information
5#
6# Revisions: 05/16/2006 - P. Harvey Created
7#
8# References: 1) http://www.getid3.org/
9# 2) https://common.helixcommunity.org/nonav/2003/HCS_SDK_r5/htmfiles/rmff.htm
10#------------------------------------------------------------------------------
11
12package Image::ExifTool::Real;
13
14use strict;
15use vars qw($VERSION);
16use Image::ExifTool qw(:DataAccess :Utils);
17use Image::ExifTool::Canon;
18
19$VERSION = '1.04';
20
21sub ProcessRealMeta($$$);
22sub ProcessRealProperties($$$);
23
24# Real property types (ref PH)
25my %propertyType = (
26 0 => 'int32u',
27 2 => 'string',
28);
29
30# Real Metadata property types
31my %metadataFormat = (
32 1 => 'string', # text
33 2 => 'string', # text list
34 3 => 'flag', # 1 or 4 byte integer
35 4 => 'int32u', # 4-byte integer
36 5 => 'undef', # binary data
37 6 => 'string', # URL
38 7 => 'string', # date
39 8 => 'string', # file name
40 9 => undef, # grouping
41 10 => undef, # reference
42);
43
44# Real Metadata property flag bit descriptions
45my %metadataFlag = (
46 0 => 'Read Only',
47 1 => 'Private',
48 2 => 'Type Descriptor',
49);
50
51
52# tags used in RealMedia (RM, RV and RMVB) files
53%Image::ExifTool::Real::Media = (
54 GROUPS => { 2 => 'Video' },
55 NOTES => q{
56 These B<Tag ID>'s are Chunk ID's used in RealMedia and RealVideo (RM, RV and
57 RMVB) files.
58 },
59 CONT => { SubDirectory => { TagTable => 'Image::ExifTool::Real::ContentDescr' } },
60 MDPR => { SubDirectory => { TagTable => 'Image::ExifTool::Real::MediaProps' } },
61 PROP => { SubDirectory => { TagTable => 'Image::ExifTool::Real::Properties' } },
62 RJMD => { SubDirectory => { TagTable => 'Image::ExifTool::Real::Metadata' } },
63);
64
65# pseudo-tags used in RealAudio (RA) files
66%Image::ExifTool::Real::Audio = (
67 GROUPS => { 2 => 'Audio' },
68 NOTES => q{
69 Tags in the following table reference information extracted from various
70 versions of RealAudio (RA) files.
71 },
72 '.ra3' => { Name => 'RA3', SubDirectory => { TagTable => 'Image::ExifTool::Real::AudioV3' } },
73 '.ra4' => { Name => 'RA4', SubDirectory => { TagTable => 'Image::ExifTool::Real::AudioV4' } },
74 '.ra5' => { Name => 'RA5', SubDirectory => { TagTable => 'Image::ExifTool::Real::AudioV5' } },
75);
76
77# pseudo-tags used in RealMedia Metafiles and RealMedia Plug-in Metafiles (RAM and RPM)
78%Image::ExifTool::Real::Metafile = (
79 GROUPS => { 2 => 'Video' },
80 NOTES => q{
81 Tags representing information extracted from Real Audio Metafile and
82 RealMedia Plug-in Metafile (RAM and RPM) files.
83 },
84 txt => 'Text',
85 url => 'URL',
86);
87
88%Image::ExifTool::Real::Properties = (
89 GROUPS => { 1 => 'Real-PROP', 2 => 'Video' },
90 PROCESS_PROC => \&Image::ExifTool::Canon::ProcessSerialData,
91 VARS => { ID_LABEL => 'Sequence' },
92 FORMAT => 'int32u',
93 0 => { Name => 'MaxBitrate', PrintConv => 'ConvertBitrate($val)' },
94 1 => { Name => 'AvgBitrate', PrintConv => 'ConvertBitrate($val)' },
95 2 => 'MaxPacketSize',
96 3 => 'AvgPacketSize',
97 4 => 'NumPackets',
98 5 => { Name => 'Duration', ValueConv => '$val / 1000', PrintConv => 'ConvertDuration($val)' },
99 6 => { Name => 'Preroll', ValueConv => '$val / 1000', PrintConv => 'ConvertDuration($val)' },
100 7 => { Name => 'IndexOffset', Unknown => 1 },
101 8 => { Name => 'DataOffset', Unknown => 1 },
102 9 => { Name => 'NumStreams', Format => 'int16u' },
103 10 => {
104 Name => 'Flags',
105 Format => 'int16u',
106 PrintConv => { BITMASK => {
107 0 => 'Allow Recording',
108 1 => 'Perfect Play',
109 2 => 'Live',
110 3 => 'Allow Download', #PH (from rmeditor dump)
111 } },
112 },
113);
114
115%Image::ExifTool::Real::MediaProps = (
116 GROUPS => { 1 => 'Real-MDPR', 2 => 'Video' },
117 PROCESS_PROC => \&Image::ExifTool::Canon::ProcessSerialData,
118 VARS => { ID_LABEL => 'Sequence' },
119 FORMAT => 'int32u',
120 PRIORITY => 0, # first stream takes priority
121 0 => { Name => 'StreamNumber', Format => 'int16u' },
122 1 => { Name => 'StreamMaxBitrate', PrintConv => 'ConvertBitrate($val)' },
123 2 => { Name => 'StreamAvgBitrate', PrintConv => 'ConvertBitrate($val)' },
124 3 => { Name => 'StreamMaxPacketSize' },
125 4 => { Name => 'StreamAvgPacketSize' },
126 5 => { Name => 'StreamStartTime' },
127 6 => { Name => 'StreamPreroll', ValueConv => '$val / 1000', PrintConv => 'ConvertDuration($val)' },
128 7 => { Name => 'StreamDuration',ValueConv => '$val / 1000', PrintConv => 'ConvertDuration($val)' },
129 8 => { Name => 'StreamNameLen', Format => 'int8u', Unknown => 1 },
130 9 => { Name => 'StreamName', Format => 'string[$val{8}]' },
131 10 => { Name => 'StreamMimeLen', Format => 'int8u', Unknown => 1 },
132 11 => {
133 Name => 'StreamMimeType',
134 Format => 'string[$val{10}]',
135 RawConv => '$self->{RealStreamMime} = $val',
136 },
137 12 => { Name => 'FileInfoLen', Unknown => 1 },
138 13 => {
139 Name => 'FileInfoLen2',
140 # if this condition fails, subsequent tags will not be processed
141 Condition => '$self->{RealStreamMime} eq "logical-fileinfo"',
142 Unknown => 1,
143 },
144 14 => {
145 Name => 'FileInfoVersion',
146 Format => 'int16u',
147 },
148 15 => {
149 Name => 'PhysicalStreams',
150 Format => 'int16u',
151 Unknown => 1,
152 },
153 16 => {
154 Name => 'PhysicalStreamNumbers',
155 Format => 'int16u[$val{15}]',
156 Unknown => 1,
157 },
158 17 => {
159 Name => 'DataOffsets',
160 Format => 'int32u[$val{15}]',
161 Unknown => 1,
162 },
163 18 => {
164 Name => 'NumRules',
165 Format => 'int16u',
166 Unknown => 1,
167 },
168 19 => {
169 Name => 'PhysicalStreamNumberMap',
170 Format => 'int16u[$val{18}]',
171 Unknown => 1,
172 },
173 20 => {
174 Name => 'NumProperties',
175 Format => 'int16u',
176 Unknown => 1,
177 },
178 21 => {
179 Name => 'FileInfoProperties',
180 Format => 'undef[$val{13}-$val{15}*6-$val{18}*2-12]',
181 SubDirectory => { TagTable => 'Image::ExifTool::Real::FileInfo' },
182 },
183);
184
185# Observed FileInfo properties (ref PH)
186%Image::ExifTool::Real::FileInfo = (
187 GROUPS => { 1 => 'Real-MDPR', 2 => 'Video' },
188 PROCESS_PROC => \&ProcessRealProperties,
189 NOTES => q{
190 The following tags have been observed in the FileInfo properties, but any
191 other existing information will also be extracted.
192 },
193 Indexable => { PrintConv => { 0 => 'False', 1 => 'True' } },
194 Keywords => { },
195 Description => { },
196 'File ID' => { Name => 'FileID' },
197 'Content Rating' => {
198 Name => 'ContentRating',
199 PrintConv => {
200 0 => 'No Rating',
201 1 => 'All Ages',
202 2 => 'Older Children',
203 3 => 'Younger Teens',
204 4 => 'Older Teens',
205 5 => 'Adult Supervision Recommended',
206 6 => 'Adults Only',
207 },
208 },
209 Audiences => { },
210 audioMode => { Name => 'AudioMode' },
211 'Creation Date' => {
212 Name => 'CreateDate',
213 Groups => { 2 => 'Time' },
214 ValueConv => q{
215 $val =~ m{(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)} ?
216 sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",$3,$2,$1,$4,$5,$6) : $val
217 },
218 PrintConv => '$self->ConvertDateTime($val)',
219 },
220 'Generated By' => { Name => 'Software' },
221 'Modification Date' => {
222 Name => 'ModifyDate',
223 Groups => { 2 => 'Time' },
224 ValueConv => q{
225 $val =~ m{(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)} ?
226 sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",$3,$2,$1,$4,$5,$6) : $val
227 },
228 PrintConv => '$self->ConvertDateTime($val)',
229 },
230 'Target Audiences' => { Name => 'TargetAudiences' },
231 'Audio Format' => { Name => 'AudioFormat' },
232 'Video Quality' => { Name => 'VideoQuality' },
233 videoMode => { Name => 'VideoMode' },
234);
235
236%Image::ExifTool::Real::ContentDescr = (
237 GROUPS => { 1 => 'Real-CONT', 2 => 'Video' },
238 PROCESS_PROC => \&Image::ExifTool::Canon::ProcessSerialData,
239 VARS => { ID_LABEL => 'Sequence' },
240 FORMAT => 'int16u',
241 0 => { Name => 'TitleLen', Unknown => 1 },
242 1 => { Name => 'Title', Format => 'string[$val{0}]' },
243 2 => { Name => 'AuthorLen', Unknown => 1 },
244 3 => { Name => 'Author', Format => 'string[$val{2}]', Groups => { 2 => 'Author' } },
245 4 => { Name => 'CopyrightLen', Unknown => 1 },
246 5 => { Name => 'Copyright', Format => 'string[$val{4}]', Groups => { 2 => 'Author' } },
247 6 => { Name => 'CommentLen', Unknown => 1 },
248 7 => { Name => 'Comment', Format => 'string[$val{6}]' },
249);
250
251# Real RJMD meta information (ref PH)
252%Image::ExifTool::Real::Metadata = (
253 GROUPS => { 1 => 'Real-RJMD', 2 => 'Video' },
254 PROCESS_PROC => \&ProcessRealMeta,
255 NOTES => q{
256 The tags below represent information which has been observed in the Real
257 Metadata format, but ExifTool will extract any information it finds in this
258 format. (As far as I can tell from the referenced documentation, string
259 values should be plain text, but this is not the case for the only sample
260 file I have been able to obtain containing this information. These tags
261 could also be split into separate sub-directories, but this will wait until
262 I have better documentation or a more complete set of samples.)
263 },
264 'Album/Name' => 'AlbumName',
265 'Track/Category' => 'TrackCategory',
266 'Track/Comments' => 'TrackComments',
267 'Track/Lyrics' => 'TrackLyrics',
268);
269
270%Image::ExifTool::Real::AudioV3 = (
271 GROUPS => { 1 => 'Real-RA3', 2 => 'Audio' },
272 PROCESS_PROC => \&Image::ExifTool::Canon::ProcessSerialData,
273 VARS => { ID_LABEL => 'Sequence' },
274 FORMAT => 'int8u',
275 0 => { Name => 'Channels', Format => 'int16u' },
276 1 => { Name => 'Unknown', Format => 'int16u[3]', Unknown => 1 },
277 2 => { Name => 'BytesPerMinute', Format => 'int16u' },
278 3 => { Name => 'AudioBytes', Format => 'int32u' },
279 4 => { Name => 'TitleLen', Unknown => 1 },
280 5 => { Name => 'Title', Format => 'string[$val{4}]' },
281 6 => { Name => 'ArtistLen', Unknown => 1 },
282 7 => { Name => 'Artist', Format => 'string[$val{6}]', Groups => { 2 => 'Author' } },
283 8 => { Name => 'CopyrightLen', Unknown => 1 },
284 9 => { Name => 'Copyright', Format => 'string[$val{8}]', Groups => { 2 => 'Author' } },
285 10 => { Name => 'CommentLen', Unknown => 1 },
286 11 => { Name => 'Comment', Format => 'string[$val{10}]' },
287);
288
289%Image::ExifTool::Real::AudioV4 = (
290 GROUPS => { 1 => 'Real-RA4', 2 => 'Audio' },
291 PROCESS_PROC => \&Image::ExifTool::Canon::ProcessSerialData,
292 VARS => { ID_LABEL => 'Sequence' },
293 FORMAT => 'int16u',
294 0 => { Name => 'FourCC1', Format => 'undef[4]', Unknown => 1 },
295 1 => { Name => 'AudioFileSize', Format => 'int32u', Unknown => 1 },
296 2 => { Name => 'Version2', Unknown => 1 },
297 3 => { Name => 'HeaderSize', Format => 'int32u', Unknown => 1 },
298 4 => { Name => 'CodecFlavorID', Unknown => 1 },
299 5 => { Name => 'CodedFrameSize', Format => 'int32u', Unknown => 1 },
300 6 => { Name => 'AudioBytes', Format => 'int32u' },
301 7 => { Name => 'BytesPerMinute', Format => 'int32u' },
302 8 => { Name => 'Unknown', Format => 'int32u', Unknown => 1 },
303 9 => { Name => 'SubPacketH', Unknown => 1 },
304 10 => 'AudioFrameSize',
305 11 => { Name => 'SubPacketSize', Unknown => 1 },
306 12 => { Name => 'Unknown', Unknown => 1 },
307 13 => 'SampleRate',
308 14 => { Name => 'Unknown', Unknown => 1 },
309 15 => 'BitsPerSample',
310 16 => 'Channels',
311 17 => { Name => 'FourCC2Len', Format => 'int8u', Unknown => 1 },
312 18 => { Name => 'FourCC2', Format => 'undef[4]', Unknown => 1 },
313 19 => { Name => 'FourCC3Len', Format => 'int8u', Unknown => 1 },
314 20 => { Name => 'FourCC3', Format => 'undef[4]', Unknown => 1 },
315 21 => { Name => 'Unknown', Format => 'int8u', Unknown => 1 },
316 22 => { Name => 'Unknown', Unknown => 1 },
317 23 => { Name => 'TitleLen', Format => 'int8u', Unknown => 1 },
318 24 => { Name => 'Title', Format => 'string[$val{23}]' },
319 25 => { Name => 'ArtistLen', Format => 'int8u', Unknown => 1 },
320 26 => { Name => 'Artist', Format => 'string[$val{25}]', Groups => { 2 => 'Author' } },
321 27 => { Name => 'CopyrightLen', Format => 'int8u', Unknown => 1 },
322 28 => { Name => 'Copyright', Format => 'string[$val{27}]', Groups => { 2 => 'Author' } },
323 29 => { Name => 'CommentLen', Format => 'int8u', Unknown => 1 },
324 30 => { Name => 'Comment', Format => 'string[$val{29}]' },
325);
326
327%Image::ExifTool::Real::AudioV5 = (
328 GROUPS => { 1 => 'Real-RA5', 2 => 'Audio' },
329 PROCESS_PROC => \&Image::ExifTool::Canon::ProcessSerialData,
330 VARS => { ID_LABEL => 'Sequence' },
331 FORMAT => 'int16u',
332 0 => { Name => 'FourCC1', Format => 'undef[4]', Unknown => 1 },
333 1 => { Name => 'AudioFileSize', Format => 'int32u', Unknown => 1 },
334 2 => { Name => 'Version2', Unknown => 1 },
335 3 => { Name => 'HeaderSize', Format => 'int32u', Unknown => 1 },
336 4 => { Name => 'CodecFlavorID', Unknown => 1 },
337 5 => { Name => 'CodedFrameSize', Format => 'int32u', Unknown => 1 },
338 6 => { Name => 'AudioBytes', Format => 'int32u' },
339 7 => { Name => 'BytesPerMinute', Format => 'int32u' },
340 8 => { Name => 'Unknown', Format => 'int32u', Unknown => 1 },
341 9 => { Name => 'SubPacketH', Unknown => 1 },
342 10 => { Name => 'FrameSize', Unknown => 1 },
343 11 => { Name => 'SubPacketSize', Unknown => 1 },
344 12 => 'SampleRate',
345 13 => { Name => 'SampleRate2', Unknown => 1 },
346 14 => { Name => 'BitsPerSample', Format => 'int32u' },
347 15 => 'Channels',
348 16 => { Name => 'Genr', Format => 'int32u', Unknown => 1 },
349 17 => { Name => 'FourCC3', Format => 'undef[4]', Unknown => 1 },
350);
351
352#------------------------------------------------------------------------------
353# Process Real NameValueProperties
354# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table ref
355# Returns: 1 on success
356sub ProcessRealProperties($$$)
357{
358 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
359 my $dataPt = $$dirInfo{DataPt};
360 my $dirLen = $$dirInfo{DirLen};
361 my $pos = $$dirInfo{DirStart};
362 my $verbose = $exifTool->Options('Verbose');
363
364 $verbose and $exifTool->VerboseDir('RealProperties', undef, $dirLen);
365
366 while ($pos + 6 <= $dirLen) {
367
368 # get property size and version
369 my ($size, $vers) = unpack("x${pos}Nn", $$dataPt);
370 last if $size < 6;
371 unless ($vers == 0) {
372 $pos += $size;
373 next;
374 }
375 $pos += 6;
376
377 my $tagLen = unpack("x${pos}C", $$dataPt);
378 ++$pos;
379
380 last if $pos + $tagLen > $dirLen;
381 my $tag = substr($$dataPt, $pos, $tagLen);
382 $pos += $tagLen;
383
384 last if $pos + 6 > $dirLen;
385 my ($type, $valLen) = unpack("x${pos}Nn", $$dataPt);
386 $pos += 6;
387
388 last if $pos + $valLen > $dirLen;
389 my $format = $propertyType{$type} || 'undef';
390 my $count = int($valLen / Image::ExifTool::FormatSize($format));
391 my $val = ReadValue($dataPt, $pos, $format, $count, $dirLen-$pos);
392
393 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
394 unless ($tagInfo) {
395 my $tagName;
396 ($tagName = $tag) =~ s/\s+//g;
397 next unless $tagName =~ /^\w+$/; # ignore crazy names
398 $tagInfo = { Name => ucfirst($tagName) };
399 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
400 }
401 if ($verbose) {
402 $exifTool->VerboseInfo($tag, $tagInfo,
403 Table => $tagTablePtr,
404 Value => $val,
405 DataPt => $dataPt,
406 Size => $valLen,
407 Start => $pos,
408 Addr => $pos + $$dirInfo{DataPos},
409 Format => $format,
410 Count => $count,
411 );
412 }
413 $exifTool->FoundTag($tagInfo, $val);
414 $pos += $valLen;
415 }
416 return 1;
417}
418
419#------------------------------------------------------------------------------
420# Process Real metadata properties
421# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table ref
422# Returns: 1 on success
423sub ProcessRealMeta($$$)
424{
425 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
426 my $dataPt = $$dirInfo{DataPt};
427 my $dataPos = $$dirInfo{DataPos};
428 my $pos = $$dirInfo{DirStart};
429 my $dirEnd = $pos + $$dirInfo{DirLen};
430 my $verbose = $exifTool->Options('Verbose');
431 my $prefix = $$dirInfo{Prefix} || '';
432 $prefix and $prefix .= '/';
433
434 $verbose and $exifTool->VerboseDir('RealMetadata', undef, $$dirInfo{DirLen});
435
436 for (;;) {
437 last if $pos + 28 > $dirEnd;
438 # extract fixed-position metadata structure members
439 my ($size, $type, $flags, $valuePos, $subPropPos, $numSubProps, $nameLen)
440 = unpack("x${pos}N7", $$dataPt);
441 # make pointers relative to data start
442 $valuePos += $pos;
443 $subPropPos += $pos;
444 # validate what we have read so far
445 last if $pos + $size > $dirEnd;
446 last if $pos + 28 + $nameLen > $dirEnd;
447 last if $valuePos < $pos + 28 + $nameLen;
448 last if $valuePos + 4 > $dirEnd;
449 my $tag = substr($$dataPt, $pos + 28, $nameLen);
450 $tag =~ s/\0.*//s; # truncate at null
451 $tag = $prefix . $tag;
452 my $valueLen = unpack("x${valuePos}N", $$dataPt);
453 $valuePos += 4; # point at value itself
454 last if $valuePos + $valueLen > $dirEnd;
455
456 my $format = $metadataFormat{$type};
457 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
458 unless ($tagInfo) {
459 my $tagName = $tag;
460 $tagName =~ tr/A-Za-z0-9//dc;
461 $tagInfo = { Name => ucfirst($tagName) };
462 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
463 }
464 if ($verbose) {
465 $format = 'undef' unless defined $format;
466 $flags = Image::ExifTool::DecodeBits($flags, \%metadataFlag);
467 }
468 if ($valueLen and $format) {
469 # (a flag can be 1 or 4 bytes)
470 if ($format eq 'flag') {
471 $format = ($valueLen == 4) ? 'int32u' : 'int8u';
472 } elsif ($type == 7 and $tagInfo) {
473 # add PrintConv and ValueConv for "date" type
474 $$tagInfo{ValueConv} or $$tagInfo{ValueConv} = q{
475 $val =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ ?
476 sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",$1,$2,$3,$4,$5,$6) :
477 $val;
478 };
479 $$tagInfo{PrintConv} or $$tagInfo{PrintConv} = '$self->ConvertDateTime($val)';
480 }
481 my $count = int($valueLen / Image::ExifTool::FormatSize($format));
482 my $val = ReadValue($dataPt, $valuePos, $format, $count, $dirEnd-$valuePos);
483 $exifTool->HandleTag($tagTablePtr, $tag, $val,
484 DataPt => $dataPt,
485 DataPos => $dataPos,
486 Start => $valuePos,
487 Size => $valueLen,
488 Format => "type=$type, flags=$flags",
489 );
490 }
491 # extract sub-properties
492 if ($numSubProps) {
493 my $dirStart = $valuePos + $valueLen + $numSubProps * 8;
494 my %dirInfo = (
495 DataPt => $dataPt,
496 DataPos => $dataPos,
497 DirStart => $dirStart,
498 DirLen => $pos + $size - $dirStart,
499 Prefix => $tag,
500 );
501 $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
502 }
503 $pos += $size; # step to next Metadata structure
504 }
505 unless ($pos == $dirEnd) {
506 $exifTool->Warn('Format error in Real Metadata');
507 return 0;
508 }
509 return 1;
510}
511
512#------------------------------------------------------------------------------
513# Read information frame a Real file
514# Inputs: 0) ExifTool object reference, 1) Directory information reference
515# Returns: 1 on success, 0 if this wasn't a valid Real file
516sub ProcessReal($$)
517{
518 my ($exifTool, $dirInfo) = @_;
519 my $raf = $$dirInfo{RAF};
520 my ($buff, $tag, $vers, $extra, @mimeTypes, %dirCount);
521
522 $raf->Read($buff, 8) == 8 or return 0;
523 $buff =~ m{^(\.RMF|\.ra\xfd|pnm://|rtsp://|http://)} or return 0;
524
525 my ($type, $tagTablePtr);
526 if ($1 eq '.RMF') {
527 $tagTablePtr = GetTagTable('Image::ExifTool::Real::Media');
528 $type = 'RM';
529 } elsif ($1 eq ".ra\xfd") {
530 $tagTablePtr = GetTagTable('Image::ExifTool::Real::Audio');
531 $type = 'RA';
532 } else {
533 $tagTablePtr = GetTagTable('Image::ExifTool::Real::Metafile');
534 my $ext = $exifTool->{FILE_EXT};
535 $type = ($ext and $ext eq 'RPM') ? 'RPM' : 'RAM';
536 require Image::ExifTool::PostScript;
537 local $/ = Image::ExifTool::PostScript::GetInputRecordSeparator($raf) || "\n";
538 $raf->Seek(0,0);
539 while ($raf->ReadLine($buff)) {
540 last if length $buff > 256;
541 next unless $buff ;
542 chomp $buff;
543 if ($type) {
544 # must be a Real file type if protocol is http
545 return 0 if $buff =~ /^http/ and $buff !~ /\.(ra|rm|rv|rmvb|smil)$/i;
546 $exifTool->SetFileType($type);
547 undef $type;
548 }
549 # save URL or Text from RAM file
550 my $tag = $buff =~ m{^[a-z]{3,4}://} ? 'url' : 'txt';
551 $exifTool->HandleTag($tagTablePtr, $tag, $buff);
552 }
553 return 1;
554 }
555
556 $exifTool->SetFileType($type);
557 SetByteOrder('MM');
558 my $verbose = $exifTool->Options('Verbose');
559#
560# Process RealAudio file
561#
562 if ($type eq 'RA') {
563 ($vers, $extra) = unpack('x4nn', $buff);
564 $tag = ".ra$vers";
565 my $fpos = $raf->Tell();
566 unless ($raf->Read($buff, 512)) {
567 $exifTool->Warn('Error reading audio header');
568 return 1;
569 }
570 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
571 if ($verbose > 2) {
572 $exifTool->VerboseInfo($tag, $tagInfo, DataPt => \$buff, DataPos => $fpos);
573 }
574 if ($tagInfo) {
575 my $subTablePtr = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
576 my %dirInfo = (
577 DataPt => \$buff,
578 DataPos => $fpos,
579 DirLen => length $buff,
580 DirStart => 0,
581 );
582 $exifTool->ProcessDirectory(\%dirInfo, $subTablePtr);
583 } else {
584 $exifTool->Warn('Unsupported RealAudio version');
585 }
586 return 1;
587 }
588#
589# Process RealMedia file
590#
591 # skip the rest of the RM header
592 my $size = unpack('x4N', $buff);
593 unless ($raf->Seek($size - 8, 1)) {
594 $exifTool->Warn('Error seeking in file');
595 return 0;
596 }
597
598 # Process RealMedia chunks
599 for (;;) {
600 $raf->Read($buff, 10) == 10 or last;
601 ($tag, $size, $vers) = unpack('a4Nn', $buff);
602 last if $tag eq "\0\0\0\0";
603 if ($verbose) {
604 $exifTool->VPrint(0, "$tag chunk ($size bytes):\n");
605 } else {
606 last if $tag eq 'DATA'; # stop normal parsing at DATA tag
607 }
608 if ($size & 0x80000000) {
609 $exifTool->Warn('Bad chunk header');
610 last;
611 }
612 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
613 if ($tagInfo and $$tagInfo{SubDirectory}) {
614 my $fpos = $raf->Tell();
615 unless ($raf->Read($buff, $size-10) == $size-10) {
616 $exifTool->Warn("Error reading $tag chunk");
617 last;
618 }
619 if ($verbose > 2) {
620 $exifTool->VerboseInfo($tag, $tagInfo, DataPt => \$buff, DataPos => $fpos);
621 }
622 my $subTablePtr = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
623 my %dirInfo = (
624 DataPt => \$buff,
625 DataPos => $fpos,
626 DirLen => length $buff,
627 DirStart => 0,
628 );
629 if ($dirCount{$tag}) {
630 $exifTool->{SET_GROUP1} = '+' . ++$dirCount{$tag};
631 } else {
632 $dirCount{$tag} = 1;
633 }
634 $exifTool->ProcessDirectory(\%dirInfo, $subTablePtr);
635 delete $exifTool->{SET_GROUP1};
636 # keep track of stream MIME types
637 my $mime = $exifTool->{RealStreamMime};
638 if ($mime) {
639 delete $exifTool->{RealStreamMime};
640 $mime =~ s/\0.*//s;
641 push @mimeTypes, $mime unless $mime =~ /^logical-/;
642 }
643 } else {
644 unless ($raf->Seek($size-10, 1)) {
645 $exifTool->Warn('Error seeking in file');
646 last;
647 }
648 }
649 }
650 # override MIMEType with stream MIME type if we only have one stream
651 if (@mimeTypes == 1 and length $mimeTypes[0]) {
652 $exifTool->{VALUE}->{MIMEType} = $mimeTypes[0];
653 $exifTool->VPrint(0, " MIMEType = $mimeTypes[0]\n");
654 }
655#
656# Process footer containing Real metadata and ID3 information
657#
658 if ($raf->Seek(-140, 2) and $raf->Read($buff, 12) == 12 and $buff =~ /^RMJE/) {
659 my $metaSize = unpack('x8N', $buff);
660 if ($raf->Seek(-$metaSize-12, 1) and
661 $raf->Read($buff, $metaSize) == $metaSize and
662 $buff =~ /^RJMD/)
663 {
664 my %dirInfo = (
665 DataPt => \$buff,
666 DataPos => $raf->Tell() - $metaSize,
667 DirStart => 8,
668 DirLen => length($buff) - 8,
669 );
670 my $tagTablePtr = GetTagTable('Image::ExifTool::Real::Metadata');
671 $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
672 } else {
673 $exifTool->Warn('Bad metadata footer');
674 }
675 if ($raf->Seek(-128, 2) and $raf->Read($buff, 128) == 128 and $buff =~ /^TAG/) {
676 $exifTool->VPrint(0, "ID3v1:\n");
677 my %dirInfo = (
678 DataPt => \$buff,
679 DirStart => 0,
680 DirLen => length($buff),
681 );
682 my $tagTablePtr = GetTagTable('Image::ExifTool::ID3::v1');
683 $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
684 }
685 }
686 return 1;
687}
688
6891; # end
690
691__END__
692
693=head1 NAME
694
695Image::ExifTool::Real - Read Real audio/video meta information
696
697=head1 SYNOPSIS
698
699This module is used by Image::ExifTool
700
701=head1 DESCRIPTION
702
703This module contains the routines required by Image::ExifTool to read meta
704information in RealAudio (RA), RealMedia (RM, RV and RMVB) and RealMedia
705Metafile (RAM and RPM) files.
706
707=head1 NOTES
708
709There must be a bug in the software that wrote the Metadata used in the test
710file t/images/Real.rm because the TrackLyricsDataSize word is written
711little-endian, but the Real format is big-endian.
712
713=head1 AUTHOR
714
715Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
716
717This library is free software; you can redistribute it and/or modify it
718under the same terms as Perl itself.
719
720=head1 REFERENCES
721
722=over 4
723
724=item L<http://www.getid3.org/>
725
726=item L<https://common.helixcommunity.org/nonav/2003/HCS_SDK_r5/htmfiles/rmff.htm>
727
728=back
729
730=head1 SEE ALSO
731
732L<Image::ExifTool::TagNames/Real Tags>,
733L<Image::ExifTool(3pm)|Image::ExifTool>
734
735=cut
736
Note: See TracBrowser for help on using the repository browser.