Ticket #10529: mythweb-0.25-html5-video.patch

File mythweb-0.25-html5-video.patch, 14.2 KB (added by Anthony Messina <amessina@…>, 13 years ago)

MythWeb HTML5 video patch for 0.25

  • includes/utils.php

    diff --git a/includes/utils.php b/includes/utils.php
    index 35b11b3..0b407a3 100644
    a b  
    242242            case 'flvp': return "$url.flvp";
    243243            case 'flv' : return "$url.flv";
    244244            case 'mp4' : return "$url.mp4";
     245            case 'ogv' : return "$url.ogv";
     246            case 'webm': return "$url.webm";
    245247        }
    246248    // No more dsmyth filters, so return the URL no matter what the browser is.
    247249        return $url;
  • modules/stream/handler.pl

    diff --git a/modules/stream/handler.pl b/modules/stream/handler.pl
    index 9015c62..ec48cc4 100755
    a b  
    3333    elsif ($ENV{'REQUEST_URI'} =~ /\.mp4$/i) {
    3434        require "modules/$Path[0]/stream_mp4.pl";
    3535    }
     36# HTML5 video/ogv
     37    elsif ($ENV{'REQUEST_URI'} =~ /\.ogv$/i) {
     38        require "modules/$Path[0]/stream_ogv.pl";
     39    }
     40# HTML5 video/webm
     41    elsif ($ENV{'REQUEST_URI'} =~ /\.webm$/i) {
     42        require "modules/$Path[0]/stream_webm.pl";
     43    }
    3644# Raw file?
    3745    else {
    3846        require "modules/$Path[0]/stream_raw.pl";
  • new file modules/stream/stream_ogv.pl

    diff --git a/modules/stream/stream_ogv.pl b/modules/stream/stream_ogv.pl
    new file mode 100755
    index 0000000..51e02f4
    - +  
     1#!/usr/bin/perl
     2#
     3# MythWeb Streaming/Download module
     4#
     5# @url       $URL$
     6# @date      $Date$
     7# @version   $Revision$
     8# @author    $Author$
     9#
     10
     11    use POSIX qw(ceil floor);
     12
     13# round to the nearest even integer
     14    sub round_even {
     15        my ($in) = @_;
     16        my $n = floor($in);
     17        return ($n % 2 == 0) ? $n : ceil($in);
     18    }
     19
     20    our $ffmpeg_pid;
     21    our $ffmpeg_pgid;
     22
     23# Shutdown cleanup, of various types
     24    $ffmpeg_pgid = setpgrp(0,0);
     25    $SIG{'TERM'} = \&shutdown_handler;
     26    $SIG{'PIPE'} = \&shutdown_handler;
     27    END {
     28        shutdown_handler();
     29    }
     30    sub shutdown_handler {
     31        kill(1, $ffmpeg_pid) if ($ffmpeg_pid);
     32        kill(-1, $ffmpeg_pgid) if ($ffmpeg_pgid);
     33    }
     34
     35# Find ffmpeg
     36    $ffmpeg = '';
     37    foreach my $path (split(/:/, $ENV{'PATH'}.':/usr/local/bin:/usr/bin'), '.') {
     38        if (-e "$path/mythffmpeg") {
     39            $ffmpeg = "$path/mythffmpeg";
     40            last;
     41        }
     42        if (-e "$path/ffmpeg") {
     43            $ffmpeg = "$path/ffmpeg";
     44            last;
     45        }
     46        elsif ($^O eq 'darwin' && -e "$path/ffmpeg.app") {
     47            $ffmpeg = "$path/ffmpeg.app";
     48            last;
     49        }
     50    }
     51
     52# Load some conversion settings from the database
     53    $sh = $dbh->prepare('SELECT data FROM settings WHERE value=? AND hostname IS NULL');
     54    $sh->execute('WebFLV_w');
     55    my ($width)    = $sh->fetchrow_array;
     56    $sh->execute('WebFLV_vb');
     57    my ($vbitrate) = $sh->fetchrow_array;
     58    $sh->execute('WebFLV_ab');
     59    my ($abitrate) = $sh->fetchrow_array;
     60    $sh->finish();
     61# auto-detect height based on aspect ratio
     62    $sh = $dbh->prepare('SELECT data FROM recordedmarkup WHERE chanid=? ' .
     63                        'AND starttime=FROM_UNIXTIME(?) AND type=30 ' .
     64                        'AND data IS NOT NULL ORDER BY mark LIMIT 1');
     65    $sh->execute($chanid,$starttime);
     66    $x = $sh->fetchrow_array;           # type = 30
     67    $sh->finish();
     68
     69    $sh = $dbh->prepare('SELECT data FROM recordedmarkup WHERE chanid=? ' .
     70                        'AND starttime=FROM_UNIXTIME(?) AND type=31 ' .
     71                        'AND data IS NOT NULL ORDER BY mark LIMIT 1');
     72    $sh->execute($chanid,$starttime);
     73    $y = $sh->fetchrow_array if ($x);   # type = 31
     74    $sh->finish();
     75
     76    if (!$x || !$y || $x <= 720) {      # <=720 means SD
     77        $sh = $dbh->prepare('SELECT recordedmarkup.type, ' .
     78               'recordedmarkup.data '.
     79               'FROM recordedmarkup ' .
     80               'WHERE recordedmarkup.chanid = ? ' .
     81               'AND recordedmarkup.starttime = FROM_UNIXTIME(?)  ' .
     82               'AND recordedmarkup.type IN (10, 11, 12, 13, 14) ' .
     83               'GROUP BY recordedmarkup.type  ' .
     84               'ORDER BY SUM((SELECT IFNULL(rm.mark, recordedmarkup.mark) ' .
     85               '   FROM recordedmarkup AS rm ' .
     86               '   WHERE rm.chanid = recordedmarkup.chanid ' .
     87               '   AND rm.starttime = recordedmarkup.starttime ' .
     88               '   AND rm.type IN (10, 11, 12, 13, 14)  ' .
     89               '   AND rm.mark > recordedmarkup.mark ' .
     90               '   ORDER BY rm.mark ASC LIMIT 1)- recordedmarkup.mark) DESC ' .
     91               'LIMIT 1');
     92        $sh->execute($chanid,$starttime);
     93        $aspect = $sh->fetchrow_hashref;
     94        $sh->finish();
     95
     96        if( $aspect->{'type'} == 10 ) {
     97            $x = $y = 1;
     98        } elsif( $aspect->{'type'}== 11 ) {
     99            $x = 4; $y = 3;
     100        } elsif( $aspect->{'type'}== 12 ) {
     101            $x = 16; $y = 9;
     102        } elsif( $aspect->{'type'}== 13 ) {
     103            $x = 2.21; $y = 1;
     104        } elsif( $aspect->{'type'}== 14 ) {
     105            $x = $aspect->{'data'}; $y = 10000;
     106        } else {
     107            $x = 4; $y = 3;
     108        }
     109    }
     110    $height = round_even($width * ($y/$x));
     111
     112    $width    = 320 unless ($width    && $width    > 1);
     113    $height   = 240 unless ($height   && $height   > 1);
     114    $vbitrate = 256 unless ($vbitrate && $vbitrate > 1);
     115    $abitrate = 64  unless ($abitrate && $abitrate > 1);
     116
     117    my $ffmpeg_command = $ffmpeg
     118                        .' -y'
     119                        .' -i '.shell_escape($filename)
     120                        .' -s '.shell_escape("${width}x${height}")
     121                        .' -g 30'
     122                        .' -r 24'
     123                        .' -f ogg'
     124                        .' -acodec libvorbis'
     125                        .' -vcodec libtheora'
     126                        .' -deinterlace'
     127                        .' -async 2'
     128                        .' -ac 2'
     129                        .' -ar 11025'
     130                        .' -ab '.shell_escape("${abitrate}k")
     131                        .' -b '.shell_escape("${vbitrate}k")
     132                        .' /dev/stdout 2>/dev/null |';
     133
     134# Print the movie
     135    $ffmpeg_pid = open(DATA, $ffmpeg_command);
     136    unless ($ffmpeg_pid) {
     137        print header(),
     138                "Can't do ffmpeg: $!\n${ffmpeg_command}";
     139        exit;
     140    }
     141    # Guess the filesize based on duration and bitrate. This allows for progressive download behavior
     142    my $lengthSec;
     143    $dur = `$ffmpeg -i $filename 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//`;
     144    if ($dur && $dur =~ /\d*:\d*:.*/) {
     145        @times = split(':',$dur);
     146        $lengthSec = $times[0]*3600+$times[1]*60+$times[2];
     147        $size = int(1.05*$lengthSec*($vbitrate*1024+$abitrate*1024)/8);
     148        print header(-type => 'video/ogg','Content-Length' => $size);
     149    } else {
     150        print header(-type => 'video/ogg');
     151    }
     152
     153    while (<DATA>) {
     154        print $_;
     155    }
     156    close DATA;
     157
     158    1;
  • new file modules/stream/stream_webm.pl

    diff --git a/modules/stream/stream_webm.pl b/modules/stream/stream_webm.pl
    new file mode 100755
    index 0000000..fb10ebe
    - +  
     1#!/usr/bin/perl
     2#
     3# MythWeb Streaming/Download module
     4#
     5# @url       $URL$
     6# @date      $Date$
     7# @version   $Revision$
     8# @author    $Author$
     9#
     10
     11    use POSIX qw(ceil floor);
     12
     13# round to the nearest even integer
     14    sub round_even {
     15        my ($in) = @_;
     16        my $n = floor($in);
     17        return ($n % 2 == 0) ? $n : ceil($in);
     18    }
     19
     20    our $ffmpeg_pid;
     21    our $ffmpeg_pgid;
     22
     23# Shutdown cleanup, of various types
     24    $ffmpeg_pgid = setpgrp(0,0);
     25    $SIG{'TERM'} = \&shutdown_handler;
     26    $SIG{'PIPE'} = \&shutdown_handler;
     27    END {
     28        shutdown_handler();
     29    }
     30    sub shutdown_handler {
     31        kill(1, $ffmpeg_pid) if ($ffmpeg_pid);
     32        kill(-1, $ffmpeg_pgid) if ($ffmpeg_pgid);
     33    }
     34
     35# Find ffmpeg
     36    $ffmpeg = '';
     37    foreach my $path (split(/:/, $ENV{'PATH'}.':/usr/local/bin:/usr/bin'), '.') {
     38        if (-e "$path/mythffmpeg") {
     39            $ffmpeg = "$path/mythffmpeg";
     40            last;
     41        }
     42        if (-e "$path/ffmpeg") {
     43            $ffmpeg = "$path/ffmpeg";
     44            last;
     45        }
     46        elsif ($^O eq 'darwin' && -e "$path/ffmpeg.app") {
     47            $ffmpeg = "$path/ffmpeg.app";
     48            last;
     49        }
     50    }
     51
     52# Load some conversion settings from the database
     53    $sh = $dbh->prepare('SELECT data FROM settings WHERE value=? AND hostname IS NULL');
     54    $sh->execute('WebFLV_w');
     55    my ($width)    = $sh->fetchrow_array;
     56    $sh->execute('WebFLV_vb');
     57    my ($vbitrate) = $sh->fetchrow_array;
     58    $sh->execute('WebFLV_ab');
     59    my ($abitrate) = $sh->fetchrow_array;
     60    $sh->finish();
     61# auto-detect height based on aspect ratio
     62    $sh = $dbh->prepare('SELECT data FROM recordedmarkup WHERE chanid=? ' .
     63                        'AND starttime=FROM_UNIXTIME(?) AND type=30 ' .
     64                        'AND data IS NOT NULL ORDER BY mark LIMIT 1');
     65    $sh->execute($chanid,$starttime);
     66    $x = $sh->fetchrow_array;           # type = 30
     67    $sh->finish();
     68
     69    $sh = $dbh->prepare('SELECT data FROM recordedmarkup WHERE chanid=? ' .
     70                        'AND starttime=FROM_UNIXTIME(?) AND type=31 ' .
     71                        'AND data IS NOT NULL ORDER BY mark LIMIT 1');
     72    $sh->execute($chanid,$starttime);
     73    $y = $sh->fetchrow_array if ($x);   # type = 31
     74    $sh->finish();
     75
     76    if (!$x || !$y || $x <= 720) {      # <=720 means SD
     77        $sh = $dbh->prepare('SELECT recordedmarkup.type, ' .
     78               'recordedmarkup.data '.
     79               'FROM recordedmarkup ' .
     80               'WHERE recordedmarkup.chanid = ? ' .
     81               'AND recordedmarkup.starttime = FROM_UNIXTIME(?)  ' .
     82               'AND recordedmarkup.type IN (10, 11, 12, 13, 14) ' .
     83               'GROUP BY recordedmarkup.type  ' .
     84               'ORDER BY SUM((SELECT IFNULL(rm.mark, recordedmarkup.mark) ' .
     85               '   FROM recordedmarkup AS rm ' .
     86               '   WHERE rm.chanid = recordedmarkup.chanid ' .
     87               '   AND rm.starttime = recordedmarkup.starttime ' .
     88               '   AND rm.type IN (10, 11, 12, 13, 14)  ' .
     89               '   AND rm.mark > recordedmarkup.mark ' .
     90               '   ORDER BY rm.mark ASC LIMIT 1)- recordedmarkup.mark) DESC ' .
     91               'LIMIT 1');
     92        $sh->execute($chanid,$starttime);
     93        $aspect = $sh->fetchrow_hashref;
     94        $sh->finish();
     95
     96        if( $aspect->{'type'} == 10 ) {
     97            $x = $y = 1;
     98        } elsif( $aspect->{'type'}== 11 ) {
     99            $x = 4; $y = 3;
     100        } elsif( $aspect->{'type'}== 12 ) {
     101            $x = 16; $y = 9;
     102        } elsif( $aspect->{'type'}== 13 ) {
     103            $x = 2.21; $y = 1;
     104        } elsif( $aspect->{'type'}== 14 ) {
     105            $x = $aspect->{'data'}; $y = 10000;
     106        } else {
     107            $x = 4; $y = 3;
     108        }
     109    }
     110    $height = round_even($width * ($y/$x));
     111
     112    $width    = 320 unless ($width    && $width    > 1);
     113    $height   = 240 unless ($height   && $height   > 1);
     114    $vbitrate = 256 unless ($vbitrate && $vbitrate > 1);
     115    $abitrate = 64  unless ($abitrate && $abitrate > 1);
     116
     117    my $ffmpeg_command = $ffmpeg
     118                        .' -y'
     119                        .' -i '.shell_escape($filename)
     120                        .' -s '.shell_escape("${width}x${height}")
     121                        .' -g 30'
     122                        .' -r 24'
     123                        .' -f webm'
     124                        .' -acodec libvorbis'
     125                        .' -vcodec libvpx'
     126                        .' -deinterlace'
     127                        .' -async 2'
     128                        .' -ac 2'
     129                        .' -ar 11025'
     130                        .' -ab '.shell_escape("${abitrate}k")
     131                        .' -b '.shell_escape("${vbitrate}k")
     132                        .' /dev/stdout 2>/dev/null |';
     133
     134# Print the movie
     135    $ffmpeg_pid = open(DATA, $ffmpeg_command);
     136    unless ($ffmpeg_pid) {
     137        print header(),
     138                "Can't do ffmpeg: $!\n${ffmpeg_command}";
     139        exit;
     140    }
     141    # Guess the filesize based on duration and bitrate. This allows for progressive download behavior
     142    my $lengthSec;
     143    $dur = `$ffmpeg -i $filename 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//`;
     144    if ($dur && $dur =~ /\d*:\d*:.*/) {
     145        @times = split(':',$dur);
     146        $lengthSec = $times[0]*3600+$times[1]*60+$times[2];
     147        $size = int(1.05*$lengthSec*($vbitrate*1024+$abitrate*1024)/8);
     148        print header(-type => 'video/webm','Content-Length' => $size);
     149    } else {
     150        print header(-type => 'video/webm');
     151    }
     152
     153    while (<DATA>) {
     154        print $_;
     155    }
     156    close DATA;
     157
     158    1;
  • modules/tv/tmpl/default/detail.php

    diff --git a/modules/tv/tmpl/default/detail.php b/modules/tv/tmpl/default/detail.php
    index cdd8093..1183c8c 100644
    a b  
    649649
    650650            <div class="x-pixmap">
    651651<?php   if (setting('WebFLV_on')) { ?>
     652          <!--Embed HTML5 video if supported-->
     653            <video controls="controls" preload="none" width="<?php echo $flv_w ?>" height="<?php echo $flv_h ?>" poster="<?php echo $program->thumb_url($flv_w,0) ?>">
     654                <source src="<?php echo video_url($program, 'ogv'); ?>" type="video/ogg" />
     655                <source src="<?php echo video_url($program, 'webm'); ?>" type="video/webm" />
    652656<?php       if (file_exists('js/libs/flowplayer/flowplayer.swf')) { ?>
    653657
    654658
     
    793797                        </embed>
    794798                    </object>
    795799                    </noscript>
     800          <!--Close HTML5 video tag-->
     801            </video>
    796802<?php       } ?>
    797803<?php   } else { ?>
    798804                <a href="<?php echo $program->url ?>" title="<?php echo t('Direct Download') ?>"
  • mythweb.conf.apache

    diff --git a/mythweb.conf.apache b/mythweb.conf.apache
    index c2a4f00..d7dade2 100644
    a b  
    184184    # those are, so we should tell it.
    185185        AddType video/nuppelvideo   .nuv
    186186
     187    # Support HTML5 video formats which can be encoded and streamed "on-the-fly"
     188        AddType video/ogg           .ogv .ogg
     189        AddType video/webm          .webm
     190
    187191    # Specify the MIME type for favicon.ico in case the server configuration
    188192    # doesn't or in case the server configuration uses the IANA-approved MIME type
    189193    # (image/vnd.microsoft.icon)--which most browsers won't recognize.