| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Audio::M4P::Atom; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | require 5.006; | 
| 4 | 6 |  |  | 6 |  | 23 | use strict; | 
|  | 6 |  |  |  |  | 8 |  | 
|  | 6 |  |  |  |  | 174 |  | 
| 5 | 6 |  |  | 6 |  | 20 | use warnings; | 
|  | 6 |  |  |  |  | 7 |  | 
|  | 6 |  |  |  |  | 121 |  | 
| 6 | 6 |  |  | 6 |  | 21 | use Carp; | 
|  | 6 |  |  |  |  | 7 |  | 
|  | 6 |  |  |  |  | 363 |  | 
| 7 |  |  |  |  |  |  | our $VERSION = '0.54'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 6 |  |  | 6 |  | 25 | use Scalar::Util 'weaken'; | 
|  | 6 |  |  |  |  | 10 |  | 
|  | 6 |  |  |  |  | 224 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 6 |  |  | 6 |  | 3535 | use Tree::Simple 'use_weak_refs'; | 
|  | 6 |  |  |  |  | 14390 |  | 
|  | 6 |  |  |  |  | 57 |  | 
| 12 | 6 |  |  | 6 |  | 2974 | use Tree::Simple::Visitor; | 
|  | 6 |  |  |  |  | 4349 |  | 
|  | 6 |  |  |  |  | 187 |  | 
| 13 | 6 |  |  | 6 |  | 3205 | use Tree::Simple::View::HTML; | 
|  | 6 |  |  |  |  | 43168 |  | 
|  | 6 |  |  |  |  | 12941 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | # see http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt | 
| 16 |  |  |  |  |  |  | my %container_atom_types = ( | 
| 17 |  |  |  |  |  |  | aaid   => 1, | 
| 18 |  |  |  |  |  |  | akid   => 1, | 
| 19 |  |  |  |  |  |  | '©alb' => 1, | 
| 20 |  |  |  |  |  |  | apid   => 1, | 
| 21 |  |  |  |  |  |  | aART   => 1, | 
| 22 |  |  |  |  |  |  | '©ART' => 1, | 
| 23 |  |  |  |  |  |  | atid   => 1, | 
| 24 |  |  |  |  |  |  | clip   => 1, | 
| 25 |  |  |  |  |  |  | '©cmt' => 1, | 
| 26 |  |  |  |  |  |  | '©com' => 1, | 
| 27 |  |  |  |  |  |  | covr   => 1, | 
| 28 |  |  |  |  |  |  | cpil   => 1, | 
| 29 |  |  |  |  |  |  | cprt   => 1, | 
| 30 |  |  |  |  |  |  | '©day' => 1, | 
| 31 |  |  |  |  |  |  | dinf   => 1, | 
| 32 |  |  |  |  |  |  | disk   => 1, | 
| 33 |  |  |  |  |  |  | drms   => 1, | 
| 34 |  |  |  |  |  |  | edts   => 1, | 
| 35 |  |  |  |  |  |  | geid   => 1, | 
| 36 |  |  |  |  |  |  | gnre   => 1, | 
| 37 |  |  |  |  |  |  | '©grp' => 1, | 
| 38 |  |  |  |  |  |  | hinf   => 1, | 
| 39 |  |  |  |  |  |  | hnti   => 1, | 
| 40 |  |  |  |  |  |  | ilst   => 1, | 
| 41 |  |  |  |  |  |  | matt   => 1, | 
| 42 |  |  |  |  |  |  | mdia   => 1, | 
| 43 |  |  |  |  |  |  | meta   => 1, | 
| 44 |  |  |  |  |  |  | minf   => 1, | 
| 45 |  |  |  |  |  |  | moof   => 1, | 
| 46 |  |  |  |  |  |  | moov   => 1, | 
| 47 |  |  |  |  |  |  | mp4a   => 1, | 
| 48 |  |  |  |  |  |  | '©nam' => 1, | 
| 49 |  |  |  |  |  |  | pinf   => 1, | 
| 50 |  |  |  |  |  |  | plid   => 1, | 
| 51 |  |  |  |  |  |  | rtng   => 1, | 
| 52 |  |  |  |  |  |  | schi   => 1, | 
| 53 |  |  |  |  |  |  | sinf   => 1, | 
| 54 |  |  |  |  |  |  | stbl   => 1, | 
| 55 |  |  |  |  |  |  | stik   => 1, | 
| 56 |  |  |  |  |  |  | stsd   => 1, | 
| 57 |  |  |  |  |  |  | tmpo   => 1, | 
| 58 |  |  |  |  |  |  | '©too' => 1, | 
| 59 |  |  |  |  |  |  | traf   => 1, | 
| 60 |  |  |  |  |  |  | trak   => 1, | 
| 61 |  |  |  |  |  |  | trkn   => 1, | 
| 62 |  |  |  |  |  |  | udta   => 1, | 
| 63 |  |  |  |  |  |  | '©wrt' => 1, | 
| 64 |  |  |  |  |  |  | ); | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | my %noncontainer_atom_types = ( | 
| 67 |  |  |  |  |  |  | chtb   => 1, | 
| 68 |  |  |  |  |  |  | ctts   => 1, | 
| 69 |  |  |  |  |  |  | data   => 1, | 
| 70 |  |  |  |  |  |  | esds   => 1, | 
| 71 |  |  |  |  |  |  | free   => 1, | 
| 72 |  |  |  |  |  |  | frma   => 1, | 
| 73 |  |  |  |  |  |  | ftyp   => 1, | 
| 74 |  |  |  |  |  |  | '©gen' => 1, | 
| 75 |  |  |  |  |  |  | hmhd   => 1, | 
| 76 |  |  |  |  |  |  | iviv   => 1, | 
| 77 |  |  |  |  |  |  | 'key ' => 1, | 
| 78 |  |  |  |  |  |  | mdat   => 1, | 
| 79 |  |  |  |  |  |  | mdhd   => 1, | 
| 80 |  |  |  |  |  |  | mp4s   => 1, | 
| 81 |  |  |  |  |  |  | mpv4   => 1, | 
| 82 |  |  |  |  |  |  | mvhd   => 1, | 
| 83 |  |  |  |  |  |  | name   => 1, | 
| 84 |  |  |  |  |  |  | priv   => 1, | 
| 85 |  |  |  |  |  |  | rtp    => 1, | 
| 86 |  |  |  |  |  |  | sign   => 1, | 
| 87 |  |  |  |  |  |  | stco   => 1, | 
| 88 |  |  |  |  |  |  | stsc   => 1, | 
| 89 |  |  |  |  |  |  | stp    => 1, | 
| 90 |  |  |  |  |  |  | stts   => 1, | 
| 91 |  |  |  |  |  |  | tfhd   => 1, | 
| 92 |  |  |  |  |  |  | tkhd   => 1, | 
| 93 |  |  |  |  |  |  | tref   => 1, | 
| 94 |  |  |  |  |  |  | trun   => 1, | 
| 95 |  |  |  |  |  |  | user   => 1, | 
| 96 |  |  |  |  |  |  | vmhd   => 1, | 
| 97 |  |  |  |  |  |  | wide   => 1, | 
| 98 |  |  |  |  |  |  | ); | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | sub int64toN { | 
| 101 | 0 |  |  | 0 | 1 | 0 | my ($int64) = @_; | 
| 102 | 0 |  |  |  |  | 0 | my $high32bits = pack( 'N', int( $int64 / ( 2**32 ) + 0.0001 ) ); | 
| 103 | 0 |  |  |  |  | 0 | my $low32bits = pack( 'N', $int64 % ( 2**32 ) ); | 
| 104 | 0 |  |  |  |  | 0 | return $high32bits . $low32bits; | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | sub int64fromN { | 
| 108 | 1 |  |  | 1 | 1 | 5 | my ($buf) = @_; | 
| 109 | 1 |  |  |  |  | 3 | my ( $high32bits, $low32bits ) = unpack( "NN", $buf ); | 
| 110 | 1 |  |  |  |  | 6 | return ( $high32bits * ( 2**32 ) ) + $low32bits; | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | # begin class methods | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | sub new { | 
| 116 | 1203 |  |  | 1203 | 1 | 3012 | my ( $class, %args ) = @_; | 
| 117 | 1203 |  |  |  |  | 1267 | my $self = \%args; | 
| 118 | 1203 |  |  |  |  | 2192 | bless( $self, $class ); | 
| 119 | 1203 |  |  |  |  | 2489 | $self->{node} = Tree::Simple->new($self); | 
| 120 | 1203 | 100 |  |  |  | 27945 | if( ref $self->{parent} ) { | 
| 121 | 1188 |  |  |  |  | 2668 | $self->{parent}->addChild( $self->{node} ); | 
| 122 | 1188 |  |  |  |  | 82493 | weaken $self->{node}; | 
| 123 | 1188 |  |  |  |  | 1873 | weaken $self->{parent}; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  | else { | 
| 126 | 15 |  |  |  |  | 35 | $self->{parent} = 0; | 
| 127 |  |  |  |  |  |  | } | 
| 128 | 1203 | 50 |  |  |  | 2581 | if( ref $self->{rbuf} ) { | 
| 129 | 1203 |  |  |  |  | 1719 | weaken $self->{rbuf}; | 
| 130 | 1203 | 100 |  |  |  | 3119 | $self->read_buffer( $self->{read_buffer_position} ) | 
| 131 |  |  |  |  |  |  | if exists $self->{read_buffer_position}; | 
| 132 |  |  |  |  |  |  | } | 
| 133 | 1203 |  |  |  |  | 2333 | return $self; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | sub DESTROY { | 
| 137 | 1218 |  |  | 1218 |  | 4968 | my($self) = @_; | 
| 138 | 1218 |  |  |  |  | 1336 | delete $self->{parent}; | 
| 139 | 1218 |  |  |  |  | 1180 | delete $self->{rbuf}; | 
| 140 | 1218 | 100 |  |  |  | 5159 | return unless ref $self->{node}; | 
| 141 | 15 |  |  |  |  | 57 | my @kids = $self->{node}->getAllChildren(); | 
| 142 | 15 |  |  |  |  | 157 | foreach my $child (@kids) { | 
| 143 | 196 | 50 |  |  |  | 328 | next unless ref $child; | 
| 144 | 196 |  |  |  |  | 306 | my $val = $child->getNodeValue(); | 
| 145 | 196 | 50 | 33 |  |  | 1459 | $val->DESTROY | 
|  |  |  | 33 |  |  |  |  | 
| 146 |  |  |  |  |  |  | if ref $val | 
| 147 |  |  |  |  |  |  | and ref $val->{parent} | 
| 148 |  |  |  |  |  |  | and $val->{parent} eq $self; | 
| 149 |  |  |  |  |  |  | } | 
| 150 | 15 | 50 |  |  |  | 96 | $self->{node}->DESTROY if ref $self->{node}; | 
| 151 | 15 |  |  |  |  | 82 | delete $self->{node}; | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 0 |  |  | 0 | 1 | 0 | sub parent { return shift->{parent} } | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 7449 |  |  | 7449 | 1 | 35201 | sub node { return shift->{node} } | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 0 |  |  | 0 | 1 | 0 | sub rbuf { return shift->{rbuf} } | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | sub read_buffer { | 
| 161 | 1128 |  |  | 1128 | 1 | 1191 | my ( $self, $starting ) = @_; | 
| 162 | 1128 |  |  |  |  | 1337 | $self->{start}  = $starting; | 
| 163 | 1128 |  |  |  |  | 1249 | $self->{offset} = 8; | 
| 164 | 1128 |  |  |  |  | 5177 | ( $self->{size}, $self->{type} ) = unpack 'Na4', | 
| 165 | 1128 |  |  |  |  | 979 | substr( ${ $self->{rbuf} }, $starting, 8 ); | 
| 166 | 1128 | 100 |  |  |  | 2222 | if ( $self->{size} == 1 ) { | 
| 167 | 1 |  |  |  |  | 8 | $self->{size} = | 
| 168 | 1 |  |  |  |  | 2 | int64fromN( substr( ${ $self->{rbuf} }, $starting + 8, 8 ) ); | 
| 169 | 1 |  |  |  |  | 4 | $self->{offset} = 16; | 
| 170 |  |  |  |  |  |  | } | 
| 171 | 1128 |  |  |  |  | 1352 | return $self->{size}; | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | sub type { | 
| 175 | 535237 |  |  | 535237 | 1 | 434231 | my ( $self, $newtype ) = @_; | 
| 176 | 535237 | 50 |  |  |  | 682777 | if ( defined $newtype ) { | 
| 177 | 0 |  |  |  |  | 0 | $self->{type} = substr( $newtype, 0, 4 ); | 
| 178 | 0 |  |  |  |  | 0 | substr( ${ $self->{rbuf} }, $self->{start} + 4, 4, $self->{type} ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 179 |  |  |  |  |  |  | } | 
| 180 | 535237 |  |  |  |  | 2055386 | return $self->{type}; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | sub start { | 
| 184 | 907 |  |  | 907 | 1 | 894 | my ( $self, $newstart ) = @_; | 
| 185 | 907 | 50 |  |  |  | 1394 | $self->{start} = $newstart if defined $newstart; | 
| 186 | 907 |  |  |  |  | 2253 | return $self->{start}; | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | sub size { | 
| 190 | 3675 |  |  | 3675 | 1 | 3109 | my ( $self, $newsize ) = @_; | 
| 191 | 3675 | 100 |  |  |  | 5308 | if ( defined $newsize ) { | 
| 192 | 380 | 50 | 33 |  |  | 755 | return $self->BigResize($newsize) | 
| 193 |  |  |  |  |  |  | if $newsize >= 2**32 | 
| 194 |  |  |  |  |  |  | and $self->{size} >= 2**32; | 
| 195 | 380 | 50 | 33 |  |  | 687 | return $self->toBigSize($newsize) | 
| 196 |  |  |  |  |  |  | if $newsize >= 2**32 | 
| 197 |  |  |  |  |  |  | and $self->{size} < 2**32; | 
| 198 | 380 | 50 | 33 |  |  | 743 | return $self->toRegularSize($newsize) | 
| 199 |  |  |  |  |  |  | if $self->{size} >= 2**32 | 
| 200 |  |  |  |  |  |  | and $newsize < 2**32; | 
| 201 | 380 |  |  |  |  | 319 | $self->{size} = $newsize; | 
| 202 | 380 |  |  |  |  | 309 | substr( ${ $self->{rbuf} }, $self->{start}, 4, pack( 'N', $newsize ) ); | 
|  | 380 |  |  |  |  | 793 |  | 
| 203 |  |  |  |  |  |  | } | 
| 204 | 3675 |  |  |  |  | 9098 | return $self->{size}; | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub BigResize { | 
| 208 | 0 |  |  | 0 | 1 | 0 | my ( $self, $newsize ) = @_; | 
| 209 | 0 | 0 |  |  |  | 0 | croak "atom size big, but offset not 16" if $self->{offset} != 16; | 
| 210 | 0 |  |  |  |  | 0 | $self->{size} = $newsize; | 
| 211 | 0 |  |  |  |  | 0 | substr( ${ $self->{rbuf} }, $self->{start} + 8, 8, int64toN($newsize) ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 212 | 0 |  |  |  |  | 0 | return $self->{size}; | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | sub toBigSize { | 
| 216 | 0 |  |  | 0 | 1 | 0 | my ( $self, $newsize ) = @_; | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | # need to add 2 bytes to the data section and reset containers and starts | 
| 219 | 0 | 0 | 0 |  |  | 0 | return unless $self->{offset} == 8 and $newsize >= 2**32; | 
| 220 | 0 |  |  |  |  | 0 | $self->{offset} = 16; | 
| 221 | 0 |  |  |  |  | 0 | $self->{size}   = $newsize; | 
| 222 | 0 |  |  |  |  | 0 | substr( ${ $self->{rbuf} }, $self->{start}, 4, pack( 'N', 1 ) ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 223 | 0 |  |  |  |  | 0 | substr( ${ $self->{rbuf} }, $self->{start} + 8, 0, int64toN($newsize) ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 224 | 0 |  |  |  |  | 0 | $self->redoStarts(8); | 
| 225 | 0 | 0 |  |  |  | 0 | $self->resizeContainers(8) unless $self->{type} eq 'moov'; | 
| 226 | 0 |  |  |  |  | 0 | return $self->{size}; | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | sub toRegularSize { | 
| 230 | 0 |  |  | 0 | 1 | 0 | my ( $self, $newsize ) = @_; | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | # need to remove 2 bytes from data section and reset containers and starts | 
| 233 | 0 | 0 | 0 |  |  | 0 | return unless $self->{offset} == 16 and $newsize < 2**32; | 
| 234 | 0 |  |  |  |  | 0 | $self->{offset} = 8; | 
| 235 | 0 |  |  |  |  | 0 | $self->{size}   = $newsize; | 
| 236 | 0 |  |  |  |  | 0 | substr( ${ $self->{rbuf} }, $self->{start}, 4, pack( 'N', $newsize ) ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 237 | 0 |  |  |  |  | 0 | substr( ${ $self->{rbuf} }, $self->{start} + 8, 8, '' ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 238 | 0 |  |  |  |  | 0 | $self->redoStarts(-8); | 
| 239 | 0 | 0 |  |  |  | 0 | $self->resizeContainers(-8) unless $self->{type} eq 'moov'; | 
| 240 | 0 |  |  |  |  | 0 | return $self->{size}; | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | sub offset { | 
| 244 | 710 |  |  | 710 | 1 | 580 | my ( $self, $o ) = @_; | 
| 245 | 710 | 0 | 0 |  |  | 993 | $self->{offset} = $o if defined($o) and ( $o == 8 or $o == 16 ); | 
|  |  |  | 33 |  |  |  |  | 
| 246 | 710 |  |  |  |  | 1642 | return $self->{offset}; | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | sub data { | 
| 250 | 1178 |  |  | 1178 | 1 | 1502 | my ( $self, $newdata ) = @_; | 
| 251 | 1178 | 100 |  |  |  | 2042 | if ( defined $newdata ) { | 
| 252 | 1 |  |  |  |  | 2 | my $newsize = ( length $newdata ) + 8; | 
| 253 | 1 |  |  |  |  | 2 | my $diff    = $newsize - $self->{size}; | 
| 254 | 1 |  |  |  |  | 4 | $self->resizeContainers($diff); | 
| 255 | 1 |  |  |  |  | 166 | substr( | 
| 256 | 1 |  |  |  |  | 1 | ${ $self->{rbuf} }, | 
| 257 |  |  |  |  |  |  | $self->{start} + $self->{offset}, | 
| 258 |  |  |  |  |  |  | $self->{size} - $self->{offset}, $newdata | 
| 259 |  |  |  |  |  |  | ); | 
| 260 | 1 |  |  |  |  | 3 | $self->size($newsize); | 
| 261 | 1 |  |  |  |  | 3 | $self->redoStarts( $diff, $self->{start} ); | 
| 262 |  |  |  |  |  |  | } | 
| 263 | 1178 |  |  |  |  | 6852 | return substr( | 
| 264 | 1178 |  |  |  |  | 1108 | ${ $self->{rbuf} }, | 
| 265 |  |  |  |  |  |  | $self->{start} + $self->{offset}, | 
| 266 |  |  |  |  |  |  | $self->{size} - $self->{offset} | 
| 267 |  |  |  |  |  |  | ); | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | sub root { | 
| 271 | 3748 |  |  | 3748 | 1 | 4104 | my ($self) = @_; | 
| 272 | 3748 | 100 |  |  |  | 5833 | return $self->node if $self->node->isRoot(); | 
| 273 | 469 | 50 |  |  |  | 2340 | return unless ref $self->{parent}; | 
| 274 | 469 |  |  |  |  | 720 | return $self->{parent}->getNodeValue()->root(); | 
| 275 |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | sub getAllRelatives { | 
| 278 | 3279 |  |  | 3279 | 1 | 3021 | my ($self) = @_; | 
| 279 | 3279 |  |  |  |  | 8325 | my $visitor = Tree::Simple::Visitor->new(); | 
| 280 | 3279 |  |  |  |  | 48807 | $self->root()->accept($visitor); | 
| 281 | 3279 |  |  |  |  | 2691993 | my @a = $visitor->getResults; | 
| 282 | 3279 |  |  |  |  | 63858 | return \@a; | 
| 283 |  |  |  |  |  |  | } | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | sub AtomTree { | 
| 286 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 287 |  |  |  |  |  |  | my $view = Tree::Simple::View::HTML->new( | 
| 288 |  |  |  |  |  |  | $self->{node}, | 
| 289 |  |  |  |  |  |  | ( | 
| 290 |  |  |  |  |  |  | list_css       => "list-style: circle;", | 
| 291 |  |  |  |  |  |  | list_item_css  => "font-family: courier;", | 
| 292 |  |  |  |  |  |  | node_formatter => sub { | 
| 293 | 0 |  |  | 0 |  | 0 | my ($tree) = @_; | 
| 294 | 0 |  |  |  |  | 0 | return " " . $tree->getNodeValue->print() . " "; | 
| 295 |  |  |  |  |  |  | }, | 
| 296 |  |  |  |  |  |  | ) | 
| 297 | 0 |  |  |  |  | 0 | ); | 
| 298 | 0 |  |  |  |  | 0 | return $view->expandAll(); | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | sub resizeContainers { | 
| 302 | 305 |  |  | 305 | 1 | 303 | my ( $self, $diff ) = @_; | 
| 303 | 305 | 100 | 66 |  |  | 1182 | if ( $self->{parent} and ref $self->{parent} ) { | 
| 304 | 304 |  |  |  |  | 592 | my $container = $self->{parent}->getNodeValue(); | 
| 305 | 304 | 50 |  |  |  | 975 | if ( $container->{type} ne 'file' ) { | 
| 306 | 304 |  |  |  |  | 381 | $container->size( $container->size + $diff ); | 
| 307 | 304 | 100 |  |  |  | 822 | $container->resizeContainers($diff) | 
| 308 |  |  |  |  |  |  | unless $container->{type} eq 'moov'; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  | } | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | sub redoStarts { | 
| 314 | 91 |  |  | 91 | 1 | 115 | my ( $self, $diff, $pivot ) = @_; | 
| 315 | 91 |  |  |  |  | 91 | foreach my $atom ( @{ $self->getAllRelatives() } ) { | 
|  | 91 |  |  |  |  | 138 |  | 
| 316 | 6628 | 100 | 100 |  |  | 14018 | $atom->{start} += $diff | 
| 317 |  |  |  |  |  |  | if $atom->{start} >= $pivot | 
| 318 |  |  |  |  |  |  | and $atom != $self; | 
| 319 |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  | } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | sub selfDelete { | 
| 323 | 15 |  |  | 15 | 1 | 25 | my ($self) = @_; | 
| 324 | 15 |  |  |  |  | 32 | $self->resizeContainers( -$self->size ); | 
| 325 | 15 |  |  |  |  | 16 | substr( ${ $self->{rbuf} }, $self->start, $self->size, '' ); | 
|  | 15 |  |  |  |  | 40 |  | 
| 326 | 15 |  |  |  |  | 32 | $self->redoStarts( -$self->size, $self->{start} ); | 
| 327 | 15 | 50 |  |  |  | 61 | return unless ref $self->{parent}; | 
| 328 | 15 |  |  |  |  | 61 | $self->{parent}->removeChild( $self->{node} ); | 
| 329 | 15 |  |  |  |  | 3559 | delete $self->{parent}; | 
| 330 | 15 |  |  |  |  | 61 | return 1; | 
| 331 |  |  |  |  |  |  | } | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | sub insertNew { | 
| 334 | 75 |  |  | 75 | 1 | 126 | my ( $self, $type, $data, $before ) = @_; | 
| 335 | 75 |  |  |  |  | 121 | my $node = $self->{node}; | 
| 336 | 75 |  |  |  |  | 269 | my $atom = new Audio::M4P::Atom( parent => $node, rbuf => $self->{rbuf} ); | 
| 337 | 75 |  |  |  |  | 92 | my $after_atom; | 
| 338 | 75 | 50 | 33 |  |  | 218 | if ( $before and ( $after_atom = $self->Contained($before) ) ) { | 
| 339 | 0 |  |  |  |  | 0 | $atom->{start} = $after_atom->{start}; | 
| 340 |  |  |  |  |  |  | } | 
| 341 | 75 |  |  |  |  | 180 | else { $atom->{start} = $self->{start} + $self->{size}; } | 
| 342 | 75 |  |  |  |  | 107 | $atom->{offset} = 8; | 
| 343 | 75 |  |  |  |  | 160 | $atom->{size}   = 8 + length $data; | 
| 344 | 75 |  |  |  |  | 113 | $atom->{type}   = $type; | 
| 345 | 75 |  |  |  |  | 214 | $atom->redoStarts( $atom->{size}, $atom->{start} ); | 
| 346 | 75 | 100 |  |  |  | 687 | my $buf = pack( 'Na4', $atom->{size}, $type ? $type : 'junk' ) . $data; | 
| 347 | 75 |  |  |  |  | 90 | substr( ${ $self->{rbuf} }, $atom->{start}, 0, $buf ); | 
|  | 75 |  |  |  |  | 16091 |  | 
| 348 | 75 |  |  |  |  | 317 | $self->size( $self->{size} + $atom->{size} ); | 
| 349 | 75 |  |  |  |  | 183 | $self->resizeContainers( $atom->{size} ); | 
| 350 | 75 |  |  |  |  | 198 | return $atom; | 
| 351 |  |  |  |  |  |  | } | 
| 352 |  |  |  |  |  |  |  | 
| 353 |  |  |  |  |  |  | sub insertNewMetaData { | 
| 354 | 31 |  |  | 31 | 1 | 66 | my ( $self, $type, $data, $before ) = @_; | 
| 355 | 31 |  |  |  |  | 105 | my $wrapper = $self->insertNew( $type, '', $before ); | 
| 356 | 31 | 100 |  |  |  | 351 | my $flag = | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | ( $type =~ /gnre|disk|trkn/i ) ? 0 | 
| 358 |  |  |  |  |  |  | : ( $type =~ /rtng/i ) ? 21 | 
| 359 |  |  |  |  |  |  | : ( $type =~ /covr/i ) ? 13 | 
| 360 |  |  |  |  |  |  | : 1; | 
| 361 | 31 |  |  |  |  | 227 | $wrapper->insertNew( 'data', pack( 'NN', $flag, 0 ) . $data ); | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | sub addMoreArtwork { | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | # add more artwork to a covr atom contained in self | 
| 367 | 1 |  |  | 1 | 1 | 2 | my ( $self, $data, $type ) = @_; | 
| 368 | 1 | 50 |  |  |  | 6 | $type = 13 unless $type; | 
| 369 | 1 | 50 |  |  |  | 3 | my $covr = $self->Contained('covr') or croak "No covr atom in this atom"; | 
| 370 | 1 |  |  |  |  | 30 | $covr->insertNew( 'data', pack( 'NN', $type, 0 ) . $data ); | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | sub Container { | 
| 374 | 0 |  |  | 0 | 1 | 0 | my ( $self, $container_type ) = @_; | 
| 375 | 0 | 0 |  |  |  | 0 | return unless ref $self->{parent}; | 
| 376 | 0 |  |  |  |  | 0 | my $parent_atom = $self->{parent}->getNodeValue(); | 
| 377 | 0 | 0 |  |  |  | 0 | return $parent_atom if $parent_atom->{type} =~ /$container_type/i; | 
| 378 | 0 |  |  |  |  | 0 | return $parent_atom->Container($container_type); | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | sub Contained { | 
| 382 | 979 |  |  | 979 | 1 | 1585 | my ( $self, $type ) = @_; | 
| 383 | 979 |  |  |  |  | 1404 | my $node = $self->{node}; | 
| 384 | 979 |  |  |  |  | 2251 | my @kids = $node->getAllChildren(); | 
| 385 | 979 |  |  |  |  | 4211 | my @results; | 
| 386 | 979 |  |  |  |  | 1605 | foreach my $child (@kids) { | 
| 387 | 1507 |  |  |  |  | 2513 | my $val = $child->getNodeValue(); | 
| 388 | 1507 | 100 | 100 |  |  | 11922 | push @results, $val if $val->{type} and $val->{type} =~ /$type/i; | 
| 389 |  |  |  |  |  |  | } | 
| 390 | 979 | 100 |  |  |  | 2064 | return @results if wantarray; | 
| 391 | 957 | 100 |  |  |  | 1956 | return unless scalar @results > 0; | 
| 392 | 917 |  |  |  |  | 2840 | return $results[0]; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | sub isContainer { | 
| 396 | 1060 |  |  | 1060 | 1 | 995 | my ($self) = @_; | 
| 397 | 1060 |  |  |  |  | 2284 | return $container_atom_types{ $self->{type} }; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | sub ParentAtom { | 
| 401 | 4 |  |  | 4 | 1 | 8 | my ($self) = @_; | 
| 402 | 4 | 50 |  |  |  | 16 | return unless ref $self->{parent}; | 
| 403 | 4 |  |  |  |  | 16 | return $self->{parent}->getNodeValue(); | 
| 404 |  |  |  |  |  |  | } | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | sub DirectChildren { | 
| 407 | 5 |  |  | 5 | 1 | 12 | my ( $self, $type ) = @_; | 
| 408 | 5 |  |  |  |  | 21 | my @kids = $self->Contained($type); | 
| 409 | 5 |  |  |  |  | 9 | my @results; | 
| 410 | 5 |  |  |  |  | 14 | foreach my $a (@kids) { | 
| 411 | 4 | 50 |  |  |  | 12 | push @results, $a if $a->ParentAtom() eq $self; | 
| 412 |  |  |  |  |  |  | } | 
| 413 | 5 | 50 |  |  |  | 62 | return @results if wantarray; | 
| 414 | 5 | 100 |  |  |  | 84 | return unless scalar @results > 0; | 
| 415 | 4 |  |  |  |  | 15 | return $results[0]; | 
| 416 |  |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | sub print { | 
| 419 | 0 |  |  | 0 | 1 |  | my ($self) = @_; | 
| 420 | 0 |  |  |  |  |  | return "Atom " | 
| 421 |  |  |  |  |  |  | . $self->type . " at " | 
| 422 |  |  |  |  |  |  | . $self->start | 
| 423 |  |  |  |  |  |  | . " size " | 
| 424 |  |  |  |  |  |  | . $self->size | 
| 425 |  |  |  |  |  |  | . " ends at " | 
| 426 |  |  |  |  |  |  | . ( $self->start + $self->size ); | 
| 427 |  |  |  |  |  |  | } | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | =head1 NAME | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | Audio::M4P::Atom -- M4P/MP4/M4A QuickTime audio music format atoms | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | M4P is a QuickTime protected audio file format. It is composed of a linear | 
| 436 |  |  |  |  |  |  | stream of bytes which are segmented into units called atoms. Some atoms | 
| 437 |  |  |  |  |  |  | may contain other atoms. This module has methods for handling atoms which | 
| 438 |  |  |  |  |  |  | are delegated by the QuickTime and other modules in the Audio::M4P hierarchy. | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | =head2 Class Internal Functions | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | =over 4 | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | =item B | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | =item B | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | =item B | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | =item B | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | =item B | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | =item B | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | =item B | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | =item B | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | =item B | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | =item B | 
| 463 |  |  |  |  |  |  |  | 
| 464 |  |  |  |  |  |  | =item B | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | =item B | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | =item B | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | =item B | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | =item B | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | =item B | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | =item B | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | =item B | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | =item B | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | =item B | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | =item B | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | =item B | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | =item B | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | =item B | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | =item B | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | =item B | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | =item B | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | =item B | 
| 499 |  |  |  |  |  |  |  | 
| 500 |  |  |  |  |  |  | =item B | 
| 501 |  |  |  |  |  |  |  | 
| 502 |  |  |  |  |  |  | =item B | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | =back | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | =head1 AUTHOR | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | William Herrera B. | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | =head1 SUPPORT | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | Questions, feature requests and bug reports should go to | 
| 513 |  |  |  |  |  |  | . | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  |  | 
| 516 |  |  |  |  |  |  | =cut | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | 1; |