neuray API Programmer's Manual

RTMP server

[Neuray API]

Description

The RTMP server module implements an RTMP server. It listens for incoming connections and calls the installed connect handlers to see if an incoming connection should be accepted. If it is accepted an RTMP connection is started and upon incoming RTMP commands the installed command handlers will be called.

The server is multithreaded and will start one thread for each connection.

Any number of connect handler classes may be installed to the RTMP server. Each of those handler classes has to implement a handle() function. This function gets the connection. From the connection the handle() function may get the various parameters of the connect packet and if it wants to claim it, it should return true. If all return false, the connection is refused.

To create a server the mi::rtmp::IFactory needs to be obtained from the neuray API using mi::neuraylib::INeuray::get_api_component(). The factory can then be used to create as many RTMP servers as needed.

The handler classes are the only ones that need to be implemented by a user. And then only the ones where the user actually wants to do something. If not implemented, they will simply not be called. The Frame_event_handler runs in a separate thread to avoid that long rendering times affect the framerate.

An example:

‎    void render_a_canvas_and_save() {  ... your code ... }
    mi::neuraylib::ICanvas* get_the_last_rendered_canvas() { ... your code ... }

    // The render loop
    class My_render_handler : public mi::Interface_implement<mi::rtmp::IRender_event_handler>
    {
    public:
        bool handle( mi::rtmp::IStream* stream)
        {
            render_a_canvas_and_save();
            return true;
         }
    };

    // The Frame loop, the actual handler where encoded video data is collected. Note that
    // it runs in another thread than the Render_event_handler which means the canvas accesses
    // need to be synchronized.
    class My_frame_handler : public mi::Interface_implement<mi::rtmp::IFrame_event_handler>
    {
    public:
        bool handle(
            mi::rtmp::IStream* stream, mi::neuraylib::IVideo_data** out, bool outqueue_is_full)
        {
            if (outqueue_is_full) // not an error, just no use in encoding a new frame
                return true;
            mi::base::Handle< mi::neuraylib::ICanvas> canvas( get_the_last_rendered_canvas());
            mi::base::Handle< mi::neuraylib::IVideo_encoder> codec( stream->get_video_codec());
            return codec->encode_canvas( canvas.get(), out) == 0;
        }
    };

    // Stream handler
    class My_stream_handler : public mi::Interface_implement<mi::rtmp::IStream_event_handler>
    {
    public:
        bool handle(
            bool is_create,
            mi::rtmp::IStream* stream,
            const mi::IData* command_arguments)
        {
            if( is_create) {
                mi::base::Handle< mi::rtmp::IRender_event_handler> render_event_handler(
                    new My_render_handler());
                stream->register_render_event_handler( render_event_handler.get());
                mi::base::Handle< mi::rtmp::IFrame_event_handler> frame_event_handler(
                    new My_frame_handler());
                stream->register_frame_event_handler( frame_event_handler.get());
            }
            return true;
        }
    };

    // Connect handler
    class My_connect_handler : public mi::Interface_implement<mi::rtmp::IConnect_event_handler>
    {
    public:
        bool handle(
            bool is_create,
            mi::rtmp::IConnection* connection,
            const mi::IData* cmd_arguments,
            const mi::IData* user_arguments)
        {
            if( is_create) {
                mi::base::Handle< mi::rtmp::IStream_event_handler> stream_event_handler(
                    new My_stream_handler());
                connection->register_stream_event_handler( stream_event_handler.get());
            }
            return true;
        }
    };

    mi::base::Handle< mi::rtmp::IFactory> rtmp_factory(
        neuray->get_api_component<mi::rtmp::IFactory>());
    mi::base::Handle< mi::rtmp::IServer>  rtmp_server( rtmp_factory->create_server());
    mi::base::Handle< mi::rtmp::IConnect_event_handler> connect_handler( new My_connect_handler());
    rtmp_server->install( connect_handler.get());
    rtmp_server->start( "0.0.0.0:1935");

Note:

Some concepts might be easier to understand if having read the Adobe RTMP specification [RTMPSPEC10]

Classes

class 
Superclass of all handlers of call events. More...
class 
Superclass of all handlers of connect events. More...
class 
The connection class represents a connection from a client to the server. More...
class 
The factory can be used to instantiate the built-in RTMP server. More...
class 
Superclass of all handlers of frame events. More...
class 
Superclass of all handlers of pause events. More...
class 
Superclass of all handlers of play events. More...
class 
Superclass of all handlers of render events. More...
class 
The server builds a framework for the handlers. More...
class 
Representing an RTMP stream. More...
class 
Superclass of all handlers of create stream events. More...