Coming Underground
« Debugging Perl CGI scripts with LighttpdMissing directory structure in Mythweb videos »

MythTV video streaming hack

Permalink 2010-03-10 15:58, by jaervosz, Categories: General, Gentoo Tips, Universe/English, Mythtv , Tags: hack, mythtv

One of our MythTV frontends is a small Dell netbook with SDD and therefor not much disk space. Therefor I decided to hack MythTV to stream videos from the Mythweb Video interface.

First off I had to enable MP4 streaming since I'm often transcoding to MP4.

--- modules/stream/stream_raw.pl.orig  2010-03-10 14:08:32.000000000 +0100
+++ modules/stream/stream_raw.pl       2010-03-10 14:08:48.000000000 +0100
@@ -39,4 +39,8 @@
         $suffix = '.avi';
     }
+    elsif ($basename =~ /\.mp4$/) {
+        $type   = 'video/avi';
+        $suffix = '.mp4';
+    }
     else {
         print header(),

After enabling MP4 streaming you'll have to hack a bit in the tv.pl script. It starts out by determinig the recording type simply by looking at the request URL.

--- modules/stream/tv.pl.orig  2010-03-04 21:02:28.000000000 +0100
+++ modules/stream/tv.pl       2010-03-10 14:26:16.000000000 +0100
@@ -19,40 +19,69 @@
     }
 
-# Which show are we streaming?
-    our $chanid    = url_param('chanid');
-    our $starttime = url_param('starttime');
-    if ($Path[1]) {
-        $chanid    = $Path[1];
-        $starttime = $Path[2];
-        $starttime =~ s/\.\w+$//;
-    }
+# Determine wether we're streaming video or tv
 
-# Get the basename from the database
-    my $sh = $dbh->prepare('SELECT basename, title, subtitle, endtime-starttime
-                              FROM recorded
-                             WHERE starttime=FROM_UNIXTIME(?)
-                                   AND recorded.chanid   = ?');
-    $sh->execute($starttime, $chanid);
-    our ($basename, $title, $subtitle, $runtime) = $sh->fetchrow_array();
-    $sh->finish;
-
-# No match?
-    unless ($basename =~ /\w/) {
-        print header(),
-              "Unknown recording requested.\n";
-        exit;
-    }
+if ($Path[2]) {
+       $type = "tv";
+} elsif ($Path[1]) {
+       $type = "video";
+}
 
-# Find the local file
-    our $filename;
-    $sh = $dbh->prepare('SELECT DISTINCT dirname
-                           FROM storagegroup');
-    $sh->execute();
-    while (my ($video_dir) = $sh->fetchrow_array()) {
-        next unless (-e "$video_dir/$basename");
-        $filename = "$video_dir/$basename";
-        last;
-    }
-    $sh->finish;
+if ( $type eq "tv" ) {
+       # Which show are we streaming?
+           our $chanid    = url_param('chanid');
+           our $starttime = url_param('starttime');
+           if ($Path[1]) {
+               $chanid    = $Path[1];
+               $starttime = $Path[2];
+               $starttime =~ s/\.\w+$//;
+           }
+
+       # Get the basename from the database
+           my $sh = $dbh->prepare('SELECT basename, title, subtitle, endtime-starttime
+                                     FROM recorded
+                                    WHERE starttime=FROM_UNIXTIME(?)
+                                          AND recorded.chanid   = ?');
+           $sh->execute($starttime, $chanid);
+           our ($basename, $title, $subtitle, $runtime) = $sh->fetchrow_array();
+           $sh->finish;
+
+       # Find the local file
+           our $filename;
+           $sh = $dbh->prepare('SELECT DISTINCT dirname
+                                  FROM storagegroup');
+           $sh->execute();
+           while (my ($video_dir) = $sh->fetchrow_array()) {
+               next unless (-e "$video_dir/$basename");
+               $filename = "$video_dir/$basename";
+               last;
+           }
+           $sh->finish;
+
+           1;
+} elsif ( $type eq "video" ) {
+       # Which show are we streaming?
+           our $vidid     = url_param('vidid');
+           if ($Path[1]) {
+               $vidid     = $Path[1];
+           }
+       # Get the basename from the database
+           my $sh = $dbh->prepare('SELECT title, subtitle, filename
+                                    FROM videometadata
+                                    WHERE intid = ?');
+           $sh->execute($vidid);
+           our ($title, $subtitle, $basename) = $sh->fetchrow_array();
+           $sh->finish;
+
+       # Find the local file
+           our $filename;
+           $sh = $dbh->prepare('SELECT DISTINCT dirname
+                                  FROM storagegroup
+                                  WHERE groupname = "Videos"');
+           $sh->execute();
+           my $video_dir = $sh->fetchrow_array();
+               $filename = "$video_dir/$basename";
+
+           $sh->finish;
 
-    1;
+           1;
+}

All that is now left is to make the webinterface display the new links.

--- modules/video/tmpl/default/video.php.orig   2010-03-10 13:30:31.000000000 +0100
+++ modules/video/tmpl/default/video.php        2010-03-10 13:57:53.000000000 +0100
@@ -307,5 +307,8 @@
         <div id="<?php echo $video->intid; ?>_browse" class="hidden"><?php echo $video->browse; ?></div>
         <div id="<?php echo $video->intid; ?>-title" class="title">
-            <a href="<?php echo $video->url; ?>"><?php echo html_entities($video->title); ?></a><?php 
+<?php echo html_entities($video->title); ?>
+            <a href="<?php echo $video->url; ?>"><img src="<?php echo skin_url ?>/img/video_sm.png"></a>
+            <a href="<?php echo ".//pl/stream/$video->intid" . ".asx"; ?>"><img src="<?php echo skin_url ?>/img/play_sm.png">
+           </a><?php 
                   if (($video->season > 0) && ($video->episode >= 0)) 
                       printf('(S%02d E%02d)', $video->season, $video->episode); 

As you can see this is just a quick hack and could probably have been better integrated into MythTV and my Perl skills feel a bit rusty too.

Sorry for the crappy display of code. If you want the diffs as properly formatted text files just drop me a line.

Let me know if you have any comments or other cool hacks.

Update: I split out my mythweb patches and you can download them here:

mythweb-0.22_p22763-carppout-debug.patch
mythweb-0.22_p22763-mp4-streaming.patch
mythweb-0.22_p22763-myth-video-streaming.patch
mythweb-0.22_p22763-path-list.patch
mythweb-0.22_p22763-tmpl-error.patch

2 comments »Send a trackback »

Trackback address for this post

This is a captcha-picture. It is used to prevent mass-access by robots.
Please enter the characters from the image above. (case insensitive)

2 comments

Comment from: M Sutton [Visitor] · http://swinton.rotherham.sch.uk
Hi Jaervosz,

I am very interested in this post as this seems the only mention (after a lot of searching) of being able to watch Video recordings made in MythVideo through MythWeb. I am trying to get this working for a complete video solution for the school I work for.
I know you mentioned this works for mp4 but does it work for avi? Unfortunately my coding skills in this area are zero so any help (and hand holding) would be fantastic!

Hope you can help

Regards
2010-06-08 @ 16:44
Comment from: jaervosz [Member] Email
Hi,

I just added MP4 support, it still supports the standard MPEG,Nuppel video and AVI formats. I just tested with a random AVI file and it works as expected.

I currently use the following diff file to patch mythweb mythweb-video-streaming.patch.
2010-06-08 @ 16:52

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
This is a captcha-picture. It is used to prevent mass-access by robots.
Please enter the characters from the image above. (case insensitive)

©2010 by admin

Contact Jaervosz