0

I'm developing a site with serves several videos online, using the Catalyst (A perl MVC framework) and the JWplayer, and I need a stable way of stream the videos to the client player with the capability of start the video from a random point.

I searched the web for some ways to do it but I cannot find a simple way of implementing it in Catalyst (RTMP or HTTP Pseudostreaming). The only simple example that i found was a old Catalyst script streaming an MP3 (http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Streaming/lib/Streaming.pm) but I didn't know if that will work as expected if I apply that technique to videos.

What would be a good approach to serve online videos in Catalyst/Perl in a non complicated way? Or what is the recommended way to do it?

Thanks guys!

Community
  • 1
  • 1
h3ct0r
  • 705
  • 1
  • 11
  • 23

2 Answers2

0

This is only a partial answer, as I'm currently stuck on this, as well.

If the files are already in FLV format, then the Static::Simple plugin will work just fine. I've tested it with a file in the root/static/ directory and with the $c->serve_static_file method. Below is my jwplayer setup (wrapped in JQuery's ready function.

<script type="text/javascript" src="[% c.uri_for('/static/js/mediaplayer-5.10') %]/jwplayer.js"></script>
<script type="text/javascript">
$(function() {
        jwplayer('mediaplayer').setup({
        'flashplayer': "[% c.uri_for('/static/js/mediaplayer-5.10/player.swf') %]",
        'id': 'playerID',
        'width': '480',
        'height': '270',
        'file': "[% c.uri_for('/download') %]/dump/ffs/root/static/transcode_jEfhmk.flv"
    }); 
});
</script>

If the file is in another format, you'll need to transcode it. The following is my current attempt. It transcodes it just fine and you can even stream the file to a download, but I'm having trouble getting jwplayer to play from the transcoded stream.

use IPC::Open3;

#path comes in as /flv/path/to/file.avi
sub index :Path :Args {
    my ( $self, $c, @path ) = @_; 
    @path = grep($_ ne '..', @path);
    my $path = join('/',@path);
    my $abs_path = $c->config->{'serve_dir'} . '/';
    $abs_path .= join("/", @path);

    if (-r $abs_path){
        my ($stdin, $stdout, $stderr, $pid);
    #avconv 
    # -i input_file
    # -b:v video bitrate
    # -s video size
    # -r video framerate
    # -an no audio (having trouble with the audio settings)
    # -f format
    # pipe:1 send transcoded video to STDOUT
        $pid = open3($stdin, $stdout, $stderr, "avconv -i \"$abs_path\" -b:v 600k -s 320x240 -r 25 -f flv -an pipe:1");

        $c->response->content_type("video/x-flv");
        $c->response->header('Content-Disposition' => "filename=transcode.flv");
        my $chunk_size = 1048576;
        do {
            read( $stdout, my $buffer, $chunk_size );
            $c->write( $buffer );
        } while (kill(0, $pid)); #loop while transcoding process is alive
    }
}

To add pseudo-streaming, you'll need to make a controller that looks for the start query parameter, then seek to it, and send the $c->response->body to the file handle.

open(my $fh, "<", $path);
binmode($fh);
if ($c->req->param('start')){
    seek($fh, $c->req->param('start'), 0); 
}
$c->response->body($fh);

One caveat: the video must have the key frames in the metadata for jwplayer to be able to seek.

From jwplayer's HTTP streaming page:

Note: Some FLV encoders do not include seekpoints metadata when encoding videos. Without this data, HTTP Pseudostreaming will not work. If you suspect your videos to not have metadata, use our Metaviewer plugin to inspect the video. There should be a seekpoints or keyframes list. If it is not there, use the FLVMDI tool to parse your FLV videos and inject this metadata.

  • The Static::Simple plugin will provide video (using the FLV format) to the player in any start position the player request? I didn't have time to test it today but i will test it and post the results! – h3ct0r Aug 29 '12 at 01:32
  • Looks like I was wrong. My video buffered instantly so I didn't notice you couldn't seek passed the buffered part. Looks like we might need to implement [pseudo-streaming](http://www.longtailvideo.com/support/jw-player/jw-player-for-flash-v5/12534/video-delivery-http-pseudo-streaming#mechanism), catch the start parameter, and seek to it like in the Streaming.pm. At least it's in bytes. Heh. –  Aug 29 '12 at 15:42
  • Thanks for the info, I'm still searching a stable and simple way of doing the streaming. If i succeed i will put the how to here! – h3ct0r Sep 05 '12 at 22:33
0

In the end, I use apache with x_send_file plugin to deliver webm videos (using range byte seek) and Amazon cloud front to deliver mp4 videos and streaming with mp4.

Edit: Ended using a Wowza Streaming Server with a custom plugin to communicate securely with Catalyst. There is no reliable way of streaming video without a dedicated video server, especially for business.

h3ct0r
  • 705
  • 1
  • 11
  • 23