From 57364ff88e840e7cd3126f4537378bc6660fc98b Mon Sep 17 00:00:00 2001
From: Lawrence Rust <lvr@softsystem.co.uk>
Date: Sun, 1 Jan 2012 14:03:09 +0100
Subject: [PATCH] modules/stream: Reduce video playback startup latency

These fixes considerably reduce video startup latency for common viewers
like totem and gstreamer.

1. RFC 3875 4.3.3. says that a CGI "script MUST NOT provide a response
   message-body for a HEAD request".  At the moment the whole video file
   (which can be several GB) is unnecessarily copied.  This can add
   several seconds of delay and overhead.

2. If the CGI output pipe is closed then the script should stop outputting
   data.  Some clients can GET a URL to parse the headers/length and then
   abort it.  This change can save outputting several GB of data.

Signed-off-by: Lawrence Rust <lvr@softsystem.co.uk>
---
 modules/stream/stream_flv.pl |   10 +++++++++-
 modules/stream/stream_mp4.pl |   10 +++++++++-
 modules/stream/stream_raw.pl |   10 +++++++++-
 3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/modules/stream/stream_flv.pl b/modules/stream/stream_flv.pl
index e8d69b7..f118e8d 100755
--- a/modules/stream/stream_flv.pl
+++ b/modules/stream/stream_flv.pl
@@ -148,6 +148,11 @@
         print header(-type => 'video/x-flv');
     }
 
+# RFC 3875 4.3.3. script MUST NOT provide a response message-body for a HEAD request
+    if ($ENV{'REQUEST_METHOD'} eq 'HEAD') {
+        exit;
+    }
+
     my $buffer;
     if (read DATA, $buffer, 53) {
         print $buffer;
@@ -155,7 +160,10 @@
         $durPrint = reverse pack("d",$lengthSec);
         print $durPrint;
         while (read DATA, $buffer, 262144) {
-            print $buffer;
+        # Exit if the output pipe is broken i.e. client disconnect
+            unless (print $buffer ) {
+                last;
+            }
         }
     }
     close DATA;
diff --git a/modules/stream/stream_mp4.pl b/modules/stream/stream_mp4.pl
index 242fca8..9cedc73 100755
--- a/modules/stream/stream_mp4.pl
+++ b/modules/stream/stream_mp4.pl
@@ -80,13 +80,21 @@
                  );
     }
 
+# RFC 3875 4.3.3. script MUST NOT provide a response message-body for a HEAD request
+    if ($ENV{'REQUEST_METHOD'} eq 'HEAD') {
+        exit;
+    }
+
 # Seek to the requested position
     sysseek DATA, $start, 0;
 
 # Print the content to the browser
     my $buffer;
     while (sysread DATA, $buffer, $read_size ) {
-        print $buffer;
+    # Exit if the output pipe is broken i.e. client disconnect
+        unless (print $buffer ) {
+            last;
+        }
         $size -= $read_size;
         if ($size == 0) {
             last;
diff --git a/modules/stream/stream_raw.pl b/modules/stream/stream_raw.pl
index 31f6854..dbdf79e 100755
--- a/modules/stream/stream_raw.pl
+++ b/modules/stream/stream_raw.pl
@@ -104,13 +104,21 @@
                  );
     }
 
+# RFC 3875 4.3.3. script MUST NOT provide a response message-body for a HEAD request
+    if ($ENV{'REQUEST_METHOD'} eq 'HEAD') {
+        exit;
+    }
+
 # Seek to the requested position
     sysseek DATA, $start, 0;
 
 # Print the content to the browser
     my $buffer;
     while (sysread DATA, $buffer, $read_size ) {
-        print $buffer;
+    # Exit if the output pipe is broken i.e. client disconnect
+        unless (print $buffer ) {
+            last;
+        }
         $size -= $read_size;
         if ($size <= 0) {
             my $fileSize = -s $filename;
-- 
1.7.4.1

