This is a short module to grab various informations from a video (or audio) file. I did two versions : one using mpgtx (http://mpgtx.sourceforge.net/) one using ffmpeg (http://ffmpeg.sourceforge.net/).
The mpgtx version works only with MPEG files, obviously, but it reports the duration right. FFMPEG reads most formats (avi, divx, etc) BUT reports the duration very approximately.
mpgtx version
#!/usr/bin/perl -w # ###################################################################### +##### # # videoinfo.pm # # V 0.3.1 08/04/05 # returns duration in frames (25f/s default) # # V 0.3.0 08/01/05 # use mpginfo instead of ffmpeg # # V 0.2.0 du 13/12/2004 # support of ffmpeg CVS # # V 0.1.0 of 20/11/2004 # ###################################################################### +##### # # Copyright (c) Intellique 2004 # All rights reserved. # # # This program is free software; you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. use strict; require Exporter; our @ISA=qw(Exporter); our @EXPORT=qw(videoinfo); # débug (set to true top get debugging messages) my $debug; # mpginfo command my $mpginfo='/usr/bin/mpgtx -i'; ########################################################## # videoinfo # returns media information in a hash # ########################################################## sub videoinfo { # variables my %finfo = ('duration' => "0", # duration in frames 'bitrate' => "0", # Mux bitrate video + audio 'vcodec' => "", 'vformat' => "", 'framerate' => "0.00", 'acodec' => "", 'samplerate' => "0", 'stereo' => "0", # 0 false (mono), 1 true (stereo) 'audiorate' => "0" ); # file to test my $file=shift; # escaping characters $file=~s/(\W)/\\$1/g; my @res; #scan only MPEG if ( $file =~ m/(MP.)$/i) { @res= `$mpginfo $file` or warn "can't run $mpginfo\n"; } # parse mpgtx output foreach (@res) { # bitrate total if ( m!Muxrate : (\d+\.?\d*) Mbps! ) { $finfo{'bitrate'}=$1; next; } # Duration if ( m!Duration: (.*[0-9][0-9]\.[0-9][0-9])s! ) { $finfo{'duration'}=$1; # convert to frame count my @tu=split(/:|\./, $finfo{'duration'}); # parse duration from end my ($c, $s, $m, $h)=reverse(@tu); # duration in seconds, converted to frames later no warnings qw(uninitialized); $finfo{'duration'}=($h*360000+$m*6000+$s*100+$c)/100; use warnings; next; } # vformat and framerate if ( /Size \[(\d+ x \d+)\]\s+(\d+\.\d+) fps/) { $finfo{'vformat'}=$1; $finfo{'framerate'}=$2; next; } # acodec if ( m!Audio : (.*)! ) { $finfo{'acodec'}=$1; next; } # audiorate and samplerate if ( m!\s+(\d+) kbps (\d+) Hz! ) { $finfo{'audiorate'}=$1; $finfo{'samplerate'}=$2; next; } # Stereo or mono if ( /Stereo/ ) { $finfo{'stereo'}=1; } } # compute the duration in frames if ($finfo{'framerate'}>1) { $finfo{'duration'}=sprintf( "%.0f", $finfo{'duration'}*$finfo{'fra +merate'}); } else { #if no framerate (audio) set to default 25/s $finfo{'duration'}=sprintf( "%.0f", $finfo{'duration'}*25); } return %finfo; } ########################################## # end ########################################## 1;
ffmpeg version
#!/usr/bin/perl -w # ###################################################################### +##### # # # V 0.2.0 du 13/12/2004 # support of ffmpeg CVS # # videoinfo.pm # V 0.1.0 du 20/11/2004 # ###################################################################### +##### # # Copyright (c) Intellique 2004 # All rights reserved. # # # This program is free software; you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. use strict; require Exporter; use IPC::Open3; our @ISA=qw(Exporter); our @EXPORT=qw(videoinfo); ########################################################## # videoinfo # returns media information in a hash # ########################################################## sub videoinfo { # ffmpeg command my $ffmpeg='/usr/bin/ffmpeg'; # variables my %finfo = ('duration' => "00:00:00.0", 'bitrate' => "0", 'vcodec' => "", 'vformat' => "", 'framerate' => "0.00", 'acodec' => "", 'samplerate' => "0", 'stereo' => "0", # 0 false (mono), 1 true (stereo) 'audiorate' => "0" ); # fichier à traiter my $file=shift; # escaping characters $file=~s/(\W)/\\$1/g; open3("</dev/null",">/dev/null",\*ERPH, "$ffmpeg -i $file") or die "ca +n't run $ffmpeg\n"; my @res=<ERPH>; # parse ffmpeg output foreach (@res) { # duration and bitrate if ( m!Duration: ([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9]), bitrate +: (\d*) kb/s! ) { $finfo{'duration'}=$1; $finfo{'bitrate'}=$2; } # vcodec, vformat and framerate if ( /Video: (\w*), (\d*x\d*), (\d*.\d*) fps/) { $finfo{'vcodec'}=$1; $finfo{'vformat'}=$2; $finfo{'framerate'}=$3; } # acodec, samplerate, stereo and audiorate if ( m!Audio: (\w*), (\d*) Hz, (mono|stereo), (\d*) kb/s!) { $finfo{'acodec'}=$1; $finfo{'samplerate'}=$2; $finfo{'stereo'}=(($3 eq 'stereo')|| 0 ); $finfo{'audiorate'}= +$4; } } return %finfo; } ########################################## # end ########################################## 1;

Replies are listed 'Best First'.
Re: Video information
by ihb (Deacon) on May 09, 2005 at 20:06 UTC

    Have you checked out Video::Info on CPAN?

    ihb

    See perltoc if you don't know which perldoc to read!

      Yes, and it didn't do what I needed at the time I checked a few months ago. There was an older one (MPEG::Info?) that did, but has been removed, so I made this quick hack to scratch my itch :)
Re: Video information
by jeffa (Bishop) on May 09, 2005 at 16:48 UTC

    That's not really a module ... first, even if you do consider that a module, it really is two modules. Second, modules are not meant to be executed, so no need for the 'she-bang' line. Third, if you are going to make a module, i really recommend you stick with the Object Oriented paradigm, but that's just me. Here is a shell that uses OO as well as allows the client to chose whether to use mpgtx or ffmpeg. (This is untested.)

    package Info::Video; use strict; use warnings; my %value_types = ( mpginfo => '/usr/bin/mpgtx -i', ffmpeg => '/usr/bin/ffmpeg', ); sub new { my $class = shift; my $type = shift || 'mpginfo'; die "invalid type:$type\n" unless $valid_type{$type}; my $self = { type => $type, duration => '00:00:00.0', bitrate => 0, vcodec => '', vformat => '', framerate => '0.00', acodec => '', samplerate => 0, stereo => 0, audiorate => 0, }; return bless $self, $class; } sub video_info { my $self = shift; my $file = shift; # note: use $valid_types{ $self->{type} } for executable if ($self->{type} eq 'mpginfo') { # handle mpginfo } elsif ($self->{type} eq 'ffmpg') { # handle ffmpg } return $self; } 1;
    And a simple client:
    #!/usr/bin/perl use strict; use warnings; use Info::Video; my $info = Info::Video->new('ffmpeg'); $info->video_info(); # now $info contains the video information

    That's a decent "first stab" at the problem. It is far from optimal, but it should illustrate a better way of getting things done. I don't like having to use an if-elsif inside the video_info() sub ... i would consider using a Factory Pattern instead (or Class::Factory). I would also consider using Class::MethodMaker so that you can automatically add accessor methods to your object, instead of mucking directly with the attributes. Finally ... use POD! Don't use simple # comments for documentation, save those for simple comments.

    And finally finally, don't stick use warnings; in the middle of a for loop. Cheers! :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)