NAME
Linux::DVB::DVBT::TS - Transport Stream utilities
SYNOPSIS
use Linux::DVB::DVBT::TS ;
my $settings_href = {'debug' => $debug} ;
# get file information
my %info = info($filename, $settings_href) ;
# Splitting file...
ts_split($filename, $ofilename, \@cuts, $settings_href) ;
# Cutting file...
ts_cut($filename, $ofilename, \@cuts, $settings_href) ;
# repair a file...
my %stats = repair($filename, $ofilename, \&error_display) ;
sub error_display
{
my ($info_href) = @_ ;
print "ERROR: PID $info_href->{'pidinfo'}{'pid'} $info_href->{'error'}{'str'} [$info_href->{'pidinfo'}{'pktnum'}]\n" ;
}
# Parse the file, calling subroutines on each frame...
parse($filename, {
'mpeg2_rgb_callback' = \&colour_callback
'user_data' => {
'outname' => "$outdir/$base%03d.ppm",
},
}) ;
sub colour_callback
{
my ($tsreader, $info_href, $width, $height, $data, $user_data_href) = @_ ;
## save image
write_ppm($user_data_href->{'outname'}, $info_href->{'framenum'},
$width, $height,
$data,
) ;
}
DESCRIPTION
Module provides a set of useful transport stream utility routines. As well as an underlying transport stream parsing framework, this module also incorporates MPEG2 video decoding and AAC audio decoding.
Callbacks
The transport stream parsing framework works through the video file, calling user provided callback functions at the appropriate points. If you don't specify any callbacks, then the framework will run through the video file and do nothing!
Many of the callbacks have the following common arguments passed to them, and are described here rather than in the callback description:
- $tsreader_ref
-
The $tsreader_ref is a pointer to the TS framework parser that is calling the callback. Some other routines accept this value as a parameters (see "parse_stop($tsreader_ref)"). Do not modify this value!
- $user_data
-
Optionally, you can pass a reference to your own user data into the settings when calling the framework (see "Settings"). This reference is passed back in the $user_data argument
The list of supported callbacks and the arguments they are called with are as follows:
PID callback
pid_callback($tsreader_ref, $pid, $user_data)
The pid of the current stream is passed as an integer in $pid. You must return a TRUE value to tell the framework to continue processing with this pid; otherwise return a FALSE value to indicate that the framework should move on to the next pid.
You can use this to skip processing any unwanted pids (mainly to speed up operation).
Error callback
error_callback($tsreader_ref, $info_href, $user_data)
The information HASH ref contains:
pidinfo = HASH ref containing:
pid = current pid
err_flag = TRUE if error flag is set in this TS packet
pes_start = TRUE is this packet is the start of a PES packet
afc = afc field code
pid_error = count of errors (so far) for this pid
pktnum = TS packet count (from start of video, starting at 0)
error = HASH ref containing:
code = error code
str = error string
Called either when there is an error indication in the transport stream, or for other errors.
TS callback
ts_callback($tsreader_ref, $info_href, $packet, $user_data)
The information HASH ref contains:
pidinfo = (see "Error callback")
This is called with the complete transport stream packet.
Payload callback
payload_callback($tsreader_ref, $info_href, $payload, $user_data)
The information HASH ref contains:
pidinfo = (see "Error callback")
This is called with the payload data of the transport stream packet (i.e. with the headers stripped off).
PES callback
pes_callback($tsreader_ref, $info_href, $pes_packet, $user_data)
The information HASH ref contains:
pidinfo = (see "Error callback")
pesinfo = HASH ref containing:
pes_error = number of errors in PES packets
psi_error = number of errors in PSI packets
ts_error = number of TS packet errors
pes_psi = String set to:
"PES" for a PES packet
"PSI" for an SI packet
pts = presentation timestamp as a HASH ref (see below for details)
dts = display timestamp in same format as pts
start_pts = first pts in video (in same format as pts)
start_dts = first dts in video (in same format as pts)
end_pts = current last pts in video (in same format as pts)
end_dts = current last dts in video (in same format as pts)
rel_pts = pts relative to start (in same format as pts)
rel_dts = dts relative to start (in same format as pts)
The timestamp format (for pts and dts entries) is a HASH containing:
secs = pts integer seconds
usecs = remainder in microseconds
ts = string of the 33-bit timestamp integer
So the time in seconds and fractional seconds can be displayed using:
printf "%d.%06d", $pts->{'secs'}, $pts->{'usecs'} ;
(Note: The 33-bit pts value is (roughly) = 'secs'*90000 + 'usecs'*90)
Called with the complete PES/PSI packet.
PES data callback
pes_data_callback($tsreader_ref, $info_href, $pes_data, $user_data)
The information HASH ref contains:
pidinfo = (see "Error callback")
pesinfo = (see "PES callback")
Called with just the PES/PSI data (i.e. with headers removed).
MPEG2 callback
mpeg2_callback($tsreader_ref, $info_href, $width, $height, $image, $user_data)
The information HASH ref contains:
pidinfo = (see "Error callback")
pesinfo = (see "PES callback")
framenum = Frame number (starting at 0)
gop_pkt = TS packet number of the last GOP (see MPEG2 docs for details on a GOP!)
This callback is called with a greyscale image, 1 per video frame. The image data ($image) is $width pixels wides and $height pixels tall, each pixel being a single 8-bit byte value.
NOTE: If you use the "PES data callback" with the video pid, you can write the data directly into a file and this data will be the raw MPEG2 video.
MPEG2 RGB callback
mpeg2_rgb_callback($tsreader_ref, $info_href, $width, $height, $image, $user_data)
The information HASH ref is as "MPEG2 callback"
This callback is called with a colour image. Here the pixels are represented by 3 consecutive bytes: a byte each for red, green, and blue.
Audio callback
audio_callback($tsreader_ref, $info_href, $audio_data, $user_data)
The information HASH ref contains:
pidinfo = (see "Error callback")
pesinfo = (see "PES callback")
sample_rate = Number of samples pre second (usually 48000)
channels = number of audio channels (usually 2)
samples_per_frame = Total number of samples in an audio frame (usually 1152)
samples = the number of audio samples in the data
audio_framenum = Count of audio frames (starting with 0)
framesize = number of samples per frame for a single channel
Called for every audio frame's worth of data. The audio data is stored as 16-bit values, 1 for each channel.
NOTE: If you use the "PES data callback" with the audio pid, you can write the data directly into a file and this data will be the raw AAC audio for the video.
Progress callback
progress_callback($tsreader_ref, $state_str, $progress, $total, $user_data)
This is a general progress update callback that is called at regular intervals during the parsing of the video file. The $progress and $total values are scaled versions of the current packet count and total number of packets respectively.
The $state_str string is one of:
"START" = callback will be called once with this string at the start of execution
"END" = callback will be called once with this string at the end of execution
"RUNNING" = normal execution - framework is parsing the video file
"STOPPED" = set if the user has told the framework to abort (see "parse_stop($tsreader_ref)")
Settings
The parsing framework accepts a variety of settings. These are passed as values in a HASH ref. The settings HASH ref consists of:
debug = set this to get debug information (higher setting gives more output) [default=0]
num_pkts = number of TS packets to process before stopping [default=0 which means the whole file]
skip_pkts = start processing the file this many packets from the origin [default=0]
origin = used with skip_pkts. May be 0=FILE START, 1=FILE CENTER, 2=FILE END [default=0]
user_data = set to whatever data you like. This is passed on to all callbacks.
pid_callback = see "PID callback"
error_callback = see "error callback"
payload_callback = see "Payload callback"
ts_callback = see "TS callback"
pes_callback = see "PES callback"
pes_data_callback = see "PES data callback"
progress_callback = see "Progress callback"
mpeg2_callback = see "MPEG2 callback"
mpeg2_rgb_callback = see "MPEG2 RGB callback"
audio_callback = see "Audio callback"
Most of the entries may be omitted, but it is expected that at least one callback function be set.
Example
The following example shows the use of the callback in order to save the AAC audio stream to a file:
Linux::DVB::DVBT::TS::parse("file.ts", {
# you can put whatever you like in this...
'user_data' => {
'outname' => "test.aac",
},
# the callback routine:
'audio_callback' => \&audio_callback,
} ;
sub audio_callback
{
my ($tsreader_ref, $info_href, $audio_data, $user_data_href) = @_ ;
open my $fh, ">>$user_data_href->{'outname'}" or die "Unable to write AAC file" ;
print $fh $audio_data ;
close $fh ;
}
Functions
- repair($src, $dest, $error_display)
-
Repair a transport stream file by removing error packets. Returns a hash of repair stats containing a HASH entry per PID. Each entry is of the form:
errors => error count for this pid
details => HASH where the keys are the error reason string, and the values are the error count for that reason.
If any runtime error occurs (e.g. unable to read file), then an error string is added to the HASH with the field 'error'.
$error_display is an optional callback routine (see "Error callback")
At the moment "repair" is probably an overstatement. What this currently does is just dump any packets that contain any errors (transport stream or PES). All of the players/transcoders I've tried so far seem fine with this approach. It also prevents ffmpeg from grabbing all available memory then crashing!
- parse($src, $settings_href)
-
Parse a TS file. Uses the settings HASH ref ($settings_href) to configure the callbacks etc. (see "Settings" for further details).
- parse_stop($tsreader_ref)
-
Abort the parsing of a TS file now (rather than completing to the end of the file).
- info($src, $settings_href)
-
Get information about a TS file. Returns a HASH containing information about the transport stream file:
total_pkts = total number of TS packets in the file
start_ts = first timestamp in file (see "PES callback" for timestamp format)
end_ts = last timestamp in file (see "PES callback" for timestamp format)
duration = HASH ref containing video duration information in timestamp format and also:
hh = integer hours
mm = integer minutes
ss = integer seconds
pids = HASH ref containing an entry per pid found in the file. Each pid contains:
pidinfo = (see "Error callback")
pesinfo = (see "PES callback")
If there is an error of any kind, the returned HASH conatins a single entry:
error = error string describing the error cause
- ts_cut($src, $dest, $cuts_aref, $settings_href)
-
Cut a transport stream file, removing the reqions described in $cuts_aref, saving the results in the new file $dest.
The ARRAY ref $cuts_aref consists of an array of HASH refs, each HASH ref defining the start and end of a region to be cut:
start_pkt = TS packet number of start of region
end_pkt = TS packet number of end of region
(Note that these ar transport stream packet numbers NOT mpeg2 frame counts. You will need to scan the file to produce a lookup table if you want to specify cuts in frames (or video time)).
See "Settings" for a description of $settings_href.
- ts_split($src, $dest, $cuts_aref, $settings_href)
-
Split a transport stream file into multiple files, starting a new file at the boundaries described in the ARRAY ref $cuts_aref (see "ts_cut($src, $dest, $cuts_aref, $settings_href)").
In this case, a new file is created at the start of the boundary and at the end of the boundary. This means that the original file is simply the concatenation of all of the individual files.
The output files are created using the specified destination name (without any exetension), and appending a 4-digit count:
sprintf("%s-%04d.ts", $dest, $filenum)
Where $filenum is the file counter (starting at 1).
For example, with a cut list of:
start=100, end=200 start=500, end=600
and assuming a file of 1000 ts packets, running this function will result in 5 output files (where $dest="file"):
file-0001.ts created from packets 0 to 99 file-0002.ts created from packets 100 to 199 file-0003.ts created from packets 200 to 499 file-0004.ts created from packets 500 to 599 file-0005.ts created from packets 600 to 999
See "Settings" for a description of $settings_href.
- error_str()
-
In the event of an error, calling this routine will return the appropriate error string that (hopefully) makes more sense than an error code integer.
ACKNOWLEDGEMENTS
libmpeg2
This module uses libmpeg2 for MPEG2 video decoding:
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* See http://libmpeg2.sourceforge.net/ for updates.
*
* libmpeg2 is free software; you can redistribute it and/or modify
* 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.
*
* libmpeg2 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
mpegaudiodec
This module uses mpegaudiodec for AAC audio decoding:
* MPEG Audio decoder
* Copyright (c) 2001, 2002 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AUTHOR
Steve Price
Please report bugs using http://rt.cpan.org.
BUGS
None that I know of!
FUTURE
Subsequent releases will include:
Proper transport stream file repair/cutting (which probably involves re-encoding!)
Add parsing of SI streams (e.g. PAT, epg etc) read from a file
COPYRIGHT AND LICENSE
Copyright (C) 2011 by Steve Price
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.