root/modules/dummy_in/dummy_in.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. DC_GetChannel
  2. DC_RemoveChannel
  3. DC_RegisterMimeTypes
  4. DC_CanHandleURL
  5. DC_NetIO
  6. DC_DownloadFile
  7. DC_ConnectService
  8. DC_CloseService
  9. DC_GetServiceDesc
  10. DC_ServiceCommand
  11. DC_ConnectChannel
  12. DC_DisconnectChannel
  13. DC_ChannelGetSLP
  14. DC_ChannelReleaseSLP
  15. DC_CanHandleURLInService
  16. QueryInterfaces
  17. LoadInterface
  18. ShutdownInterface

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / Dummy input module
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#include <gpac/modules/service.h>
/*for GF_STREAM_PRIVATE_SCENE definition*/
#include <gpac/constants.h>
#include <gpac/download.h>
#include <gpac/xml.h>

typedef struct
{
        u32 ESID;
        LPNETCHANNEL ch;
        u32 start, end;
} DummyChannel;

typedef struct
{
        /*the service we're responsible for*/
        GF_ClientService *service;
        char *url;
        u32 oti;
        Bool is_views_url;
        GF_List *channels;

        /*file downloader*/
        GF_DownloadSession * dnload;
        Bool is_service_connected;
} DCReader;

DummyChannel *DC_GetChannel(DCReader *read, LPNETCHANNEL ch)
{
        DummyChannel *dc;
        u32 i=0;
        while ((dc = (DummyChannel *)gf_list_enum(read->channels, &i))) {
                if (dc->ch && dc->ch==ch) return dc;
        }
        return NULL;
}

Bool DC_RemoveChannel(DCReader *read, LPNETCHANNEL ch)
{
        DummyChannel *dc;
        u32 i=0;
        while ((dc = (DummyChannel *)gf_list_enum(read->channels, &i))) {
                if (dc->ch && dc->ch==ch) {
                        gf_list_rem(read->channels, i-1);
                        gf_free(dc);
                        return GF_TRUE;
                }
        }
        return GF_FALSE;
}

static const char * DC_MIME_TYPES[] = {
        /*  "application/x-xmta", "xmta xmta.gz xmtaz", "MPEG-4 Text (XMT)" */
        "application/x-bt", "bt bt.gz btz", "MPEG-4 Text (BT)",
        "application/x-xmt", "xmt xmt.gz xmtz", "MPEG-4 Text (XMT)",
        "model/vrml", "wrl wrl.gz", "VRML World",
        "x-model/x-vrml", "wrl wrl.gz", "VRML World",
        "model/x3d+vrml", "x3dv x3dv.gz x3dvz", "X3D/VRML World",
        "model/x3d+xml", "x3d x3d.gz x3dz", "X3D/XML World",
        "application/x-shockwave-flash", "swf", "Macromedia Flash Movie",
        "image/svg+xml", "svg svg.gz svgz", "SVG Document",
        "image/x-svgm", "svgm", "SVGM Document",
        "application/x-LASeR+xml", "xsr", "LASeR Document",
        "application/widget", "wgt", "W3C Widget Package",
        "application/x-mpegu-widget", "mgt", "MPEG-U Widget Package",
        NULL
};


static u32 DC_RegisterMimeTypes(const GF_InputService *plug) {
        u32 i;
        if (!plug)
                return 0;
        for (i = 0 ; DC_MIME_TYPES[i] ; i+=3)
                gf_service_register_mime(plug, DC_MIME_TYPES[i], DC_MIME_TYPES[i+1], DC_MIME_TYPES[i+2]);
        return i / 3;
}

Bool DC_CanHandleURL(GF_InputService *plug, const char *url)
{
        char *sExt;
        if (!plug || !url)
                return GF_FALSE;
        sExt = strrchr(url, '.');
        if (sExt) {
                Bool ok = GF_FALSE;
                char *cgi_par;
                if (!strnicmp(sExt, ".gz", 3)) sExt = strrchr(sExt, '.');
                if (!strnicmp(url, "rtsp://", 7)) return GF_FALSE;

                cgi_par = strchr(sExt, '?');
                if (cgi_par) cgi_par[0] = 0;
                {
                        u32 i;
                        for (i = 0 ; DC_MIME_TYPES[i] ; i+=3)
                                if (0 != (ok = gf_service_check_mime_register(plug, DC_MIME_TYPES[i], DC_MIME_TYPES[i+1], DC_MIME_TYPES[i+2], sExt)))
                                        break;
                }
                if (cgi_par) cgi_par[0] = '?';
                if (ok) return GF_TRUE;
        }
        /*views:// internal URI*/
        if (!strnicmp(url, "views://", 8))
                return GF_TRUE;

        if (!strncmp(url, "\\\\", 2)) return GF_FALSE;

        if (!strnicmp(url, "file://", 7) || !strstr(url, "://")) {
                char *rtype = gf_xml_get_root_type(url, NULL);
                if (rtype) {
                        Bool handled = GF_FALSE;
                        if (!strcmp(rtype, "SAFSession")) handled = GF_TRUE;
                        else if (!strcmp(rtype, "XMT-A")) handled = GF_TRUE;
                        else if (!strcmp(rtype, "X3D")) handled = GF_TRUE;
                        else if (!strcmp(rtype, "svg")) handled = GF_TRUE;
                        else if (!strcmp(rtype, "bindings")) handled = GF_TRUE;
                        else if (!strcmp(rtype, "widget")) handled = GF_TRUE;
                        gf_free(rtype);
                        return handled;
                }
        }
        return GF_FALSE;
}

void DC_NetIO(void *cbk, GF_NETIO_Parameter *param)
{
        GF_Err e;
        DCReader *read = (DCReader *) cbk;

        /*handle service message*/
        gf_service_download_update_stats(read->dnload);

        e = param->error;

        if (param->msg_type==GF_NETIO_DATA_TRANSFERED) {
        } else if (param->msg_type==GF_NETIO_PARSE_HEADER) {
                if (!strcmp(param->name, "Content-Type")) {
                        if (strstr(param->value, "application/x-bt")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        if (strstr(param->value, "application/x-xmt")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        if (strstr(param->value, "model/vrml")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        if (strstr(param->value, "model/x3d+vrml")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        if (strstr(param->value, "application/x-shockwave-flash")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        if (strstr(param->value, "image/svg+xml")) read->oti = GPAC_OTI_PRIVATE_SCENE_SVG;
                        if (strstr(param->value, "image/x-svgm")) read->oti = GPAC_OTI_PRIVATE_SCENE_SVG;
                        if (strstr(param->value, "application/x-LASeR+xml")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        if (strstr(param->value, "application/widget")) read->oti = GPAC_OTI_PRIVATE_SCENE_WGT;
                        if (strstr(param->value, "application/x-mpegu-widget")) read->oti = GPAC_OTI_PRIVATE_SCENE_WGT;
                }
                return;
        } else if (!e && (param->msg_type!=GF_NETIO_DATA_EXCHANGE)) return;

        if (!e && !read->oti)
                return;

        /*OK confirm*/
        if (!read->is_service_connected) {
                if (!gf_dm_sess_get_cache_name(read->dnload)) e = GF_IO_ERR;
                if (e>0) e = GF_OK;
                gf_service_connect_ack(read->service, NULL, e);
                read->is_service_connected = GF_TRUE;
        }
}

void DC_DownloadFile(GF_InputService *plug, char *url)
{
        DCReader *read = (DCReader *) plug->priv;

        read->dnload = gf_service_download_new(read->service, url, 0, DC_NetIO, read);
        if (!read->dnload) {
                gf_service_connect_ack(read->service, NULL, GF_NOT_SUPPORTED);
        } else {
                /*start our download (threaded)*/
                gf_dm_sess_process(read->dnload);
        }
}


GF_Err DC_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
{
        DCReader *read = (DCReader *) plug->priv;
        FILE *test;
        char *tmp, *ext;

        if (!read || !serv || !url) return GF_BAD_PARAM;

        if (read->dnload) gf_service_download_del(read->dnload);
        read->dnload = NULL;

        read->url = gf_strdup(url);
        ext = strchr(read->url, '#');
        if (ext) {
                char *anext;
                ext[0] = 0;
                anext = strrchr(read->url, '.');
                ext[0] = '#';
                ext = anext;
        } else {
                ext = strrchr(read->url, '.');
        }
        if (ext && !stricmp(ext, ".gz")) {
                char *anext;
                ext[0] = 0;
                anext = strrchr(read->url, '.');
                ext[0] = '.';
                ext = anext;
        }
        read->service = serv;

        if (!strnicmp(url, "views://", 8)) {
                read->is_views_url = GF_TRUE;
                gf_service_connect_ack(serv, NULL, GF_OK);
                read->is_service_connected = GF_TRUE;
                return GF_OK;
        }

        if (ext) {
                char *cgi_par = NULL;
                ext += 1;
                if (ext) {
                        tmp = strchr(ext, '#');
                        if (tmp) tmp[0] = 0;
                        /* Warning the '?' sign should not be present in local files but it is convenient to have it
                           to test web content locally */
                        cgi_par = strchr(ext, '?');
                        if (cgi_par) cgi_par[0] = 0;
                }
                if (!stricmp(ext, "bt") || !stricmp(ext, "btz") || !stricmp(ext, "bt.gz")
                        || !stricmp(ext, "xmta")
                        || !stricmp(ext, "xmt") || !stricmp(ext, "xmt.gz") || !stricmp(ext, "xmtz")
                        || !stricmp(ext, "wrl") || !stricmp(ext, "wrl.gz")
                        || !stricmp(ext, "x3d") || !stricmp(ext, "x3d.gz") || !stricmp(ext, "x3dz")
                        || !stricmp(ext, "x3dv") || !stricmp(ext, "x3dv.gz") || !stricmp(ext, "x3dvz")
                        || !stricmp(ext, "swf")
                   )
                        read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;

                else if (!stricmp(ext, "svg") || !stricmp(ext, "svgz") || !stricmp(ext, "svg.gz")) {
                        read->oti = GPAC_OTI_PRIVATE_SCENE_SVG;
                }
                /*XML LASeR*/
                else if (!stricmp(ext, "xsr"))
                        read->oti = GPAC_OTI_PRIVATE_SCENE_LASER;
                else if (!stricmp(ext, "xbl"))
                        read->oti = GPAC_OTI_PRIVATE_SCENE_XBL;
                else if (!stricmp(ext, "wgt") || !stricmp(ext, "mgt"))
                        read->oti = GPAC_OTI_PRIVATE_SCENE_WGT;

                if (cgi_par) cgi_par[0] = '?';
        }

        if (!read->oti && (!strnicmp(url, "file://", 7) || !strstr(url, "://"))) {
                char *rtype = gf_xml_get_root_type(url, NULL);
                if (rtype) {
                        if (!strcmp(rtype, "SAFSession")) read->oti = GPAC_OTI_PRIVATE_SCENE_LASER;
                        else if (!strcmp(rtype, "svg")) read->oti = GPAC_OTI_PRIVATE_SCENE_SVG;
                        else if (!strcmp(rtype, "XMT-A")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        else if (!strcmp(rtype, "X3D")) read->oti = GPAC_OTI_PRIVATE_SCENE_GENERIC;
                        else if (!strcmp(rtype, "bindings")) read->oti = GPAC_OTI_PRIVATE_SCENE_XBL;
                        else if (!strcmp(rtype, "widget")) read->oti = GPAC_OTI_PRIVATE_SCENE_WGT;
                        gf_free(rtype);
                }
        }

        /*remote fetch*/
        if (!strnicmp(url, "file://", 7)) {
        }
        else if (strstr(url, "://")) {
                DC_DownloadFile(plug, read->url);
                return GF_OK;
        }

        test = gf_fopen(read->url, "rt");
        if (!test) {
                gf_service_connect_ack(serv, NULL, GF_URL_ERROR);
                return GF_OK;
        }
        gf_fclose(test);
        if (!read->is_service_connected) {
                gf_service_connect_ack(serv, NULL, GF_OK);
                read->is_service_connected = GF_TRUE;
        }
        return GF_OK;
}

GF_Err DC_CloseService(GF_InputService *plug)
{
        DCReader *read = (DCReader *) plug->priv;
        if (read->dnload) gf_service_download_del(read->dnload);
        read->dnload = NULL;
        gf_service_disconnect_ack(read->service, NULL, GF_OK);
        return GF_OK;
}

/*Dummy input just send a file name, no multitrack to handle so we don't need to check sub_url nor expected type*/
static GF_Descriptor *DC_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url)
{
        u32 size = 0;
        char *uri;
        GF_ESD *esd;
        GF_BitStream *bs;
        DCReader *read = (DCReader *) plug->priv;
        GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *) gf_odf_desc_new(GF_ODF_IOD_TAG);
        iod->scene_profileAndLevel = 1;
        iod->graphics_profileAndLevel = 1;
        iod->OD_profileAndLevel = 1;
        iod->audio_profileAndLevel = 0xFE;
        iod->visual_profileAndLevel = 0xFE;
        iod->objectDescriptorID = 1;

        if (read->is_views_url) {
                iod->URLString = gf_strdup(read->url);
                return (GF_Descriptor *)iod;
        }

        esd = gf_odf_desc_esd_new(0);
        esd->slConfig->timestampResolution = 1000;
        esd->slConfig->useTimestampsFlag = 1;
        esd->ESID = 0xFFFE;
        esd->decoderConfig->streamType = GF_STREAM_PRIVATE_SCENE;
        esd->decoderConfig->objectTypeIndication = read->oti;
        if (read->dnload) {
                uri = (char *) gf_dm_sess_get_cache_name(read->dnload);
                gf_dm_sess_get_stats(read->dnload, NULL, NULL, &size, NULL, NULL, NULL);
        } else {
                FILE *f = gf_fopen(read->url, "rt");
                gf_fseek(f, 0, SEEK_END);
                size = (u32) gf_ftell(f);
                gf_fclose(f);
                uri = read->url;
        }
        bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
        gf_bs_write_u32(bs, size);
        gf_bs_write_data(bs, uri, (u32) strlen(uri));
        gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
        gf_bs_del(bs);

        gf_list_add(iod->ESDescriptors, esd);
        return (GF_Descriptor *)iod;
}


GF_Err DC_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
        DCReader *read = (DCReader *) plug->priv;
        DummyChannel *dc;

        if (!com->base.on_channel) return GF_NOT_SUPPORTED;

        dc = DC_GetChannel(read, com->base.on_channel);
        if (!dc) return GF_STREAM_NOT_FOUND;

        switch (com->command_type) {
        case GF_NET_CHAN_SET_PULL:
                return GF_OK;
        case GF_NET_CHAN_INTERACTIVE:
                return GF_OK;
        /*since data is file-based, no padding is needed (decoder plugin will handle it itself)*/
        case GF_NET_CHAN_SET_PADDING:
                return GF_OK;
        case GF_NET_CHAN_BUFFER:
                com->buffer.max = com->buffer.min = 0;
                return GF_OK;
        case GF_NET_CHAN_DURATION:
                /*this module is not made for updates, use undefined duration*/
                com->duration.duration = 0;
                return GF_OK;
        case GF_NET_CHAN_PLAY:
                dc->start = (u32) (1000 * com->play.start_range);
                dc->end = (u32) (1000 * com->play.end_range);
                return GF_OK;
        case GF_NET_CHAN_STOP:
                return GF_OK;
        case GF_NET_CHAN_CONFIG:
                return GF_OK;
        case GF_NET_CHAN_GET_DSI:
                com->get_dsi.dsi = NULL;
                com->get_dsi.dsi_len = 0;
                return GF_OK;
        default:
                break;
        }
        return GF_OK;
}

GF_Err DC_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
{
        u32 ESID;
        DCReader *read = (DCReader *) plug->priv;

        sscanf(url, "ES_ID=%ud", &ESID);
        if (!ESID) {
                gf_service_connect_ack(read->service, channel, GF_STREAM_NOT_FOUND);
        } else {
                DummyChannel *dc;
                GF_SAFEALLOC(dc, DummyChannel);
                if (!dc) return GF_OUT_OF_MEM;
                dc->ch = channel;
                dc->ESID = ESID;
                gf_list_add(read->channels, dc);
                gf_service_connect_ack(read->service, channel, GF_OK);
        }
        return GF_OK;
}

GF_Err DC_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
        Bool had_ch;
        DCReader *read = (DCReader *) plug->priv;

        had_ch = DC_RemoveChannel(read, channel);
        gf_service_disconnect_ack(read->service, channel, had_ch ? GF_OK : GF_STREAM_NOT_FOUND);
        return GF_OK;
}

GF_Err DC_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, char **out_data_ptr, u32 *out_data_size, GF_SLHeader *out_sl_hdr, Bool *sl_compressed, GF_Err *out_reception_status, Bool *is_new_data)
{
        DummyChannel *dc;
        DCReader *read = (DCReader *) plug->priv;
        dc = DC_GetChannel(read, channel);
        if (!dc) return GF_STREAM_NOT_FOUND;

        memset(out_sl_hdr, 0, sizeof(GF_SLHeader));
        out_sl_hdr->compositionTimeStampFlag = 1;
        out_sl_hdr->compositionTimeStamp = dc->start;
        out_sl_hdr->accessUnitStartFlag = 1;
        *sl_compressed = GF_FALSE;
        *out_reception_status = GF_OK;
        *is_new_data = GF_TRUE;
        return GF_OK;
}

GF_Err DC_ChannelReleaseSLP(GF_InputService *plug, LPNETCHANNEL channel)
{
        return GF_OK;
}

Bool DC_CanHandleURLInService(GF_InputService *plug, const char *url)
{
        return GF_FALSE;
}

GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
        static u32 si [] = {
                GF_NET_CLIENT_INTERFACE,
                0
        };
        return si;
}

GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
        DCReader *read;
        GF_InputService *plug;
        if (InterfaceType != GF_NET_CLIENT_INTERFACE) return NULL;

        GF_SAFEALLOC(plug, GF_InputService);
        if (!plug) return NULL;
        GF_SAFEALLOC(read, DCReader);
        if (!read) {
                gf_free(plug);
                return NULL;
        }
        read->channels = gf_list_new();
        plug->priv = read;

        GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "GPAC Dummy Loader", "gpac distribution")


        plug->RegisterMimeTypes = DC_RegisterMimeTypes;
        plug->CanHandleURL = DC_CanHandleURL;
        plug->ConnectService = DC_ConnectService;
        plug->CloseService = DC_CloseService;
        plug->GetServiceDescriptor = DC_GetServiceDesc;
        plug->ConnectChannel = DC_ConnectChannel;
        plug->DisconnectChannel = DC_DisconnectChannel;
        plug->ServiceCommand = DC_ServiceCommand;
        plug->CanHandleURLInService = DC_CanHandleURLInService;
        plug->ChannelGetSLP = DC_ChannelGetSLP;
        plug->ChannelReleaseSLP = DC_ChannelReleaseSLP;

        return (GF_BaseInterface *)plug;
}

GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *bi)
{
        GF_InputService *ifcn = (GF_InputService*)bi;
        if (ifcn->InterfaceType==GF_NET_CLIENT_INTERFACE) {
                DCReader *read = (DCReader*)ifcn->priv;
                assert(!gf_list_count(read->channels));
                gf_list_del(read->channels);
                if( read->url) gf_free(read->url);
                gf_free(read);
                gf_free(bi);
        }
}

GPAC_MODULE_STATIC_DECLARATION( dummy_in )

/* [<][>][^][v][top][bottom][index][help] */