Archive for February, 2013

Multiple locations for VOD in 0.9.8

Last week I’ve added support for multiple play locations in VOD engine. Until 0.9.8 play directive could only receive a single directory or http location to play from. Now it receives multiple locations. Playback is started from the first location where file is found.

application vod {
    # search in /var/videos; in case of failure search in /www
    play /var/videos /www;
}

application vod {
    # search in local directories; if not found go to remote server
    play /tmp/cache /var/videos http://example.com/videos;
}

Another new feature in 0.9.8 is play_local_path setting. This directive sets directory where remote files are copied after they are completely downloaded from http location. The setting is unset by default. This directory should be on the same device as play_temp_path setting which sets temporary location where remote files are downloaded. Default is /tmp.

With the new features it’s easy to set up local cache for remote files.

application cached_vod {
    # remote files are copied to /tmp/videos after download
    # and played later from local directory until deleted manually

    play_local_path /tmp/videos;
    play /tmp/videos http://video.example.com/videos;
}

4 Comments

Picture in picture

Following the previous post about logo this post describes in short how to make picture-in-picture (PIP) with ffmpeg and set up nginx-rtmp to work with that.

PIP can be done with the same overlay ffmpeg filter as before. This is nginx.conf example merging two incoming streams and producing picture-in-picture result.

application myapp {
    live on;
}

application big {
    live on;
    exec ffmpeg -i rtmp://localhost/big/$name -i rtmp://localhost/small/$name
         -filter_complex "[0][1]overlay=10:10" -f flv rtmp://localhost/myapp/$name;
}

application small {
    live on;
}

The incoming streams are published in big and small application. The result is published to myapp.

Publish Sintel to big.

 ffmpeg -re -i /var/video/sintel.mp4 -c:v flv -s 800x600 -c:a libfaac -ar 22050 -ac 1
        -f flv rtmp://localhost/big/mystream

Then publish Elephants dream to small.

ffmpeg -re -i /var/video/ed.avi -c:v flv -s 400x200 -c:a libfaac -ar 22050 -ac 1
       -f flv rtmp://localhost/small/mystream

Here's the result.
pip

Note the result will not be available if one of incoming streams in unavailable.

Leave a comment

Placing logo on video

It’s really great to be able to add logo on your video. Here’s a simple guide how to do that with ffmpeg and set up nginx-rtmp to add logo automatically.

Here’s a simple mychan.png logo with transparent background made in GIMP.
mychan

What we want is to add logo on video that goes through nginx-rtmp. That can be done with the following ffmpeg overlay filter.

movie=/var/pictures/mychan.png[logo];[0][logo]overlay=0:70

Let's create a new application addlogo and add ffmpeg exec line to it. The result is published to myapp.

application myapp {
    live on;
}

application addlogo{
    live on;
    exec ffmpeg -i rtmp://localhost/addlogo/$name 
         -vf "movie=/var/pictures/mychan.png[logo];[0][logo]overlay=0:70" 
         -c:v flv -f flv rtmp://localhost/myapp/$name;
}

Now start streaming sintel.

ffmpeg -re -i /var/video/sintel.mp4 -c:v flv -s 800x600 -c:a libfaac -ar 44100 -ac 1
       -f flv rtmp://localhost/addlogo/mystream

Here's the result.
logo_on_stream

5 Comments

Proper video-only playback and new defaults in 0.9.7

There have been problems with playing video-only (no audio) streams. With wait_key setting disabled several flash players used to wait forever when playing such stream. With the setting enabled it’s much better but still it hangs sometimes. Now an empty audio frame is sent with the first video frame and that completely fixes the problem. That behavior is enabled with wait_video on directive. It’s optional since it’s not needed for audio-only streams.

All the above is true for flash clients only. Ffmpeg-family tools treat such streams in a completely different way. They wait for both (audio and video) streams to appear in RTMP stream until probesize bytes pass through. That setting can (and should) be reduced in real life.

Moreover since 0.9.7 version of nginx-rtmp-module new default values are set for several options:

  • wait_key is now ON by default. That’s the most reasonable setting for most cases.
  • play_restart is now OFF by default. Several flash players stop streaming on NetStream.Play.Stop and do not resume it later on NetStream.Play.Start which is not what expected.

Leave a comment

On_connect and on_disconnect in 0.9.6

Two new HTTP notifications were added in version 0.9.6 of nginx-rtmp-module: on_connect and on_disconnect.

The first one is called when client issues connect command. It receives all arguments coming with that command, namely app, flashver, swfurl, tcurl, pageurl, addr. In addition to that on_connect receives connection arguments which have never been available in previous versions if nginx-rtmp. Any HTTP result code different from 2xx is considered an error and client connection is closed. This notification can be used for user authorization.

Here’s an example of passing connection argument with JWPlayer.

jwplayer("container").setup({
  modes: [
     {   type: "flash",
         src: "/jwplayer/player.swf",
         config: {
              bufferlength: 1,
              file: "mystream",
              streamer: "rtmp://localhost/myapp?arg1=v1&arg2=v2",
              provider: "rtmp",
              autostart: "1"
         }
     }
  ]
});


Several Flash players can only pass connection arguments to server and never pass play/publish arguments. OSMF passes the same arguments to all calls.

The second notification on_disconnect is called when the connection is closed. It receives exactly the same set of arguments as on_connect. Note however on_dicsonnect is called on every disconnect event whether connect command was issued or not. The result code of this callback is not analyzed.

Both new callbacks should be added to server{} scope of nginx.conf and never to application{} scope. That’s because client is still not connected to any application at the moment of on_connect and might have no application at the moment of on_disconnect. HTTP method is tuned with the previously introduced notify_method directive.

rtmp {
    server {
        listen 1935;
        notify_method get;

        on_connect http://localhost:8080/on_connect;
        on_disconnect http://localhost:8080/on_disconnect;

        application myapp {
            live on;
        }
    }
}

Leave a comment

New static features in 0.9.5

Two new great features were merged into nginx-rtmp master on the weekend. The first is formerly announced static pull and the second is static exec.

Static pulls are pulls started at nginx startup. This makes it possible to generate HLS files without any dependence on rtmp clients currently playing the stream.

pull rtmp://remote.example.com/app/stream name=localstream static;

Static exec is a similar feature for running external programs at nginx startup. With this feature you can start streaming from an external source with ffmpeg.

exec_static ffmpeg -re -i /var/movies/movie.avi -c:v libx264 
            -c:a libmp3lame -ar 22050 -ac 1 -f flv rtmp://localhost/myapp/mystream;

The greatest thing that comes with static execs is the ability to receive data from webcam without running external scripts. Now it can all be done in nginx.conf.

exec_static ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264
            -an -f flv rtmp://localhost/myapp/mystream

The same applies to receiving stream from any remote source in any formats and codecs.

exec_static ffmpeg -i http://video.example.com/livechannel.ts -c copy
            -f flv rtmp://localhost/myapp/mystream

While static exec feature works perfectly on Linux it has certain limitations on FreeBSD. Because of missing prctl syscall or any substitution there’s no simple way to make child process terminated automatically when parent gets killed. When a single nginx worker in multi-worker configuration is killed on FreeBSD it’s still possible that a new exec child will be started even if the previously started child is still alive. If you use that on FreeBSD make sure you never kill a single nginx worker and always kill all.

Leave a comment