Ticket #10529: mythweb-0.25-html5-video.patch
File mythweb-0.25-html5-video.patch, 14.2 KB (added by , 13 years ago) |
---|
-
includes/utils.php
diff --git a/includes/utils.php b/includes/utils.php index 35b11b3..0b407a3 100644
a b 242 242 case 'flvp': return "$url.flvp"; 243 243 case 'flv' : return "$url.flv"; 244 244 case 'mp4' : return "$url.mp4"; 245 case 'ogv' : return "$url.ogv"; 246 case 'webm': return "$url.webm"; 245 247 } 246 248 // No more dsmyth filters, so return the URL no matter what the browser is. 247 249 return $url; -
modules/stream/handler.pl
diff --git a/modules/stream/handler.pl b/modules/stream/handler.pl index 9015c62..ec48cc4 100755
a b 33 33 elsif ($ENV{'REQUEST_URI'} =~ /\.mp4$/i) { 34 34 require "modules/$Path[0]/stream_mp4.pl"; 35 35 } 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 } 36 44 # Raw file? 37 45 else { 38 46 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 649 649 650 650 <div class="x-pixmap"> 651 651 <?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" /> 652 656 <?php if (file_exists('js/libs/flowplayer/flowplayer.swf')) { ?> 653 657 654 658 … … 793 797 </embed> 794 798 </object> 795 799 </noscript> 800 <!--Close HTML5 video tag--> 801 </video> 796 802 <?php } ?> 797 803 <?php } else { ?> 798 804 <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 184 184 # those are, so we should tell it. 185 185 AddType video/nuppelvideo .nuv 186 186 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 187 191 # Specify the MIME type for favicon.ico in case the server configuration 188 192 # doesn't or in case the server configuration uses the IANA-approved MIME type 189 193 # (image/vnd.microsoft.icon)--which most browsers won't recognize.