Video Streaming using non http backend, Ref ngx_drizzle

Hi All,

I am trying to stream video it can be mp4, flv anything using nginx.

The video streams in the form of 1024 size will be available from the
backend non-http server.

For achieveing this I followed the ngx_http_drizzle source.

I wrote an upstream handler and followed most of the source code from
ngx_http_drizzle.

I have few questions or to be more precise I did not understood how the
output from drizzle is being streamed to the client.

  1. In ngx_http_drizzle_output.c the function ngx_http_drizzle_submit_mem
    is
    the place where it is setting the output filter, Is it also sending the
    response i.e the stream to the client at this point, or it is some other
    function?

  2. What I need to do to send my video contents to the client, I followed
    the drizzle example but setting output and sending stream to the client,
    how I can achieve this. I have 1024B avaialble at one point and I want
    to
    send this to the client till the backend server has no stream to send
    and
    the client should be able to play the content.

  3. Is it possible to send the video stream to the client with the
    browser.

Can someone who knows about this, please explain how it works. What
changes
I need to make.
It would be highly appreciated if anyone explains this.

Thanks,
Raul

Anything on this, just a small hint on how I can configure the output
filter
would be highly appreciated.

Thanks,
Raul


View this message in context:
http://nginx.2469901.n2.nabble.com/Video-Streaming-using-non-http-backend-Ref-ngx-drizzle-tp7580235p7580237.html
Sent from the nginx mailing list archive at Nabble.com.

Hello!

On Mon, Jun 4, 2012 at 10:01 AM, Sammy R. [email protected]
wrote:

I am trying to stream video it can be mp4, flv anything using nginx.

The video streams in the form of 1024 size will be available from the
backend non-http server.

I think this can be done trivially via ngx_lua module while still
achieving good performance. Here is a small example that demonstrates
how to meet your requirements with a little Lua:

location /api {
    content_by_lua '
        local sock, err = ngx.socket.tcp()
        if not sock then
            ngx.log(ngx.ERR, "failed to get socket: ", err)
            ngx.exit(500)
        end

        sock:settimeout(1000)  -- 1 sec

        local ok, err = sock:connect("some.backend.host", 12345)
        if not ok then
            ngx.log(ngx.ERR, "failed to connect to upstream: ", err)
            ngx.exit(502)
        end

        local bytes, err = sock:send("some query")
        if not bytes then
            ngx.log(ngx.ERR, "failed to send query: ", err)
            ngx.exit(502)
        end

        while true do
            local data, err, partial = sock:receive(1024)
            if not data then
                if err == "closed" then
                    if partial then
                        ngx.print(partial)
                        ngx.eof()
                        ngx.exit(ngx.OK)
                    end
                else
                    ngx.log(ngx.ERR, "error reading data: ", err)
                    ngx.exit(502)
                end
            else
                ngx.print(data)
                ngx.flush(true)
           end
        end
    ';
}

See the documentation for details:

http://wiki.nginx.org/HttpLuaModule

For achieveing this I followed the ngx_http_drizzle source.

I wrote an upstream handler and followed most of the source code from
ngx_http_drizzle.

As the author of ngx_drizzle, I suggest you start from trying out
ngx_lua. Customizing ngx_drizzle for your needs requires a lot of
work. The C approach should only be attempted when Lua is indeed too
slow for your purpose, which is not very likely for many applications
though.

Also, please note that ngx_drizzle does not support strict
non-buffered data output. So, for downstream connections that are slow
to write, data will still accumulate in RAM without control. On the
other hand, the ngx_lua sample given above does not suffer from this
issue.

I have few questions or to be more precise I did not understood how the
output from drizzle is being streamed to the client.

  1. In ngx_http_drizzle_output.c the function ngx_http_drizzle_submit_mem is
    the place where it is setting the output filter, Is it also sending the
    response i.e the stream to the client at this point, or it is some other
    function?

Nope. Sending output buffers to the output filter chain is done by the
ngx_http_drizzle_output_bufs function.

  1. What I need to do to send my video contents to the client, I followed the
    drizzle example but setting output and sending stream to the client, how I
    can achieve this. I have 1024B avaialble at one point and I want to send
    this to the client till the backend server has no stream to send and the
    client should be able to play the content.

Basically, you can call the ngx_http_output_filter function, just as
other nginx upstream modules.

  1. Is it possible to send the video stream to the client with the browser.

I do not quite follow this question.

Best regards,
-agentzh

Thanks agentzh for explaining so well.

When I am connected to the backend server I am getting buffer which I am
sending to the client like this:

ngx_int_t
ngx_http_ccn_send_output_bufs(ngx_http_request_t *r,
ngx_http_upstream_ccn_peer_data_t *dp, const unsigned char
*data,
size_t data_size)
{
ngx_http_upstream_t *u = r->upstream;
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;

   /* allocate a buffer for your response body */
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
     return NGX_HTTP_INTERNAL_SERVER_ERROR;
   }

/* attach this buffer to the buffer chain */
out.buf = b;
out.next = NULL;

/* adjust the pointers of the buffer */
b->pos = (u_char *) data;
b->last = b->pos + data_size - 1;
b->memory = 1;    /* this buffer is in memory */
b->last_buf = 1;  /* this is the last buffer in the buffer chain */


if ( ! u->header_sent ) {
  fprintf(stdout, "ngx_http_ccn_send_output_bufs u->header_sent\n");
    r->headers_out.status = NGX_HTTP_OK;

    /* set the Content-Type header */

    r->headers_out.content_type.data =
        (u_char *) "application/octet-stream";

    r->headers_out.content_type.len =
        sizeof("application/octet-stream") - 1;

    r->headers_out.content_type_len =
        sizeof("application/octet-stream") - 1;

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
      fprintf(stdout, "ngx_http_ccn_send_output_bufs header sent

error\n");
return rc;
}

    u->header_sent = 1;
    fprintf(stdout, "ngx_http_ccn_send_output_bufs

u->header_sent=%d\n",u->header_sent);
}

rc = ngx_http_output_filter(r, &out);

if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
    return rc;
    }

this function I am calling everytime I am receiving data (1024) from the
backend
when it is end of stream I am calling
ngx_http_finalize_request(r, rc);

but it is not working as expected which is like playing the video file
in
the browser

I didn’t follow the lua module yet, but will look into it

Is there anything I am doing wrong while setting the output buffer, do I
need to change this line b->last_buf = 1;
or something else.

Thanks,
Raul


View this message in context:
http://nginx.2469901.n2.nabble.com/Video-Streaming-using-non-http-backend-Ref-ngx-drizzle-tp7580235p7580247.html
Sent from the nginx mailing list archive at Nabble.com.

Hello!

On Tue, Jun 5, 2012 at 12:06 PM, sammy_raul [email protected]
wrote:

/* adjust the pointers of the buffer */
b->pos = (u_char ) data;
b->last = b->pos + data_size - 1;
b->memory = 1; /
this buffer is in memory /
b->last_buf = 1; /
this is the last buffer in the buffer chain */

Setting b->last_buf to 1 means the current buf is the last buf in the
whole response body stream in this context (actually it is the
indicator for the end of the output data stream). So you must not set
this for every single buf.

Also, you should never set this flag in case you’re in a subrequest or
things will break.

this function I am calling everytime I am receiving data (1024) from the
backend
when it is end of stream I am calling
ngx_http_finalize_request(r, rc);

Call ngx_http_send_header once and call ngx_http_output_filter
multiple times (as needed).

If you need strict non-buffered output behaivor, you have to wait
for the downstream to flush out all the data before continuing
reading data from upstream. You can check out how the
ngx_http_upstream (in non-buffered mode) and ngx_lua modules do this.

I didn’t follow the lua module yet, but will look into it

I strongly recommend it because it should save you a lot of time (I
guess) :slight_smile:

Is there anything I am doing wrong while setting the output buffer, do I
need to change this line b->last_buf = 1;
or something else.

See above.

Regards,
-agentzh

P.S. C programming is hard; let’s go scripting! :smiley:

Hello!

On Tue, Jun 12, 2012 at 3:01 PM, sammy_raul [email protected]
wrote:

2)Before sock:receive I need to decrypt the data before sending to the
client. I think I can decode in the print function in lua_output.c where I
receive the data from upstream. Is that correct.

You can just try doing encrypting and decrypting on the Lua level.
It’s a scripting language anyway and you’re free to use the classic
Lua/C API or LuaJIT FFI to extend your Lua script with C code if
desired.

It’s not recommended, however, to patch ngx_lua cosocket’s C
implementation directly.

Regards,
-agentzh

Hi,

I am trying to understand lua module.
Using the above script in the conf file I am able to connect to my
upstream.
I have few questions regarding the Lua module.

1)How I can send some data i.e I have to send a message to my backend
probably which is more than a simple string. I have to construct it and
encode it. Probably I need to add to the c function I can see
ngx_http_lua_socket_tcp_send is used to send data over Nginx Socket, but
I
could not figure out how I can modify this function and which buffers I
need
to put my own data.

2)Before sock:receive I need to decrypt the data before sending to the
client. I think I can decode in the print function in lua_output.c where
I
receive the data from upstream. Is that correct.

Thanks,
Raul

Raul


View this message in context:
http://nginx.2469901.n2.nabble.com/Video-Streaming-using-non-http-backend-Ref-ngx-drizzle-tp7580235p7580380.html
Sent from the nginx mailing list archive at Nabble.com.