Audio-M4P
view release on metacpan or search on metacpan
lib/Audio/M4P/QuickTime.pm view on Meta::CPAN
package Audio::M4P::QuickTime;
require 5.008;
use strict;
use warnings;
use Carp;
use Scalar::Util 'weaken';
our $VERSION = '0.57';
use Audio::M4P::Atom;
#-------------- useful hashes and arrays ------------------------------------#
our %meta_info_types = (
aART => 1, # album artist
aaid => 1, # album artist
'©alb' => 1, # album
akid => 1, # ? alternate id ?
apid => 1, # apple id
'©ART' => 1, # artist (performing)
atid => 1, # apple itunes id ?
catg => 1, # category
'©cmt' => 1, # comment field
'©com' => 1, # composer
covr => 1, # cover art
cpil => 1, # 1 if compilation => 0 if not ?
cprt => 1, # copyrighted material purchaser ?
'©day' => 1, # date of release--often just the year
disk => 1, # CD set number: cut is from, disk [field 1] of [field 2]
geid => 1, # iTMS store ID ?
gnre => 1, # genre
'©grp' => 1, # group(?)
'©lyr' => 1, # lyrics
'©nam' => 1, # title of track
pcst => 1, # podcast flag
pgap => 1, # iTunes gapless playback ?
pinf => 1, # iTunes 7.2+ purchaser info ?
plid => 1, # purchase id ?
purd => 1, # iTunes 6+ purchase date
purl => 1, # program URL
rtng => 1, # rating (integer)
sfid => 1, # ? itms ID info
sign => 1, # ? file hash signature
stik => 1, # movie type: 0x1 default, 0x5 bookmarkable, 0x6 music video,
# 0xA TV show, ?? 0x2 newsreel, 0xE ringtone
tmpo => 1, # tempo (beats per minute)
'©too' => 1, # encoder
trkn => 1, # two fields: [field 1] track num. of [field 2] total tracks
tves => 1, # TV show episode
tvsh => 1, # TV show
'©wrt' => 1, # composer
'----' => 1, # itunes specific info
);
our %utf8_atoms = (
aART => 1, # album artist
aaid => 1, # album artist
'©alb' => 1, # album
'©ART' => 1, # artist (performing)
catg => 1, # category
'©cmt' => 1, # comment field
'©com' => 1, # composer
cprt => 1, # copyrighted material purchaser ?
'©day' => 1, # date of release--often just the year
'©grp' => 1, # group(?)
'©lyr' => 1, # lyrics
'©nam' => 1, # title of track
lib/Audio/M4P/QuickTime.pm view on Meta::CPAN
COMMENT => 'dscp', # caption or description for the media
COPYRIGHT => 'cprt', # notice about organisation holding copyright
GENRE => 'gnre', # genre (category and style) of the media
RTNG => 'rtng', # media rating
TITLE => 'titl', # title for the media
YEAR => 'yrrc', # recording year for the media
# these exist in 3GP but not really in iTMS meta data
CLASS => 'clsf', # classification of the media
KEYWORDS => 'kywd', # media keywords
LOCATION => 'loci', # location information
);
our $default_asset_3GP_lang = 'eng';
#------------------- object methods -----------------------------------------#
sub new {
my ( $class, %args ) = @_;
my $self = {};
bless( $self, $class );
$self->{meta} = {};
foreach my $k (qw( DEBUG DEBUGDUMPFILE file)) {
$self->{$k} = $args{$k} if exists $args{$k};
}
$self->{DEBUG} = 0 unless exists $self->{DEBUG};
if ( exists $self->{file} ) {
$self->ReadFile( $self->{file} );
$self->ParseBuffer();
}
return $self;
}
sub DESTROY {
my($self) = @_;
if( ref $self->{root} ) {
$self->{root}->DESTROY;
}
}
sub ReadFile {
my ( $self, $infile ) = @_;
open( my $infh, '<', $infile ) or croak "Cannot open input $infile: $!";
binmode $infh;
read( $infh, $self->{buffer}, -s $infile ) or croak "Bad file read: $!";
close $infh;
$self->{meta}->{filesize} = length $self->{buffer};
}
sub ParseBuffer {
my ($self) = @_;
$self->{atom_count} = 0;
$self->{root} = new Audio::M4P::Atom(
rbuf => \$self->{buffer},
type => 'file',
size => length $self->{buffer},
read_buffer_position => 0,
offset => 8,
parent => 0,
);
weaken $self->{root};
my $fsize = length $self->{buffer};
print "Buffer size is $fsize\n" if $self->{DEBUG};
$self->ParseMP4Container( $self->{root}->node, 0, $fsize );
print "Found $self->{atom_count} atoms.\n" if $self->{DEBUG};
$self->DumpTree( $self->{DEBUGDUMPFILE} ) if $self->{DEBUG} > 1;
}
sub WriteFile {
my ( $self, $outfile ) = @_;
open( my $outfh, '>', $outfile ) or croak "Cannot open output $outfile: $!";
binmode $outfh;
my $retval = print $outfh $self->{buffer};
close $outfh;
return $retval;
}
sub ParseMP4Container {
my ( $self, $parent, $posit, $end_posit ) = @_;
my $pAtom = $parent->getNodeValue() or croak "Cannot get atom from node";
$posit = $pAtom->start + $pAtom->offset unless defined $posit;
$end_posit = $pAtom->start + $pAtom->size unless $end_posit;
while ( $posit < $end_posit ) {
my $atom = new Audio::M4P::Atom(
parent => $parent,
rbuf => \$self->{buffer},
read_buffer_position => $posit
);
print $atom->type, " at $posit size ", $atom->size, "\n"
if $self->{DEBUG};
last unless $atom->size > 7; # sanity check
$self->{atom_count}++;
if ( $atom->type =~ /stsd/i ) { $self->ParseStsd($atom) }
elsif ( $atom->type =~ /mp4a/i ) { $self->ParseMp4a($atom) }
elsif ( $atom->type =~ /drms/i ) { $self->ParseDrms($atom) }
elsif ( $atom->type =~ /meta/i ) { $self->ParseMeta($atom) }
elsif ( $atom->isContainer() ) {
$self->ParseMP4Container(
$atom->node,
$posit + $atom->offset,
$posit + $atom->size - $atom->offset
);
}
else {
print( "done with noncontainer atom of atom of type ",
$atom->type, "\n" )
if $self->{DEBUG};
}
$posit += $atom->size;
}
}
sub ParseStsd {
my ( $self, $stsd ) = @_;
$self->ParseMP4Container(
$stsd->node,
$stsd->start + 16,
$stsd->start + $stsd->size - 16
);
}
( run in 0.647 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )