1use strict; 2 3use File::Spec::Functions; 4use FindBin (); 5use Test::More tests => 120; 6 7use Audio::Scan; 8 9# TODO: DLNA profile tests: 10# AAC_ISO 11# AAC_MULT5_ISO 12# AAC_LTP_ISO 13# AAC_LTP_MULT5_ISO 14# AAC_LTP_MULT7_ISO 15# HEAAC_L2_ISO_128 16# HEAAC_L2_ISO_320 17# HEAAC_L2_ISO 18# HEAAC_MULT5_ISO 19# HEAAC_MULT7 20# HEAACv2_L2_128 21# HEAACv2_L2_320 22# HEAACv2_L3 23# HEAACv2_L4 24# HEAACv2_MULT5 25# HEAACv2_MULT7 26 27# Failing profiles: 28# O-HEAAC_ISO_128-stereo-16kHz-12.mp4 (channels 1, should be 2) 29 30# AAC file from iTunes 8.1.1 31{ 32 my $s = Audio::Scan->scan( _f('itunes811.m4a'), { md5_size => 4096 } ); 33 34 my $info = $s->{info}; 35 my $tags = $s->{tags}; 36 my $track = $info->{tracks}->[0]; 37 38 is( $info->{audio_offset}, 6169, 'Audio offset ok' ); 39 is( $info->{audio_size}, 320, 'Audio size ok' ); 40 is( $info->{audio_md5}, '9bf0388a5bfd81c857fdce52dac9ce7f', 'Audio MD5 ok' ); 41 is( $info->{compatible_brands}->[0], 'M4A ', 'Compatible brand 1 ok' ); 42 is( $info->{compatible_brands}->[1], 'mp42', 'Compatible brand 2 ok' ); 43 is( $info->{compatible_brands}->[2], 'isom', 'Compatible brand 3 ok' ); 44 is( $info->{leading_mdat}, undef, 'Leading MDAT flag is blank' ); 45 is( $info->{file_size}, 6489, 'File size ok' ); 46 is( $info->{major_brand}, 'M4A ', 'Major brand ok' ); 47 is( $info->{minor_version}, 0, 'Minor version ok' ); 48 is( $info->{song_length_ms}, 69, 'Song length ok' ); 49 is( $info->{samplerate}, 44100, 'Sample rate ok' ); 50 is( $info->{avg_bitrate}, 96000, 'Avg bitrate ok' ); 51 is( $info->{dlna_profile}, 'AAC_ISO_192', 'DLNA profile AAC_ISO_192 ok' ); 52 53 is( $track->{audio_object_type}, 2, 'Audio object type ok' ); 54 is( $track->{audio_type}, 64, 'Audio type ok' ); 55 is( $track->{bits_per_sample}, 16, 'Bits per sample ok' ); 56 is( $track->{channels}, 2, 'Channels ok' ); 57 is( $track->{duration}, 69, 'Duration ok' ); 58 is( $track->{encoding}, 'mp4a', 'Encoding ok' ); 59 is( $track->{handler_name}, '', 'Handler name ok' ); 60 is( $track->{handler_type}, 'soun', 'Handler type ok' ); 61 is( $track->{id}, 1, 'Track ID ok' ); 62 is( $track->{max_bitrate}, 0, 'Max bitrate ok' ); 63 64 is( $tags->{AART}, 'Album Artist', 'AART ok' ); 65 is( $tags->{ALB}, 'Album', 'ALB ok' ); 66 is( $tags->{ART}, 'Artist', 'ART ok' ); 67 is( $tags->{CMT}, 'Comments', 'CMT ok' ); 68 is( length($tags->{COVR}), 2103, 'COVR ok' ); 69 is( $tags->{CPIL}, 1, 'CPIL ok' ); 70 is( $tags->{DAY}, 2009, 'DAY ok' ); 71 is( $tags->{DESC}, 'Video Description', 'DESC ok' ); 72 is( $tags->{DISK}, '1/2', 'DISK ok' ); 73 is( $tags->{GNRE}, 'Jazz', 'GNRE ok' ); 74 is( $tags->{GRP}, 'Grouping', 'GRP ok' ); 75 is( $tags->{ITUNNORM}, ' 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000', 'ITUNNORM ok' ); 76 is( $tags->{ITUNSMPB}, ' 00000000 00000840 000001E4 00000000000001DC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000', 'ITUNSMPB ok' ); 77 is( $tags->{LYR}, 'Lyrics', 'LYR ok' ); 78 is( $tags->{NAM}, 'Name', 'NAM ok' ); 79 is( $tags->{PGAP}, 1, 'PGAP ok' ); 80 is( $tags->{SOAA}, 'Sort Album Artist', 'SOAA ok' ); 81 is( $tags->{SOAL}, 'Sort Album', 'SOAL ok' ); 82 is( $tags->{SOAR}, 'Sort Artist', 'SOAR ok' ); 83 is( $tags->{SOCO}, 'Sort Composer', 'SOCO ok' ); 84 is( $tags->{SONM}, 'Sort Name', 'SONM ok' ); 85 is( $tags->{SOSN}, 'Sort Show', 'SOSN ok' ); 86 is( $tags->{TMPO}, 120, 'TMPO ok' ); 87 is( $tags->{TOO}, 'iTunes 8.1.1, QuickTime 7.6', 'TOO ok' ); 88 is( $tags->{TRKN}, '1/10', 'TRKN ok' ); 89 is( $tags->{TVEN}, 'Episode ID', 'TVEN ok' ); 90 is( $tags->{TVES}, 12, 'TVES ok' ); 91 is( $tags->{TVSH}, 'Show', 'TVSH ok' ); 92 is( $tags->{TVSN}, 12, 'TVSN ok' ); 93 is( $tags->{WRT}, 'Composer', 'WRT ok' ); 94} 95 96# ALAC file from iTunes 8.1.1 97{ 98 my $s = Audio::Scan->scan( _f('alac.m4a') ); 99 100 my $info = $s->{info}; 101 my $tags = $s->{tags}; 102 my $track = $info->{tracks}->[0]; 103 104 is( $info->{audio_offset}, 3850, 'ALAC audio offset ok' ); 105 is( $info->{song_length_ms}, 10, 'ALAC song length ok' ); 106 is( $info->{samplerate}, 44100, 'ALAC samplerate ok' ); 107 is( $info->{avg_bitrate}, 981600, 'ALAC avg bitrate ok' ); 108 ok( !exists $info->{dlna_profile}, 'ALAC no DLNA profile ok' ); 109 110 is( $track->{duration}, 10, 'ALAC duration ok' ); 111 is( $track->{encoding}, 'alac', 'ALAC encoding ok' ); 112 is( $track->{bits_per_sample}, 16, 'ALAC bits_per_sample ok' ); 113 is( $track->{channels}, 2, 'ALAC channels ok' ); 114 115 is( $tags->{CPIL}, 0, 'ALAC CPIL ok' ); 116 is( $tags->{DISK}, '1/2', 'ALAC DISK ok' ); 117 is( $tags->{TOO}, 'iTunes 8.1.1', 'ALAC TOO ok' ); 118} 119 120# File with mdat before the rest of the boxes 121{ 122 my $s = Audio::Scan->scan( _f('leading-mdat.m4a') ); 123 124 my $info = $s->{info}; 125 my $tags = $s->{tags}; 126 127 is( $info->{audio_offset}, 20, 'Leading MDAT offset ok' ); 128 is( $info->{leading_mdat}, 1, 'Leading MDAT flag ok' ); 129 is( $info->{song_length_ms}, 69845, 'Leading MDAT length ok' ); 130 is( $info->{samplerate}, 44100, 'Leading MDAT samplerate ok' ); 131 is( $info->{avg_bitrate}, 128000, 'Leading MDAT bitrate ok' ); 132 ok( !exists $info->{dlna_profile}, 'Leading MDAT no DLNA profile ok' ); 133 134 is( $tags->{DAY}, '-001', 'Leading MDAT DAY ok' ); 135 is( $tags->{TOO}, 'avc2.0.11.1110', 'Leading MDAT TOO ok' ); 136} 137 138# File with array keys, bug 13486 139{ 140 my $s = Audio::Scan->scan( _f('array-keys.m4a') ); 141 142 my $tags = $s->{tags}; 143 144 is( $tags->{AART}, 'Sonic Youth', 'Array key single key ok' ); 145 is( ref $tags->{PRODUCER}, 'ARRAY', 'Array key array element ok' ); 146 is( $tags->{PRODUCER}->[0], 'Ron Saint Germain', 'Array key element 0 ok' ); 147 is( $tags->{PRODUCER}->[1], 'Nick Sansano', 'Array key element 1 ok' ); 148 is( $tags->{PRODUCER}->[2], 'Sonic Youth', 'Array key element 2 ok' ); 149 is( $tags->{PRODUCER}->[3], 'J Mascis', 'Array key element 3 ok' ); 150 is( $tags->{PRODUCER}->[4], 'Don Fleming', 'Array key element 4 ok' ); 151} 152 153# 88.2 kHz sample rate, bug 8563 154{ 155 my $s = Audio::Scan->scan( _f('882-sample-rate.m4a') ); 156 157 my $info = $s->{info}; 158 159 is( $info->{samplerate}, 88200, '88.2 sample rate ok' ); 160 is( $info->{song_length_ms}, 179006, '88.2 song length ok' ); 161 ok( !exists $info->{dlna_profile}, '88.2 no DLNA profile ok' ); 162} 163 164# Multiple covers, bug 14476 165{ 166 my $s = Audio::Scan->scan( _f('multiple-covers.m4a') ); 167 168 my $tags = $s->{tags}; 169 170 is( length( $tags->{COVR} ), 2103, 'Multiple cover art reads first cover ok' ); 171} 172 173# Test ignoring artwork 174{ 175 local $ENV{AUDIO_SCAN_NO_ARTWORK} = 1; 176 177 my $s = Audio::Scan->scan( _f('multiple-covers.m4a') ); 178 179 my $tags = $s->{tags}; 180 181 is( $tags->{COVR}, 2103, 'COVR with AUDIO_SCAN_NO_ARTWORK ok' ); 182 is( $tags->{COVR_offset}, 1926, 'COVR with AUDIO_SCAN_NO_ARTWORK offset ok' ); 183} 184 185# File with array keys that are integers, bug 14462 186{ 187 my $s = Audio::Scan->scan( _f('array-keys-int.m4a') ); 188 189 my $tags = $s->{tags}; 190 191 is( $tags->{AART}, 'Stevie Wonder', 'Array key int single key ok' ); 192 is( ref $tags->{FREE}, 'ARRAY', 'Array key int array element ok' ); 193 is( $tags->{FREE}->[0], 1969970, 'Array key int element 0 ok' ); 194 is( $tags->{FREE}->[1], 'xxxxxx@xxxxxx.com', 'Array key int element 1 ok' ); 195 is( $tags->{FREE}->[2], 46726, 'Array key int element 2 ok' ); 196 is( $tags->{FREE}->[3], 1969972, 'Array key int element 3 ok' ); 197 is( $tags->{FREE}->[4], 15, 'Array key int element 4 ok' ); 198 is( $tags->{FREE}->[5], 0, 'Array key int element 5 ok' ); 199} 200 201# File with short trkn field 202{ 203 my $s = Audio::Scan->scan( _f('short-trkn.m4a') ); 204 205 my $tags = $s->{tags}; 206 207 is( $tags->{TRKN}, 10, 'Short trkn ok' ); 208} 209 210# HD-AAC file 211# Contains 48khz LC track and 96khz SLS track 212{ 213 my $s = Audio::Scan->scan( _f('hd-aac.m4a') ); 214 215 my $info = $s->{info}; 216 217 is( $info->{samplerate}, 96000, 'HD-AAC samplerate ok' ); 218 is( $info->{song_length_ms}, 409130, 'HD-AAC song length ok' ); 219 is( $info->{avg_bitrate}, 4, 'HD-AAC avg bitrate ok' ); 220 ok( !exists $info->{dlna_profile}, 'HD-AAC no DLNA profile ok' ); 221 222 my $track1 = $info->{tracks}->[0]; 223 my $track2 = $info->{tracks}->[1]; 224 225 is( $track1->{audio_object_type}, 2, 'HD-AAC LC track ok' ); 226 is( $track1->{samplerate}, 48000, 'HD-AAC LC track samplerate ok' ); 227 is( $track1->{bits_per_sample}, 16, 'HD-AAC LC track bps ok' ); 228 229 is( $track2->{audio_object_type}, 37, 'HD-AAC SLS track ok' ); 230 is( $track2->{samplerate}, 96000, 'HD-AAC SLS track samplerate ok' ); 231 is( $track2->{bits_per_sample}, 24, 'HD-AAC SLS track bps ok' ); 232} 233 234# Bug 15262, secondary hint track with 0 duration, caused bad song_length_ms value 235{ 236 my $s = Audio::Scan->scan( _f('hint-track.m4a') ); 237 238 my $info = $s->{info}; 239 240 is( $info->{song_length_ms}, 263433, 'MP4 hint track song_length_ms ok' ); 241 is( $info->{dlna_profile}, 'AAC_ISO_320', 'MP4 hint track DLNA profile AAC_ISO_320 ok' ); 242 is( $info->{tracks}->[0]->{duration}, 263433, 'MP4 hint track track 1 duration ok' ); 243 is( $info->{tracks}->[1]->{duration}, 0, 'MP4 hint track track 2 duration ok' ); 244} 245 246# HE-AAC file, tests that we got the right samplerate from esds 247{ 248 my $s = Audio::Scan->scan( _f('heaac.mp4') ); 249 250 my $info = $s->{info}; 251 252 is( $info->{samplerate}, 16000, 'HE-AAC main samplerate 16000 ok' ); 253 is( $info->{tracks}->[0]->{samplerate}, 16000, 'HE-AAC track 1 samplerate 16000 ok' ); 254 255 # XXX this should be 2 256 #is( $info->{tracks}->[0]->{channels}, 2, 'HE-AAC track 1 channels 2 ok' ); 257} 258 259# Find frame 260{ 261 my $offset = Audio::Scan->find_frame( _f('itunes811.m4a'), 30 ); 262 263 is( $offset, 6183, 'Find frame ok' ); 264} 265 266# Find frame with info 267{ 268 my $info = Audio::Scan->find_frame_return_info( _f('itunes811.m4a'), 30 ); 269 270 is( $info->{seek_offset}, 6183, 'Find frame return info offset ok' ); 271 is( length( $info->{seek_header} ), 6173, 'Find frame return info header rewrite ok' ); 272} 273 274# Find frame in ALAC file with unusual stts values 275{ 276 my $info = Audio::Scan->find_frame_return_info( _f('alac-multiple-stts.m4a'), 30000 ); 277 278 is( $info->{seek_offset}, 2123193, 'Find frame in ALAC multiple stts ok' ); 279 is( length( $info->{seek_header} ), 34274, 'Find frame in ALAC multiple stts header ok' ); 280} 281 282# Find frame in HD-AAC file (2 tracks) (not yet supported) 283{ 284 my $info = Audio::Scan->find_frame_return_info( _f('hd-aac.m4a'), 10 ); 285 286 is( $info->{seek_offset}, -1, 'Find frame in HD-AAC ok' ); 287} 288 289# Find frame with info from filehandle 290{ 291 open my $fh, '<', _f('itunes811.m4a'); 292 293 my $info = Audio::Scan->find_frame_fh_return_info( mp4 => $fh, 30 ); 294 295 is( $info->{seek_offset}, 6183, 'Find frame return info via filehandle ok' ); 296 is( length( $info->{seek_header} ), 6173, 'Find frame return info via filehandle rewrite ok' ); 297 298 close $fh; 299} 300 301sub _f { 302 return catfile( $FindBin::Bin, 'mp4', shift ); 303} 304