The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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:

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:

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:

    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:

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:

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.