Stream Input Handler
SIH plugin Specification (Version 3)

Changes

This document describes the SIH plugin API Version 4, used in mtvp-sdk version 1.1.1.0 and later. Check the version that you use (macro MTVP_SIH_VERSION in sih_api.h).

The changes from the previous SIH plugin API (Version 3) are minorand mostly cosmetic:

Overview

A SIH plugin is a dynamic library that the application can dynamically link to mtvp to add support to a new stream input type or protocol. An SIH plugin defines the set of routines that mtvp uses internally to open, read, seek and close a particular type of input stream.

A SIH plugin is attached using the MTVP_COMMAND_SIH_LINK command. It is possible to link several SIH plugins.

SIH plugins may be very useful if you want to play MPEG streams from an input that is not handled by default. The application could of course read the data a separate process and pipe the data into the the standard input player, but this involves several buffer copies and makes the stream always non-seekable. Using an SIH plugin is much more efficient and allows seeking (when possible).

SIH Plugin API

An SIH plugin is a dynamic library (.so or .dll file) that defines the following symbol:
    int SIH_register(MTVP_SIH_EXPOSED *sih_exposed, int version);
SIH_register is called by the Player to register the SIH plugin. SIH_register should initialize the SIH_EXPOSED structure with the adresses of the various routines of the SIH plugin. It should be defined as:
int SIH_register(MTVP_SIH_EXPOSED *sih_exposed, int version)
{
    if (version == MTVP_SIH_VERSION) {
        sih_exposed->SIH_version        = MTVP_SIH_VERSION;
        sih_exposed->SIH_init           = SIH_init;
        sih_exposed->SIH_free           = SIH_free;
        sih_exposed->SIH_probe_url      = SIH_probe_url;
        sih_exposed->SIH_open_url       = SIH_open_url;
        sih_exposed->SIH_close          = SIH_close;
        sih_exposed->SIH_read           = SIH_read;
        sih_exposed->SIH_seek           = SIH_seek;
        sih_exposed->SIH_cntl           = SIH_cntl;
        sih_exposed->SIH_fd             = SIH_fd;
        sih_exposed->SIH_size           = SIH_size;
        sih_exposed->SIH_buffer         = SIH_buffer;
        sih_exposed->SIH_notify_free    = SIH_notify_free;
        sih_exposed->SIH_notify_rate    = SIH_notify_rate;
    }
    return MTVP_SIH_VERSION;
}
The SIH plugin should define the following static routines:
    static int SIH_probe_url(const MTVP_SIH_RESOURCES *resources, const char *url);
    static int SIH_init(const MTVP_SIH_RESOURCES *resources,
                        const char *p,
                        struct mtvp_sih_handler_data **result_handler_data_ptr);
    static void SIH_free(struct mtvp_sih_handler_data *handler_data);
    static int SIH_open_url(struct mtvp_sih_handler_data *handler_data,
                            const char *url,
                            struct mtvp_sih_stream_data **result_stream_data_ptr);
    static void SIH_close(struct mtvp_sih_stream_data *stream_data);
    static int SIH_fd(struct mtvp_sih_stream_data *stream_data,
                      void **result_fd_ptr);
    static int SIH_read(struct mtvp_sih_stream_data *stream_data,
                        char *buf,
                        size_t count,
                        size_t *result_count_read);
[*] static int SIH_seek(struct mtvp_sih_stream_data *stream_data,
                        off_t offset);
[*] static int SIH_cntl(struct mtvp_sih_handler_data *handler_data,
                        const MTVP_SIH_CNTL *data,
                        u_int size);
[*] static int SIH_size(struct mtvp_sih_stream_data *stream_data,
                        off_t *result_size_ptr);
[*] static int SIH_buffer(struct mtvp_sih_stream_data *stream_data,
                          MTVP_SIB_IPL_SIZES *sizes);
[*] statis int SIH_notify_free(struct mtvp_sih_stream_data *stream_data, 
                               u_int number_of_free_buffers);
[*] statis int SIH_notify_rate(struct mtvp_sih_stream_data *stream_data,
                               double playback_rate);

[*] means that the routine is optional and can be set to NULL by SIH_register.

Re-entrancy

An SIH plugin code must be fully reentrant, i.e. it should not have ANY global or static variables. SIH plugins should be compiled with the -DREENTRANT compiler flag.

Any "global" variable should be implemented as an element of the mtvp_sih_handler_data structure dynamically allocated and returned by SIH_init.

Returned value and error

Unless otherwise specified, each routine returns 0 when successful, and a non-zero error status in case of error.

Description of the SIH routines

static int SIH_probe_url(const MTVP_SIH_RESOURCES *sih_resources,
                         const char *url)

Probe a URL.

This routine is called to ask the SIH plugin if it can handle the specified URL. Note that this routine may be called before SIH_init, i.e. before the SIH plugin has been initialized.

static int SIH_init(const MTVP_SIH_RESOURCES *sih_resources,
                    const char *p,
                    struct mtvp_sih_handler_data **result_handler_data_ptr)

Instanciate and initialize the SIH plugin.

This routine instanciates the SIH plugin i.e. allocates a mtvp_sih_handler_data structure for storing its "global" variables used by the plugin, initializes this structure and returns a pointer to this structure in *result_handler_data_ptr. The mtvp_sih_handler_data structure, defined and known only by the SIH plugin, should contain at least the sih_resources pointer passed to SIH_init:

/* handler data */
typedef struct mtvp_sih_handler_data {
    const MTVP_SIH_RESOURCES *sih_resources;
    ... anything you want ...
};
You can initialize the SIH plugin by sending a MTVP_COMMAND_SIH_INIT command.

The parameter of MTVP_COMMAND_SIH_INIT must be formed of an SIH handler-id (int32) identifying the SIH plugin, immediately followed by an arbitrary string. A pointer to this string will be passed to SIH_init as its second parameter.

If you do not send a MTVP_COMMAND_SIH_INIT, SIH_init will be called automatically before the handler opens its first URL, and in that case the second parameter passed to SIH_init will that URL.

In all the following routines, the struct mtvp_sih_handler_data *handler_data parameter is the pointer to the mtvp_sih_handler_data structure that was allocated and initialized by SIH_init.

static void SIH_free(struct mtvp_sih_handler_data *handler_data)

Delete the SIH plugin instance.

The routine can be called only when the SIH plugin has no opened streams.

SIH_free should release any resources allocated by SIH_init and free the mtvp_sih_handler_data structure that was allocated by SIH_init.

After a call to SIH_free, the struct mtvp_sih_handler_data *handler_data pointer should be considered invalid.

SIH_free is called automatically before the player quits, but it can also be called explicitely by sending a MTVP_COMMAND_SIH_FREE command, with a handler-id (int32) as parameter to identify the SIH handler.

static int SIH_open_url(struct mtvp_sih_handler_data *handler_data,
                        const char *url,
                        struct mtvp_sih_stream_data **result_stream_data_ptr)

Open a URL.

SIH_open_url allocates a mtvp_sih_stream_data structure to store all the resources associated with the stream corresponding to the specified URL. It should initialize this structure and return a pointer to it in *result_stream_data_ptr. The mtvp_sih_stream_data structure, defined and known only by the SIH plugin, should contain at least the handler_data pointer:

/* stream data */
typedef struct mtvp_sih_stream_data {
    struct mtvp_sih_handler_data *handler_data;    /* should always be there */
    ...
};
If the specified URL cannot be opened, SIH_open returns a non-zero error status.

In all the following routines, the struct mtvp_sih_stream_data *stream_data parameter is the pointer to the mtvp_sih_stream_data structure that was allocated by SIH_open.

static int SIH_fd(struct mtvp_sih_stream_data *stream_data, void **result_fd_ptr)

Unix: Get file descriptor associated with specified input stream.

SIH_fd must return a file descriptor in *result_fd_ptr. The Player will use this file descriptor to determine if there is some input stream data available for reading. The Player calls select() to determine if there is data available on this file descriptor and if that is the case, it calls SIH_read (provided that there is buffer space available to read some stream input data).

The file descriptor returned by SIH_fd does not have to be the actual fd used by SIH_read to read the stream. It may be one end of a control pipe.

Windows: Get the HANDLE of an Event associated with specified stream.

SIH_fd must return an Event HANDLE in *result_fd_ptr. The Player uses the status of this Event to determine if there is some input stream data available for reading. If the Event is "set", it calls SIH_read (provided that there is buffer space available to read some input data).

SIH_fd is called immediately after each (successful) call to SIH_seek, and it a call to SIH_seek may change the fd or Event returned by SIH_fd.

SIH_fd should always return 0.


static int SIH_read(struct mtvp_sih_stream_data *stream_data, 
                    char *buf,
                    size_t count,
                    size_t *result_count_read)

Read stream data.

SIH_read is normally called when data is available for reading. However, it is possible that SIH_read be called if there is no data to be read. If there is no data immediately available, SIH_read should return MTVP_SIH_READ_ERROR_TRY_AGAIN.

SIH_read must always behave like a non-blocking read. This means that SIH_read should never block, even if there is less than count bytes of stream data immediately available (or no data available at all, for some reason).

If there is less data available than count bytes, SIH_read should copy all the data available into the buffer buf and return the number of bytes copied in *result_count_read, which should be > 0 and <= count.

If EOF is reached, SIH_read should set *result_count_read to 0.

If count is less than the size of the individual stream buffers, SIH_read can return MTVP_SIH_READ_ERROR_TOO_SMALL. In this case, the next call to SIH_read will have a count parameter equal to the size of the individual stream buffers (which is by default 4K and can be set using SIH_buffer or env variable MTVP_SYS_READ_CHUNK_SIZE).

All read errors (except MTVP_SIH_READ_ERROR_TRY_AGAIN and MTVP_SIH_READ_ERROR_TOO_SMALL) will be treated as EOF.

IMPORTANT: SIH_read should NEVER block. If there is no data immediately available, SIH_read should return MTVP_SIH_READ_ERROR_TRY_AGAIN.

static int SIH_seek(struct mtvp_sih_stream_data *stream_data,
                    off_t offset)

Seek in stream.

The SIH_seek function repositions the stream "read" pointer to the argument offset (number of bytes past the start os the stream). SIH_seek should return ESPIPE (regardless of the offset) if the stream does not support seeking.

If SIH_seek is set to NULL by SIH_register, it is assumed that the stream does not support seeking.

static int SIH_size(struct mtvp_sih_stream_data *stream_data, off_t *result_size_ptr)

Get stream size, in byte.

SIH_size sets the size of the stream, in bytes, in *result_size_ptr and returns 0;

If the stream size is unknown, SIH_size should return a non-zero error status.

If SIH_seek is defined, SIH_size must not be set to NULL.

Note: It is possible to have streams that support SIH_size (i.e. size of stream is known), but yet do not support seeking (SIH_seek set to NULL).

static void SIH_close(struct mtvp_sih_stream_data *stream_data)

Close specified stream.

This routine must release every resource allocated by SIH_open and free the mtvp_sih_stream_data structure. All the resources allocated for the specified stream should be released.

After a call to SIH_close, that struct mtvp_sih_stream_data *stream_data pointer should be considered invalid.

static int SIH_cntl(struct mtvp_sih_handler_data *handler_data,
                    const MTVP_SIH_CNTL *data,
                    u_int size)

Handle private messages from application.

SIH_cntl is called when the application sends the command MTVP_COMMAND_SIH_CNTL. The SIH plugin must be already initialized.

Note that size is always <= sizeof(MTVP_PMP_DATA_GENERIC), as defined in pmp.h, i.e. <= 1024 bytes.

To call SIH_cntl, the application must send a MTVP_COMMAND_SIH_CNTL command with a parameter being this same buffer (data), containing the SIH handler-id identifying the SIH plugin (SIH handler-id is an int32) immediately followed by an arbitrary chunk of data.

If SIH_cntl is set to NULL by SIH_register, MTVP_COMMAND_SIH_CNTL commands will do nothing and cause the player to send an error notification.

static void SIH_buffer(struct mtvp_sih_stream_data *stream_data,
                       MTVP_SIB_IPL_SIZES *sizes)

Set buffer specification.

If SIH_buffer is defined, it is called after SIH_open_url (and before the first call to SIH_read). SIH_buffer must initialize the MTVP_SIB_IPL_SIZES structure. The values in the MTVP_SIB_IPL_SIZES structure are used to allocate the buffer pool.

If SIH_buffer is set to NULL by SIH_register, the default buffer specification is used.

You should probably not define SIH_buffer unless you have a very good reason for not using the default buffer specification.

Linking an SIH plugin

Sending a MTVP_COMMAND_SIH_LINK command causes the player to link an SIH plugin. The application can link several SIH plugins at the same time.

The parameter of MTVP_COMMAND_SIH_LINK is the full pathname of the SIH plugin (.so file).

Getting the handler_id of an SIH plugin

If you want to communicate with a particular handler (built-in or plugin), using the commands MTVP_COMMAND_SIH_INIT, MTVP_COMMAND_SIH_CNTL, MTVP_NOTIFY_SIH_FEEDBACK or MTVP_COMMAND_SIH_FREE, you need to know the handler_id which is an integer identifying the handler.

The built-in SIH handlers have the following ids:

MTVP_SIH_HANDLER_ID_HTTP_FTP  for the HTTP and FTP handler.
MTVP_SIH_HANDLER_ID_PORT      for the raw TCP/UDP handler.
MTVP_SIH_HANDLER_ID_VCD       for the Video-CD handler.
MTVP_SIH_HANDLER_ID_FD        for the FD (unix file descriptor) handler.
MTVP_SIH_HANDLER_ID_FILE      for the FILE handler.
To get the handler_id of an SIH plugin, you should ask for the return status notification of the MTVP_COMMAND_SIH_LINK command.

If the status indicates that no error occured (i.e. if you get a notification of type MTVP_NOTIFY_RETURN_SUCCESS in return), the handler_id is passed back in the data.data_return_success.value of the MTVP_NOTIFY_RETURN_SUCCESS notification.

To get the return status of a command, the application must pass the MTVP_NOTIFY_RETURN_FAILURE flag when sending the command. Note that passing also the flag MTVP_PMP_FLAG_RETURN_ORIGINAL causes the original command to be copied right after the return status, which is can be used to identify the source of a return status notification.

Initializing an SIH plugin

You can initialize the SIH plugin by sending a MTVP_COMMAND_SIH_INIT command.

If you do not send a MTVP_COMMAND_SIH_INIT, SIH_init will be called automatically before the SIH handler opens its first URL, and in that case the second parameter passed to SIH_init will that URL.

The parameter of MTVP_COMMAND_SIH_INIT must be formed of an SIH handler-id (int32) identifying the SIH plugin, immediately followed by an arbitrary string. A pointer to this string will be passed to SIH_init as its second parameter.

De-initializing an SIH plugin

You can de-initialize the SIH plugin by sending a MTVP_COMMAND_SIH_FREE command. It will cause SIH_free to be called.

Opening a stream with an SIH plugin

The MTVP_COMMAND_OPEN_STREAM_URL command causes the Player to open a stream using the first SIH handler (built-in or plugin) that recognizes the URL (i.e. with SIH_probe_URL returning 0). The plugins are probed before the built-in handlers.

The parameter of MTVP_COMMAND_OPEN_STREAM_URL is a URL (string).

If the stream can be opened successfully, any previously opened stream is automatically closed.

Closing a stream opened by an SIH plugin

The MTVP_COMMAND_CLOSE_STREAM command causes the Player to close the current stream.

The MTVP_COMMAND_OPEN_STREAM_URL command causes the Player to open a new stream. If the new stream can be opened successfully, any previously opened stream is automatically closed.

Sending a private message to an SIH plugin

The MTVP_COMMAND_SIH_CNTL command causes the SIH routine SIH_cntl of the specified SIH plaugin to be called with the specified parameter.

The parameter of MTVP_COMMAND_SIH_CNTL is a pointer to a buffer containing an SIH handler-id (int32) identifying the SIH plugin followed by an arbitrary chunk of data.

Note: The size of the buffer must be >= 4 and <= sizeof(MTVP_PMP_DATA_GENERIC), as defined in pmp.h, i.e. <= 1024 bytes. If size is larger than the maximum value authorized, then the command will cause an error notification with error status EINVAL. size is always >= 4, because the buffer always contains the SIH handler-id, which is a 4-byte integer.

Sending a private message from an SIH plugin to the application

Any of the routines in an SIH plugin (except SIH_register) can send arbitrary feedback data to the application by calling:
int (*sih_resources->feedback)(
    const MTVP_SIH_RESOURCES *sih_resources,
    const void *data,
    u_int size
);
Note: size must be <= sizeof(MTVP_PMP_DATA_GENERIC) - 4, as defined in pmp.h, i.e. <= 1020 bytes. If size is larger than the maximum value authorized, sih_resources->feedback returns a non-zero error status.

Calling sih_resources->feedback causes the application to receive a MTVP_NOTIFY_SIH_FEEDBACK notification with the data block specified by the data and size parameters.

The protocol used to communicate between the application and an SIH plugin using MTVP_COMMAND_SIH_CNTL / SIH_cntl() and sih_resources->feedback() / MTVP_NOTIFY_SIH_FEEDBACK must be agreed privately between the application and the SIH plugin.

Compiling an SIH plugin

You can look at the example of SIH plugin provided with mtvp-sdk. SIH plugins should be compiled as dynamic (shared) libraries.

Important: You should ALWAYS compile SIH plugin as reentrant code. Under Unix, you should define the _REENTRANT macro in the compiler line (i.e. use the compilation flag -D_REENTRANT).

Testing the SIH plugin API

To test the SIH plugin API you can use sample_sih.so which is functionally equivalent to the built-in FILE handler (i.e. it recognizes URL of the form "file:filename").

You can use the sample application simple_player as a test program to test this SIH handler.

If you define the macro TEST_SIH (in simple_player.c) to be the pathname of the sample SIH plugin (sample_sih.so), simple_player will link the sample SIH plugin and use it (instead of the buil-in handler) to access input files.

The routines in sample_sih.so print many messages so that you see what is happening.

You can use sample_sih.c as a template to develop your own SIH plugin.