42
48
$hchild{'meta'} = 12;
43
49
$hchild{'ilst'} = 8;
44
50
$hchild{'----'} = 8;
46
51
$hchild{'day'} = 8;
47
52
$hchild{'cmt'} = 8;
48
53
$hchild{'disk'} = 8;
50
54
$hchild{'wrt'} = 8;
51
58
$hchild{'�nam'} = 8;
70
##Call this to parse a file
57
open(QTFILE, $qtfile) or return undef;
59
my $fsize = -s "$qtfile";
64
if($fsize < 16 || rseek(4,4) ne "ftyp") {
69
my($clevel, $len) = get_atom($level, $pos, \%lx);
71
warn "** Unexpected data found at $pos!\n";
72
warn "** You found a bug! Please send a bugreport\n";
73
warn "** to pab\@blinkenlights.ch\n";
74
warn "** GIVING UP PARSING\n";
75
open(QTFILE, $qtfile) or return undef;
77
my $fsize = -s "$qtfile" or return undef; #Hey.. VFS borken?
83
if($fsize < 16 || rseek(4,4) ne "ftyp") { #Can't be a QTfile
89
#Ok, header looks okay.. seek each atom and buildup $lx{metadat}
91
my($clevel, $len) = get_atom($level, $pos, \%lx);
93
warn "QTfile.pm: ** Unexpected data found at $pos!\n";
94
warn "QTfile.pm: ** You found a bug! Please send a bugreport\n";
95
warn "QTfile.pm: ** to pab\@blinkenlights.ch\n";
96
warn "QTfile.pm: ** GIVING UP PARSING **\n";
105
########### Now we build the chain #######################################
107
#Search the Sound-Stream
108
my $sound_index = get_sound_index($lx{metadat}{'::moov::trak::mdia::hdlr'});
110
if($sound_index < 0) {
111
warn "QTfile.pm: No 'sound' data found in file!\n";
115
#print "::moov::trak::mdia::hdlr -> $sound_index\n";
117
my @METADEF = ("album", "\xA9alb",
118
"comment", "\xA9cmt",
121
"composer","\xA9wrt",
126
"comment", "\xA9cmt");
128
###All STRING fields..
129
for(my $i = 0;$i<int(@METADEF);$i+=2) {
130
my $cKey = "::moov::udta::meta::ilst::".$METADEF[$i+1]."::data";
131
if($lx{metadat}{$cKey}[$sound_index]) {
132
$reth{$METADEF[$i]} = $lx{metadat}{$cKey}[$sound_index];
136
###INT and such fields are here:
138
if( my $cDat = $lx{metadat}{'::moov::udta::meta::ilst::tmpo::data'}[$sound_index] ) {
139
$reth{bpm} = GNUpod::FooBar::shx2_x86_int($cDat);
142
if( my $cDat = $lx{metadat}{'::moov::udta::meta::ilst::trkn::data'}[$sound_index]) {
143
$reth{tracknum} = GNUpod::FooBar::shx2_x86_int(substr($cDat,2,2));
144
$reth{tracks} = GNUpod::FooBar::shx2_x86_int(substr($cDat,4,2));
147
if( my $cDat = $lx{metadat}{'::moov::udta::meta::ilst::disk::data'}[$sound_index]) {
148
$reth{cdnum} = GNUpod::FooBar::shx2_x86_int(substr($cDat,2,2));
149
$reth{cds} = GNUpod::FooBar::shx2_x86_int(substr($cDat,4,2));
153
if( my $cDat = $lx{metadat}{'::moov::mvhd'}[$sound_index] ) {
154
#Calculate the time...
155
$reth{time} = int( get_string_oct(8,4,$cDat)/
156
get_string_oct(4,4,$cDat)*1000 );
160
if($lx{metadat}{'::moov::udta::meta::ilst::----::mean'}[$sound_index] eq "apple.iTunes" &&
161
$lx{metadat}{'::moov::udta::meta::ilst::----::name'}[$sound_index] eq "NORM") {
162
$reth{iTunNORM} = $lx{metadat}{'::moov::udta::meta::ilst::----::data'}[$sound_index];
165
if( my $cDat = $lx{metadat}{'::moov::trak::mdia::minf::stbl::stsd'}[$sound_index] ) {
166
$reth{_CODEC} = substr($cDat,4,4);
167
$reth{srate} = get_string_oct(32,2,$cDat);
168
$reth{channels} = get_string_oct(24,2,$cDat);
169
$reth{bit_depth} = get_string_oct(26,2,$cDat);
80
171
$reth{filesize} = $fsize;
173
#Fixme: This is ugly.. bitrate is somewhere found in esds / stsd
174
$reth{bitrate} = int( ($reth{filesize}*8/1024)/(1+$reth{time})*1000 );
177
print "* ************ FINISHED PARSER ***********************\n";
178
foreach(keys(%{$lx{metadat}})) {
181
use GNUpod::iTunesDB;
185
foreach(@{$lx{metadat}{$_}}) {
187
print "==============> $x <==================\n";
188
GNUpod::iTunesDB::__hd($_);
84
199
############################################################
85
200
# Get a single ATOM
87
my($level, $pos, $lt) = @_;
89
my $len = getoct($pos,4);
91
return(undef, undef) if $len < 16;
92
my $typ = rseek($pos+4,4);
202
my($level, $pos, $lt) = @_;
203
my $len = getoct($pos,4); #Length of field
205
return(undef, undef) if $len < 8;
94
$level = $lt->{ltrack}->{$pos} if $lt->{ltrack}->{$pos};
95
$lt->{topic}->{$level} = $typ;
98
#print int($level)."] \@$pos L $len -> $typ \n";
99
#print " parent : ".$lt->{"topic_".($level-1)}."\n";
102
my $parent =$lt->{topic}->{$level-1};
103
my $dat = rseek($pos+16,$len-16);
104
if($parent eq "�alb") {
107
elsif($parent eq "�ART") {
108
$reth{artist} = $dat;
110
elsif($parent eq "�nam") {
113
elsif($parent eq "�too") {
117
warn "Skipping $typ -> $parent\n";
120
elsif($typ eq "mvhd") {
121
$reth{time} = int(getoct($pos+24,4)/getoct($pos+20,4)*1000);
124
if(defined($hchild{$typ})) { #This type has a child
126
$lt->{ltrack}->{$pos+$len} = $level unless $lt->{ltrack}->{$pos+$len};
130
$len = $hchild{$typ};
208
my $typ = rseek($pos+4,4);
209
#..and keep track of it..
210
$level = $lt->{ltrack}->{$pos} if $lt->{ltrack}->{$pos};
212
#Build a chain for this level.. looks like '::foo::bar::bla'
213
$LEVELA[$level] = $typ;
216
$cChain .= "::".$LEVELA[$_];
219
if(defined($hchild{$typ})) { #This type has a child
221
$lt->{ltrack}->{$pos+$len} = $level unless $lt->{ltrack}->{$pos+$len};
225
$len = $hchild{$typ};
227
elsif($len >= 16 && $cChain !~ /(::mdat|::free)$/) { #No child -> final element -> data!
228
push(@{$lt->{metadat}->{$cChain}},rseek($pos+16,$len-16));
234
############################################
235
# Search the 'soun' item
236
sub get_sound_index {
239
my $sound_index = -1;
241
if( substr($_,0,4) eq SOUND_ITEM ) {
138
250
###################################################
141
my($offset, $len) = @_;
142
GNUpod::FooBar::shx2_x86_int(rseek($offset,$len));
253
my($offset, $len) = @_;
254
GNUpod::FooBar::shx2_x86_int(rseek($offset,$len));
258
###################################################
259
# Get INT vaules from string
261
my($offset, $len, $string) = @_;
263
if($offset+$len > length($string)) {
264
warn "Bug: invalid substr() call! Returning 0\n";
268
GNUpod::FooBar::shx2_x86_int(substr($string,$offset,$len));
145
271
####################################################
148
my($offset, $len) = @_;
149
return undef if $len < 0;
151
seek(QTFILE, $offset, 0);
152
read(QTFILE, $buff, $len);
274
my($offset, $len) = @_;
275
return undef if $len < 0;
277
seek(QTFILE, $offset, 0);
278
read(QTFILE, $buff, $len);