Perlbal - request - help with streaming flash video through perlbal

This is Interesting: Free IT Magazines  
Home > Archive > Perlbal > November 2007 > request - help with streaming flash video through perlbal





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author request - help with streaming flash video through perlbal
EJH Pollard

2007-11-22, 7:11 am

Hi Eric, and the perlbal list members,

[Cross-posted to the mogilefs mailing list, where there was discussion
about perlbal and FLV streaming in april 2007, and a patch from Eric.]

I've been reading with interest the posts on the mogilefs mailing list
from April 2007 regarding FLV (flash video) streaming through perlbal.
I'm asking for your help because I'm not 100% sure how to modify the
patch at http://lists.danga.com/pipermail/mo...ril/000862.html
to enable some slightly different behaviour (for a free online archive
of the UK parliament's video coverage).

Basically, I'm working with the civic activism charity mySociety
(www.mysociety.org) on a beta site that captures streaming footage of
the UK parliament, converts it into FLV format, and then makes it
available for people to view online alongside the written record
(www.theyworkforyou.com - video not yet online, we're still in closed
beta). At the moment we're using lighttpd on an Amazon EC2 instance,
the mod_flv_streaming module and a local store of the FLV files, which
enables our users to jump around in the footage using byte offsets and
the 13-byte header trick
(http://blog.lighttpd.net/articles/2...g-with-lighttpd).
However, we're eventually going to run out of space on the local
drive, so I would prefer to run a perlbal proxy that streams from FLV
files stored on Amazon S3. This would have the advantage of allowing
us to scale to meet future demand by simply adding more EC2 servers
running perlbal and proxying out of S3.

In other words, an HTTP GET request to the perlbal server for
www.example.com/999.flv?start=xxxx would be handled by 1) perlbal
sends the 13 byte FLV header to the client, 2) perlbal does an HTTP
GET request to s3.amazonaws.com/bucket-name/999.flv with a "Range:
xxxx" header, and then streams the output from S3 to the client. For
extra bonus points, rate-limited to 35kbps, to save us some money on
uncessary downloads of the whole FLV file (it plays out 33kbps, and we
don't need to seek ahead and fill up the cache).

Is it possible to configure perlbal, patched as per
http://lists.danga.com/pipermail/mo...il/000862.html, to
behave in the manner described above? If not, do you have any
suggestions for what I should do to the patch/config to make it work
like that? We have a modest budget, and if it's a lot of work then I
would be happy to pay someone for their effort in helping us to
produce a working solution.

Thanks,

Etienne
--
Etienne Pollard
email@ejhp.net
+44 (0) 7946 415 996



--
Etienne Pollard
email@ejhp.net
+44 (0) 7946 415 996



--
Etienne Pollard
email@ejhp.net
+44 (0) 7946 415 996

John Berthels

2007-11-28, 7:12 am

On 22/11/2007, EJH Pollard <ejhpollard@gmail.com> wrote:
> I've been reading with interest the posts on the mogilefs mailing list
> from April 2007 regarding FLV (flash video) streaming through perlbal.
> I'm asking for your help because I'm not 100% sure how to modify the
> patch at http://lists.danga.com/pipermail/mo...ril/000862.html
> to enable some slightly different behaviour (for a free online archive
> of the UK parliament's video coverage).


Hi,

We've recently made the following local update to perlbal, heavily
based on the patch which went to the list, which adds support for two
more x-reproxy- headers back from the application:

x-reproxy-prefix - a hex encoded prefix to be prepended to the
reproxied response (a slightly generalised alternative to the original
patch's approach of hardcoding the FLV header in perlbal)

x-reproxy-additional-hdrs, a | separated list of additional headers to
add to the reproxied request (we need this since the original app
request isn't actually a partial GET, so we pass back an appropriate
Range: header to be included in the reproxied request).

(The patch also causes perlbal to advertise a new
x-reproxy-capability, 'reproxy-prefix', treating the header as a
comma-separated list).

Does anyone have any objections to my committing this?

regards,

jb

should apply cleanly to current perlbal with 'patch -p1' in top-level dir.

diff --git a/lib/Perlbal/BackendHTTP.pm b/lib/Perlbal/BackendHTTP.pm
index b6e774e..84f04ba 100644
--- a/lib/Perlbal/BackendHTTP.pm
+++ b/lib/Perlbal/BackendHTTP.pm
@@ -257,7 +257,7 @@ sub assign_client {
$hds->header("Connection", $persist ? "keep-alive" : "close");

if ($svc->{enable_reproxy}) {
- $hds->header("X-Proxy-Capabilities", "reproxy-file");
+ $hds->header("X-Proxy-Capabilities", "reproxy-file, reproxy-prefix");
}

# decide whether we trust the upstream or not, to give us useful
@@ -453,6 +453,13 @@ sub handle_response { # : void

my $reproxy_cache_for = $hd->header('X-REPROXY-CACHE-FOR') || 0;

+ if ($hd->header('X-REPROXY-ADDITIONAL-HDRS')) {
+ foreach my $line (split (/\|/,
$hd->header('X-REPROXY-ADDITIONAL-HDRS'))) {
+ my ($hdr, $val) = $line =~ /^(\S*).*$)/;
+ $client->{reproxy_additional_hdrs}->{$hdr} = $val;
+ }
+ }
+
# special cases: reproxying and retrying after server errors:
if ((my $rep = $hd->header('X-REPROXY-FILE')) && $self->may_reproxy) {
# make the client begin the async IO while we move on
@@ -493,12 +500,24 @@ sub handle_response { # : void
# if we had an alternate primary response header, make sure
# we send the real content-length (from the reproxied URL)
# and not the one the first server gave us
+ my $prefix;
if ($client->{primary_res_hdrs}) {
- $thd->header('Content-Length', $hd->header('Content-Length'));
+ # If we are adding a prefix to the reproxy, adjust content-length
+ $prefix = pack('H*',
$client->{primary_res_hdrs}->header('X-REPROXY-PREFIX'))
+ if $client->{primary_res_hdrs}->header('X-REPROXY-PREFIX');
+ if (defined $prefix) {
+ $thd->header('Content-Length',
$hd->header('Content-Length') + length($prefix));
+ }
+ else {
+ $thd->header('Content-Length', $hd->header('Content-Length'));
+ }
+
$thd->header('X-REPROXY-FILE', undef);
$thd->header('X-REPROXY-URL', undef);
$thd->header('X-REPROXY-EXPECTED-SIZE', undef);
$thd->header('X-REPROXY-CACHE-FOR', undef);
+ $thd->header('X-REPROXY-PREFIX', undef);
+ $thd->header('X-REPROXY-ADDITIONAL-HDRS', undef);

# also update the response code, in case of 206 partial content
my $rescode = $hd->response_code;
@@ -508,6 +527,7 @@ sub handle_response { # : void

print " writing response headers to client\n" if Perlbal::DEBUG >= 3;
$client->write($thd->to_string_ref);
+ $client->write($prefix) if $prefix;

print(" content_length=", (defined $self->{content_length} ?
$self->{content_length} : "(undef)"),
" remain=", (defined
$self->{content_length_remain} ? $self->{content_length_remain} :
"(undef)"), "\n")
diff --git a/lib/Perlbal/ClientProxy.pm b/lib/Perlbal/ClientProxy.pm
index 08d769f..7ff5f87 100644
--- a/lib/Perlbal/ClientProxy.pm
+++ b/lib/Perlbal/ClientProxy.pm
@@ -47,6 +47,7 @@ use fields (

# error-retrying stuff
'retry_count', # number of times we've retried
this request so far after getting 500 errors
+ 'reproxy_additional_hdrs', # Headers we should
add to the reproxied request
);

use constant READ_SIZE => 131072; # 128k, ~common TCP window size?
@@ -112,6 +113,8 @@ sub init {
$self->{currently_reproxying} = undef;

$self->{retry_count} = 0;
+
+ $self->{reproxy_additional_hdrs} = undef;
}

# given a service name, re-request (GET/HEAD only) to that service, even though
@@ -234,6 +237,9 @@ sub use_reproxy_backend {
if (my $host = $self->{req_headers}->header("Host")) {
$extra_hdr .= "Host: $host\r\n";
}
+ foreach my $hdr (keys %{$self->{reproxy_additional_hdrs}}) {
+ $extra_hdr .= "$hdr: $self->{reproxy_additional_hdrs}->{$hdr}\r\n";
+ }

my $req_method = $self->{req_headers}->request_method eq 'HEAD' ?
'HEAD' : 'GET';
my $headers = "$req_method $datref->[2] HTTP/1.0\r\nConnection:
keep-alive\r\n${extra_hdr}\r\n";
@@ -477,6 +483,7 @@ sub http_response_sent {
$self->{upload_session} = undef;
$self->{chunked_upload_state} = undef;
$self->{request_body_length} = undef;
+ $self->{reproxy_additional_hdrs} = undef;
return 1;
}

Eric Lambrecht

2007-11-28, 7:12 am

EJH Pollard wrote:
> In other words, an HTTP GET request to the perlbal server for
> www.example.com/999.flv?start=xxxx would be handled by 1) perlbal
> sends the 13 byte FLV header to the client, 2) perlbal does an HTTP
> GET request to s3.amazonaws.com/bucket-name/999.flv with a "Range:
> xxxx" header, and then streams the output from S3 to the client. For
> extra bonus points, rate-limited to 35kbps, to save us some money on
> uncessary downloads of the whole FLV file (it plays out 33kbps, and we
> don't need to seek ahead and fill up the cache).
>
> Is it possible to configure perlbal, patched as per
> http://lists.danga.com/pipermail/mo...il/000862.html, to
> behave in the manner described above? If not, do you have any
> suggestions for what I should do to the patch/config to make it work
> like that? We have a modest budget, and if it's a lot of work then I


Hi Etienne -
I believe the patch I submitted will do what you want, but you're
missing one component.

In your email the perlbal server recognizes the '?start=xxx' request
parameters, makes a modified response to the S3 storage server, and
proxies the file out to the client.

My patch doesn't put any smarts into perlbal - it assumes that you've
got another web server that is interpreting the incoming request,
mapping it to a location in S3 (or mogile), and telling perlbal where to
get that final file and to also include that magic 13 byte header.

To make things work with my patch, you need to first set up perlbal to
reproxy all requests to some webserver you've got running on the same
machine.

Then let's assume your requests for flash files all look like this:

GET /play?id=123123&start=5675675

Where 'id' is the id of the flash file, and 'start' is the byte offset
for the FLV file.

The '/play' cgi script on your webserver should map the value of 'id' to
the location of your flash file in S3 (lets say that is
's3.amazon.com/123123'), and send these headers back to perlbal:

X-REPROXY-URL: http://s3.amazon.com/123123
X-REPROXY-FLV-START: 5675675

perlbal will then close the connection to the webserver, open a
connection to S3, jump to byte offset 5675675, send the 13 byte magic
header to the client, then send the remainder of the flv file to the client.

So the only real development you need to do is to create that cgi script
that generates those headers, which should be pretty easy.

Eric...


Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com