1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
|
use strict;
use File::Spec::Functions;
use FindBin ();
use Test::More tests => 142;
use Audio::Scan;
# TODO: LSL_MULT5 profile test (lossless, channels > 2)
my $HAS_ENCODE;
eval {
require Encode;
$HAS_ENCODE = 1;
};
# Basic tests of all fields
{
my $s = Audio::Scan->scan( _f('wma92-32k.wma'), { md5_size => 4096 } );
my $info = $s->{info};
my $tags = $s->{tags};
is( $info->{audio_offset}, 5161, 'Audio offset ok' );
is( $info->{audio_size}, 7590, 'Audio size ok' );
is( $info->{audio_md5}, '472091bc205bf78e0d321b8ef11f2f1c', 'Audio MD5 ok' );
is( $info->{broadcast}, 0, 'Broadcast not set ok' );
is( ref $info->{codec_list}, 'ARRAY', 'Codec list ok' );
is( $info->{codec_list}->[0]->{description}, ' 32 kbps, 22 kHz, stereo 2-pass CBR', 'Codec description ok' );
is( $info->{codec_list}->[0]->{name}, 'Windows Media Audio 9.2', 'Codec name ok' );
is( $info->{codec_list}->[0]->{type}, 'Audio', 'Codec type ok' );
is( $info->{creation_date}, 1239379533, 'Creation date ok' );
is( $info->{data_packets}, 5, 'Data packets ok' );
is( $info->{file_id}, '4c2d71e7-f116-4e47-ae0f-e27a4632f9e3', 'File ID ok' );
is( $info->{file_size}, 12751, 'File size ok' );
is( ref $info->{language_list}, 'ARRAY', 'Language list ok' );
is( $info->{language_list}->[0], 'en-us', 'Language list item ok' );
is( $info->{max_bitrate}, 32645, 'Max bitrate ok' );
is( $info->{max_packet_size}, 1518, 'Max packet size ok' );
is( $info->{min_packet_size}, 1518, 'Min packet size ok' );
is( $info->{play_duration_ms}, 2602, 'Play duration ok' );
is( $info->{preroll}, 1579, 'Preroll ok' );
is( $info->{seekable}, 1, 'Seekable ok' );
is( $info->{send_duration_ms}, 1857, 'Send duration ok' );
is( $info->{song_length_ms}, 1023, 'Song length ok' );
is( $info->{dlna_profile}, 'WMABASE', 'DLNA profile WMABASE ok' );
is( ref $info->{streams}, 'ARRAY', 'Streams ok' );
my $stream = $info->{streams}->[0];
is( $stream->{DeviceConformanceTemplate}, 'L2', 'DeviceConformanceTemplate ok' );
is( $stream->{IsVBR}, 0, 'IsVBR ok' );
is( $stream->{alt_bitrate}, 32024, 'Alt bitrate ok' );
is( $stream->{alt_buffer_fullness}, 0, 'Alt buffer fullness ok' );
is( $stream->{alt_buffer_size}, 1579, 'Alt buffer size ok' );
is( $stream->{avg_bitrate}, 32645, 'Average bitrate ok' );
is( $stream->{avg_bytes_per_sec}, 4003, 'Average bytes/sec ok' );
is( $stream->{bitrate}, 32024, 'Bitrate ok' );
is( $stream->{bits_per_sample}, 16, 'Bits per sample ok' );
is( $stream->{block_alignment}, 1487, 'Block alignment ok' );
is( $stream->{buffer_fullness}, 0, 'Buffer fullness ok' );
is( $stream->{buffer_size}, 1579, 'Buffer size ok' );
is( $stream->{channels}, 2, 'Channels ok' );
is( $stream->{codec_id}, 0x161, 'Codec ID ok' );
is( $stream->{encode_options}, 23, 'Encode options ok' );
is( $stream->{encrypted}, 0, 'Encrypted ok' );
is( $stream->{error_correction_type}, 'ASF_Audio_Spread', 'Error correction type ok' );
is( $stream->{flag_seekable}, 1, 'Seekable ok' );
is( $stream->{language_index}, 0, 'Language index ok' );
is( $stream->{max_object_size}, 1487, 'Max object size ok' );
is( $stream->{samplerate}, 22050, 'Sample rate ok' );
is( $stream->{samples_per_block}, 17408, 'Samples per block ok' );
is( $stream->{stream_number}, 1, 'Stream number ok' );
is( $stream->{stream_type}, 'ASF_Audio_Media', 'Stream type ok' );
is( $stream->{super_block_align}, 0, 'Super block align ok' );
is( $stream->{time_offset}, 0, 'Time offset ok' );
is( $tags->{Author}, 'Author String', 'Author tag ok' );
is( $tags->{Copyright}, 'Copyright String', 'Copyright tag ok' );
is( $tags->{Description}, 'Description String', 'Description tag ok' );
is( $tags->{IsVBR}, 0, 'IsVBR tags ok' );
is( $tags->{Rating}, 'Rating String', 'Rating tag ok' );
is( $tags->{Title}, 'Voice Test', 'Title tag ok' );
is( $tags->{WMFSDKNeeded}, '0.0.0.0000', 'WMFSDKNeeded tag ok' );
is( $tags->{WMFSDKVersion}, '11.0.5721.5251', 'WMFSDKVersion tag ok' );
}
# Multiple bitrate file
{
my $s = Audio::Scan->scan( _f('wma92-mbr.wma') );
my $info = $s->{info};
my $tags = $s->{tags};
is( ref $info->{mutex_list}, 'ARRAY', 'Mutex list ok' );
is( $info->{mutex_list}->[0]->{ASF_Mutex_Bitrate}->[0], 1, 'Mutex stream 1 ok' );
is( $info->{mutex_list}->[0]->{ASF_Mutex_Bitrate}->[1], 2, 'Mutex stream 2 ok' );
is( $info->{streams}->[0]->{stream_number}, 1, 'Stream 1 ok' );
is( $info->{streams}->[1]->{stream_number}, 2, 'Stream 2 ok' );
is( $tags->{'User Key'}, 'User Value', 'User key ok' );
}
# VBR file
{
my $s = Audio::Scan->scan( _f('wma92-vbr.wma') );
my $info = $s->{info};
my $tags = $s->{tags};
is( $info->{streams}->[0]->{IsVBR}, 1, 'IsVBR ok' );
is( $info->{streams}->[0]->{avg_bitrate}, 53719, 'Average bitrate ok' );
SKIP:
{
skip 'Encode is not available', 3 unless $HAS_ENCODE;
my $pate = Encode::decode_utf8("pâté");
my $ber = Encode::decode_utf8('ЪЭЯ');
my $yc = Encode::decode_utf8('γζ');
is( $tags->{'Latin1 Key'}, $pate, 'Latin1 tag ok' );
is( $tags->{'Russian Key'}, $ber, 'Unicode tag ok' );
is( $tags->{$ber}, $yc, 'Unicode key/value ok' );
}
is( ref $tags->{'WM/Picture'}, 'HASH', 'WM/Picture ok' );
is( $tags->{'WM/Picture'}->{image_type}, 3, 'WM/Picture type ok' );
is( $tags->{'WM/Picture'}->{mime_type}, 'image/jpeg', 'WM/Picture MIME type ok' );
is( length($tags->{'WM/Picture'}->{image}), 2103, 'WM/Picture length ok' );
}
# Test ignoring artwork
{
local $ENV{AUDIO_SCAN_NO_ARTWORK} = 1;
my $s = Audio::Scan->scan( _f('wma92-vbr.wma') );
my $tags = $s->{tags};
is( $tags->{'WM/Picture'}->{image}, 2103, 'WM/Picture with AUDIO_SCAN_NO_ARTWORK ok' );
is( $tags->{'WM/Picture'}->{offset}, 555, 'WM/Picture with AUDIO_SCAN_NO_ARTWORK offset ok' );
}
# Bug 17355, WM/Picture tag within Header Extension/Metadata Library
{
local $ENV{AUDIO_SCAN_NO_ARTWORK} = 1;
my $s = Audio::Scan->scan( _f('bug17355-picture-offset.wma') );
my $tags = $s->{tags};
is( $tags->{'WM/Picture'}->{image}, 88902, 'WM/Picture in Header Extension/Metadata Library length ok' );
is( $tags->{'WM/Picture'}->{offset}, 1121, 'WM/Picture in Header Extension/Metadata Library length ok' );
}
# WMA Pro 10 file
{
my $s = Audio::Scan->scan( _f('wma92-48k-pro.wma') );
my $info = $s->{info};
is( $info->{codec_list}->[0]->{name}, 'Windows Media Audio 10 Professional', 'WMA 10 Pro ok' );
is( $info->{streams}->[0]->{codec_id}, 0x0162, 'WMA 10 Pro codec ID ok' );
is( $info->{dlna_profile}, 'WMAPRO', 'WMA 10 Pro DLNA profile WMAPRO ok' );
}
# WMA Lossless file
{
my $s = Audio::Scan->scan( _f('wma92-lossless.wma') );
my $info = $s->{info};
is( $info->{codec_list}->[0]->{name}, 'Windows Media Audio 9.2 Lossless', 'WMA Lossless ok' );
is( $info->{streams}->[0]->{codec_id}, 0x0163, 'WMA Lossless codec ID ok' );
is( $info->{streams}->[0]->{avg_bitrate}, 607494, 'WMA Lossless average bitrate ok' );
is( $info->{lossless}, 1, 'WMA Lossless flag ok' );
is( $info->{dlna_profile}, 'WMALSL', 'WMA Lossless DLNA profile WMALSL ok' );
}
# WMA Voice file with duplicate tags
{
my $s = Audio::Scan->scan( _f('wma92-voice.wma') );
my $info = $s->{info};
my $tags = $s->{tags};
is( $info->{streams}->[0]->{codec_id}, 0x000a, 'WMA Voice codec ID ok' );
ok( !exists $info->{dlna_profile}, 'WMA Voice no DLNA profile ok' );
# Note these are out of order because they are written to different objects by MP3tag
is( ref $tags->{'WM/Composer'}, 'ARRAY', 'Multiple composer tags ok' );
is( $tags->{'WM/Composer'}->[0], 'Composer 2', 'Composer 2 ok' );
is( $tags->{'WM/Composer'}->[1], 'Composer 3', 'Composer 3 ok' );
is( $tags->{'WM/Composer'}->[2], 'Composer 1', 'Composer 1 ok' );
}
# WMV file, no audio
{
my $s = Audio::Scan->scan( _f('wmv92.wmv') );
my $info = $s->{info};
my $stream = $info->{streams}->[0];
is( $info->{codec_list}->[0]->{name}, 'Windows Media Video 9 Screen', 'WMV ok' );
is( $stream->{stream_type}, 'ASF_Video_Media', 'WMV stream type ok' );
is( $stream->{bpp}, 24, 'WMV bpp ok' );
is( $stream->{compression_id}, 'MSS2', 'WMV compression ID ok' );
is( $stream->{height}, 57, 'WMV height ok' );
is( $stream->{width}, 501, 'WMV width ok' );
}
# Video/Audio file
{
my $s = Audio::Scan->scan( _f('wmv92-with-audio.wmv') );
my $info = $s->{info};
is( $info->{codec_list}->[0]->{name}, 'Windows Media Audio 9.2', 'WMV audio track ok' );
is( $info->{codec_list}->[1]->{name}, 'Windows Media Video 9', 'WMV video track ok' );
is( $info->{dlna_profile}, 'WMAFULL', 'WMV with audio DLNA profile WMAFULL ok' );
is( $info->{streams}->[0]->{stream_type}, 'ASF_Audio_Media', 'WMV audio stream ok' );
is( $info->{streams}->[1]->{stream_type}, 'ASF_Video_Media', 'WMV video stream ok' );
}
# Live audio stream header
{
my $s = Audio::Scan->scan( _f('wma-live.wma') );
my $info = $s->{info};
is( $info->{broadcast}, 1, 'Live stream ok' );
is( $info->{seekable}, 0, 'Live stream not seekable ok' );
is( $info->{streams}->[1]->{stream_type}, 'ASF_Command_Media', 'Live stream metadata stream ok' );
}
# File with DRM, script commands, and 2 images
{
my $s = Audio::Scan->scan( _f('drm.wma') );
my $info = $s->{info};
my $tags = $s->{tags};
is( $info->{streams}->[0]->{encrypted}, 1, 'DRM encrypted flag set ok' );
is( $info->{drm_key}, 'pMYQ3zAwEE+/lAEL5hP0Ug==', 'DRM key ok' );
is( $info->{drm_license_url}, 'http://switchboard.real.com/rhapsody/?cd=wmupgrade', 'DRM license URL ok' );
is( $info->{drm_protection_type}, 'DRM', 'DRM protection type ok' );
like( $info->{drm_data}, qr{<RhapsodyAlbumArtistId>16826</RhapsodyAlbumArtistId>}, 'Extended encryption data ok' );
is( ref $info->{script_types}, 'ARRAY', 'Script types ok' );
is( $info->{script_types}->[0], 'URL', 'Script type URL ok' );
is( $info->{script_types}->[1], 'FILENAME', 'Script type FILENAME ok' );
is( ref $info->{script_commands}, 'ARRAY', 'Script commands ok' );
is( $info->{script_commands}->[0]->{command}, 'http://www.microsoft.com/isapi/redir.dll?Prd=WMT4&Sbp=DRM&Plcid=0x0409&Pver=4.0&WMTFeature=DRM', 'Script command 1 ok' );
is( $info->{script_commands}->[0]->{time}, 1579, 'Script time 1 ok' );
is( $info->{script_commands}->[0]->{type}, 0, 'Script type 1 ok' );
is( $info->{script_commands}->[1]->{command}, undef, 'Script command 2 ok' );
is( $info->{script_commands}->[1]->{time}, 1579, 'Script time 2 ok' );
is( $info->{script_commands}->[1]->{type}, 1, 'Script type 2 ok' );
is( ref $tags->{'WM/Picture'}, 'ARRAY', 'WM/Picture array ok' );
is( $tags->{'WM/Picture'}->[0]->{description}, 'Large Cover Art', 'WM/Picture 1 description ok' );
is( length( $tags->{'WM/Picture'}->[0]->{image} ), 4644, 'WM/Picture 1 image ok' );
is( $tags->{'WM/Picture'}->[1]->{description}, 'Cover Art', 'WM/Picture 2 description ok' );
is( length( $tags->{'WM/Picture'}->[1]->{image} ), 2110, 'WM/Picture 2 image ok ');
}
# File with JFIF image type and MP3 codec
{
my $s = Audio::Scan->scan( _f('jfif.wma') );
my $info = $s->{info};
is( $info->{streams}->[0]->{stream_type}, 'ASF_JFIF_Media', 'JFIF stream ok' );
is( $info->{streams}->[1]->{codec_id}, 85, 'MP3 codec ID ok' );
is( $info->{streams}->[0]->{width}, 320, 'JFIF width ok' );
is( $info->{streams}->[0]->{height}, 240, 'JFIF height ok' );
ok( !exists $info->{dlna_profile}, 'MP3 codec no DLNA profile ok' );
}
# Bug 14788, multiple tags where one is an integer, caused a crash
{
my $s = Audio::Scan->scan( _f('wma92-multiple-tags.wma') );
my $tags = $s->{tags};
is( $tags->{'WM/TrackNumber'}->[0], 1, 'Multiple tag Track Number ok' );
is( $tags->{'WM/TrackNumber'}->[1], '01', 'Multiple tag Track Number ok' );
}
# Scan via a filehandle
{
open my $fh, '<', _f('wma92-32k.wma');
my $s = Audio::Scan->scan_fh( asf => $fh );
my $info = $s->{info};
my $tags = $s->{tags};
is( $info->{audio_offset}, 5161, 'Audio offset ok via filehandle' );
is( $tags->{Author}, 'Author String', 'Author tag ok via filehandle' );
close $fh;
}
# Find frame MBR
{
my $offset = Audio::Scan->find_frame( _f('wma92-mbr.wma'), 650 );
is( $offset, 6261, 'Find frame MBR ok' );
# Offset bigger than song_length_ms
$offset = Audio::Scan->find_frame( _f('wma92-mbr.wma'), 1300 );
is( $offset, 7061, 'Find frame MBR with retry ok' );
}
{
open my $fh, '<', _f('wma92-mbr.wma');
my $offset = Audio::Scan->find_frame_fh( asf => $fh, 1025 );
close $fh;
is( $offset, 7061, 'Find frame MBR via filehandle ok' );
}
# Find frame VBR
{
my $offset = Audio::Scan->find_frame( _f('wma92-vbr.wma'), 2200 );
is( $offset, 9825, 'Find frame VBR time 2200 ok' );
$offset = Audio::Scan->find_frame( _f('wma92-vbr.wma'), 800 );
is( $offset, 7564, 'Find frame VBR time 800 ok' );
$offset = Audio::Scan->find_frame( _f('wma92-vbr.wma'), 0 );
is( $offset, 5303, 'Find frame VBR time 0 ok' );
}
{
open my $fh, '<', _f('wma92-vbr.wma');
my $offset = Audio::Scan->find_frame_fh( asf => $fh, 1000 );
close $fh;
is( $offset, 9825, 'Find frame VBR via filehandle ok' );
}
# Find frame CBR with no ASF_Index object
{
my $offset = Audio::Scan->find_frame( _f('wma92-32k.wma'), 740 );
is( $offset, 6679, 'Find frame CBR without ASF_Index ok' );
}
sub _f {
return catfile( $FindBin::Bin, 'asf', shift );
}
|