package Slim::Formats::WMA; # $Id: WMA.pm 30173 2010-02-16 18:20:53Z agrundman $ # Squeezebox Server Copyright 2001-2009 Logitech. # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License, # version 2. use strict; use base qw(Slim::Formats); use Slim::Utils::Log; use Audio::Scan; my $sourcelog = logger('player.source'); my %tagMapping = ( 'Author' => 'ARTIST', 'Title' => 'TITLE', 'WM/AlbumArtist' => 'ALBUMARTIST', 'WM/AlbumTitle' => 'ALBUM', 'WM/Composer' => 'COMPOSER', 'WM/Genre' => 'GENRE', 'WM/TrackNumber' => 'TRACKNUM', 'WM/PartOfACompilation' => 'COMPILATION', 'Description' => 'COMMENT', 'replaygain_track_gain' => 'REPLAYGAIN_TRACK_GAIN', 'replaygain_track_peak' => 'REPLAYGAIN_TRACK_PEAK', 'replaygain_album_gain' => 'REPLAYGAIN_ALBUM_GAIN', 'replaygain_album_peak' => 'REPLAYGAIN_ALBUM_PEAK', 'WM/PartOfSet' => 'DISC', 'WM/ArtistSortOrder' => 'ARTISTSORT', 'WM/AlbumSortOrder' => 'ALBUMSORT', 'WM/Comments' => 'COMMENT', 'WM/Lyrics' => 'LYRICS', 'WM/Year' => 'YEAR', ); sub getTag { my $class = shift; my $file = shift || return {}; my $s = Audio::Scan->scan($file); my $info = $s->{info}; my $tags = $s->{tags}; return unless $info->{song_length_ms}; # Map tags onto Squeezebox Server's preferred. while ( my ($old, $new) = each %tagMapping ) { if ( exists $tags->{$old} ) { $tags->{$new} = delete $tags->{$old}; } } # Add additional info my $stream = $info->{streams}->[0]; $tags->{SIZE} = $info->{file_size}; $tags->{SECS} = $info->{song_length_ms} / 1000; $tags->{RATE} = $stream->{samplerate}; $tags->{SAMPLESIZE} = $stream->{bits_per_sample}; $tags->{BITRATE} = $info->{max_bitrate}; $tags->{DRM} = $stream->{encrypted}; $tags->{CHANNELS} = $stream->{channels}; $tags->{LOSSLESS} = $info->{lossless}; $tags->{STEREO} = $tags->{CHANNELS} == 2 ? 1 : 0; if ( $tags->{IsVBR} ) { $tags->{VBR_SCALE} = 1; } if ( grep (/Professional/, map ($_->{'name'}, @{$info->{'codec_list'}})) ) { $tags->{CONTENT_TYPE} = 'wmap'; } elsif ( $tags->{LOSSLESS} ) { $tags->{CONTENT_TYPE} = 'wmal'; } # Flag if we have embedded cover art $tags->{HAS_COVER} = 1 if $tags->{'WM/Picture'}; return $tags; } sub getCoverArt { my $class = shift; my $file = shift || return undef; my $s = Audio::Scan->scan_tags($file); if ( my $pic = $s->{tags}->{'WM/Picture'} ) { if ( ref $pic eq 'ARRAY' ) { # return image with lowest image_type value return ( sort { $a->{image_type} <=> $b->{image_type} } @{$pic} )[0]->{image}; } else { return $pic->{image}; } } return; } sub getInitialAudioBlock { my ($class, $fh) = @_; open my $localFh, '<&=', $fh; seek $localFh, 0, 0; my $s = Audio::Scan->scan_fh( asf => $localFh ); main::DEBUGLOG && $sourcelog->is_debug && $sourcelog->debug( 'Reading initial audio block: length ' . $s->{info}->{audio_offset} ); seek $localFh, 0, 0; read $localFh, my $buffer, $s->{info}->{audio_offset}; close $localFh; return $buffer; } sub findFrameBoundaries { my ($class, $fh, $offset, $time) = @_; if (!defined $fh || !defined $time) { return 0; } return Audio::Scan->find_frame_fh( asf => $fh, int($time * 1000) ); } sub canSeek { 1 } 1;