This source file includes following definitions.
- DC_GetChannel
- DC_RemoveChannel
- DC_RegisterMimeTypes
- DC_CanHandleURL
- DC_NetIO
- DC_DownloadFile
- DC_ConnectService
- DC_CloseService
- DC_GetServiceDesc
- DC_ServiceCommand
- DC_ConnectChannel
- DC_DisconnectChannel
- DC_ChannelGetSLP
- DC_ChannelReleaseSLP
- DC_CanHandleURLInService
- QueryInterfaces
- LoadInterface
- ShutdownInterface
#include <gpac/modules/service.h>
#include <gpac/constants.h>
#include <gpac/download.h>
#include <gpac/xml.h>
typedef struct
{
u32 ESID;
LPNETCHANNEL ch;
u32 start, end;
} DummyChannel;
typedef struct
{
GF_ClientService *service;
char *url;
u32 oti;
Bool is_views_url;
GF_List *channels;
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-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;
}
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;
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;
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 {
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;
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;
}
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);
}
}
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;
}
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;
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:
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 )