2
* GPAC Multimedia Framework
4
* Authors: Cyril Concolato
5
* Copyright (c) Telecom ParisTech 2013-
8
* This file is part of GPAC / VTT Loader/Decoder module
10
* GPAC is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU Lesser General Public License as published by
12
* the Free Software Foundation; either version 2, or (at your option)
15
* GPAC is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this library; see the file COPYING. If not, write to
22
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27
#include <gpac/internal/terminal_dev.h>
28
#include <gpac/scene_manager.h>
29
#include <gpac/constants.h>
30
#include <gpac/modules/js_usr.h>
32
#ifndef GPAC_DISABLE_VTT
36
/* Counter-part object in the terminal */
37
GF_ClientService *service;
38
/* Channel object associated to this object */
42
GF_DownloadSession * dnload;
44
Bool needs_connection;
46
/* Header for the SL packets created by this module and sent out to the terminal */
50
const char * VTT_MIME_TYPES[] = {
51
"text/vtt", "vtt", "VTT SubTitles",
55
static u32 VTT_RegisterMimeTypes(const GF_InputService *plug){
58
for (i = 0 ; VTT_MIME_TYPES[i]; i+=3){
59
gf_term_register_mime_type(plug, VTT_MIME_TYPES[i], VTT_MIME_TYPES[i+1], VTT_MIME_TYPES[i+2]);
64
static Bool VTT_CanHandleURL(GF_InputService *plug, const char *url)
68
if (!plug || !url) return GF_FALSE;
69
sExt = strrchr(url, '.');
70
if (!sExt) return GF_FALSE;
71
for (i = 0 ; VTT_MIME_TYPES[i]; i+=3){
72
if (gf_term_check_extension(plug, VTT_MIME_TYPES[i], VTT_MIME_TYPES[i+1], VTT_MIME_TYPES[i+2], sExt)) return GF_TRUE;
77
static Bool VTT_is_local(const char *url)
79
if (!url) return GF_FALSE;
80
if (!strnicmp(url, "file://", 7)) return GF_TRUE;
81
if (strstr(url, "://")) return GF_FALSE;
85
void VTT_NetIO(void *cbk, GF_NETIO_Parameter *param)
89
GF_InputService *plug = (GF_InputService *)cbk;
90
VTTIn *vttin = (VTTIn *) plug->priv;
93
gf_term_download_update_stats(vttin->dnload);
97
if (param->msg_type==GF_NETIO_DATA_TRANSFERED) {
98
szCache = gf_dm_sess_get_cache_name(vttin->dnload);
99
if (!szCache) e = GF_IO_ERR;
101
//e = TTIn_LoadFile(plug, szCache, 1);
104
else if (param->msg_type==GF_NETIO_DATA_EXCHANGE) {
109
if (vttin->needs_connection) {
110
vttin->needs_connection = GF_FALSE;
111
gf_term_on_connect(vttin->service, NULL, e);
112
//if (!e && !vttin->od_done) tti_setup_object(vttin);
116
void VTT_download_file(GF_InputService *plug, const char *url)
118
VTTIn *vttin = (VTTIn *) plug->priv;
121
vttin->needs_connection = GF_TRUE;
122
vttin->dnload = gf_term_download_new(vttin->service, url, 0, VTT_NetIO, plug);
123
if (!vttin->dnload) {
124
vttin->needs_connection = GF_FALSE;
125
gf_term_on_connect(vttin->service, NULL, GF_NOT_SUPPORTED);
127
/*start our download (threaded)*/
128
gf_dm_sess_process(vttin->dnload);
130
/*service confirm is done once fetched*/
133
static GF_Err VTT_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
136
VTTIn *vttin = (VTTIn *)plug->priv;
139
vttin->service = serv;
141
if (vttin->dnload) gf_term_download_del(vttin->dnload);
142
vttin->dnload = NULL;
145
if (!VTT_is_local(url)) {
146
VTT_download_file(plug, url);
150
//e = TTIn_LoadFile(plug, url, 0);
151
gf_term_on_connect(serv, NULL, e);
152
//if (!e && !vttin->od_done) tti_setup_object(vttin);
157
static GF_Err VTT_CloseService(GF_InputService *plug)
160
if (!plug) return GF_BAD_PARAM;
162
vttin = (VTTIn *)plug->priv;
163
if (!vttin) return GF_BAD_PARAM;
165
//if (vttin->szFile) {
166
// gf_delete_file(vttin->szFile);
167
// gf_free(vttin->szFile);
169
//vttin->szFile = NULL;
172
gf_term_download_del(vttin->dnload);
174
vttin->dnload = NULL;
176
if (vttin->service) {
177
gf_term_on_disconnect(vttin->service, NULL, GF_OK);
179
vttin->service = NULL;
184
static GF_Descriptor *VTT_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url)
187
if (!plug) return NULL;
188
vttin = (VTTIn *)plug->priv;
189
if (!vttin) return NULL;
191
switch (expect_type) {
192
case GF_MEDIA_OBJECT_UNDEF:
193
case GF_MEDIA_OBJECT_UPDATES:
194
case GF_MEDIA_OBJECT_TEXT:
196
GF_ObjectDescriptor *od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
197
//GF_ESD *esd = tti_get_esd(vttin);
198
//od->objectDescriptorID = esd->ESID;
199
//gf_list_add(od->ESDescriptors, esd);
200
//vttin->od_done = 1;
201
return (GF_Descriptor *) od;
209
static GF_Err VTT_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
213
VTTIn *vttin = (VTTIn *)plug->priv;
214
if (!vttin) return GF_BAD_PARAM;
215
e = GF_SERVICE_ERROR;
216
if (!vttin || vttin->channel==channel) goto exit;
218
e = GF_STREAM_NOT_FOUND;
220
if (strstr(url, "ES_ID")) sscanf(url, "ES_ID=%ud", &ES_ID);
223
vttin->channel = channel;
228
gf_term_on_connect(vttin->service, channel, e);
232
static GF_Err VTT_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
234
VTTIn *vttin = (VTTIn *)plug->priv;
235
GF_Err e = GF_STREAM_NOT_FOUND;
237
if (!vttin) return GF_BAD_PARAM;
239
if (vttin->channel == channel) {
240
vttin->channel = NULL;
243
gf_term_on_disconnect(vttin->service, channel, e);
247
static GF_Err VTT_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
249
//VTTIn *vttin = (VTTIn *)plug->priv;
251
//if (!vttin) return GF_BAD_PARAM;
252
//if (!com->base.on_channel) return GF_NOT_SUPPORTED;
253
//switch (com->command_type) {
254
//case GF_NET_CHAN_SET_PADDING:
255
// gf_isom_set_sample_padding(vttin->mp4, vttin->tt_track, com->pad.padding_bytes);
257
//case GF_NET_CHAN_DURATION:
258
// com->duration.duration = (Double) (s64) gf_isom_get_media_duration(vttin->mp4, vttin->tt_track);
259
// com->duration.duration /= gf_isom_get_media_timescale(vttin->mp4, vttin->tt_track);
261
//case GF_NET_CHAN_PLAY:
262
// vttin->start_range = (com->play.start_range>0) ? (u32) (com->play.start_range * 1000) : 0;
263
// if (vttin->channel == com->base.on_channel) {
264
// vttin->samp_num = 0;
265
// if (vttin->samp) gf_isom_sample_del(&vttin->samp);
268
//case GF_NET_CHAN_STOP:
276
static GF_Err VTT_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)
278
//VTTIn *vttin = (VTTIn *)plug->priv;
280
//*out_reception_status = GF_OK;
281
//*sl_compressed = GF_FALSE;
282
//*is_new_data = GF_FALSE;
284
//memset(&vttin->sl_hdr, 0, sizeof(GF_SLHeader));
285
//vttin->sl_hdr.randomAccessPointFlag = 1;
286
//vttin->sl_hdr.compositionTimeStampFlag = 1;
287
//vttin->sl_hdr.accessUnitStartFlag = vttin->sl_hdr.accessUnitEndFlag = 1;
289
///*fetching es data*/
290
//if (vttin->channel == channel) {
291
// if (vttin->samp_num>=gf_isom_get_sample_count(vttin->mp4, vttin->tt_track)) {
292
// *out_reception_status = GF_EOS;
296
// if (!vttin->samp) {
298
// if (vttin->start_range) {
300
// *out_reception_status = gf_isom_get_sample_for_movie_time(vttin->mp4, vttin->tt_track, vttin->start_range, &di, GF_ISOM_SEARCH_SYNC_BACKWARD, &vttin->samp, &vttin->samp_num);
301
// vttin->start_range = 0;
303
// vttin->samp = gf_isom_get_sample(vttin->mp4, vttin->tt_track, vttin->samp_num+1, &di);
305
// if (!vttin->samp) {
306
// *out_reception_status = GF_CORRUPTED_DATA;
311
// vttin->sl_hdr.compositionTimeStamp = vttin->sl_hdr.decodingTimeStamp = vttin->samp->DTS;
312
// *out_data_ptr = vttin->samp->data;
313
// *out_data_size = vttin->samp->dataLength;
314
// *out_sl_hdr = vttin->sl_hdr;
317
return GF_STREAM_NOT_FOUND;
320
static GF_Err VTT_ChannelReleaseSLP(GF_InputService *plug, LPNETCHANNEL channel)
322
//VTTIn *vttin = (VTTIn *)plug->priv;
323
//if (vttin->channel == channel) {
324
// if (!vttin->samp) return GF_BAD_PARAM;
325
// gf_isom_sample_del(&vttin->samp);
326
// vttin->samp = NULL;
327
// vttin->samp_num++;
333
static void *NewVTTInput()
336
GF_InputService *plug;
337
GF_SAFEALLOC(plug, GF_InputService);
338
GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "GPAC SubTitle Reader", "gpac distribution")
340
plug->RegisterMimeTypes = VTT_RegisterMimeTypes;
341
plug->CanHandleURL = VTT_CanHandleURL;
342
plug->CanHandleURLInService = NULL;
343
plug->ConnectService = VTT_ConnectService;
344
plug->CloseService = VTT_CloseService;
345
plug->GetServiceDescriptor = VTT_GetServiceDesc;
346
plug->ConnectChannel = VTT_ConnectChannel;
347
plug->DisconnectChannel = VTT_DisconnectChannel;
348
plug->ChannelGetSLP = VTT_ChannelGetSLP;
349
plug->ChannelReleaseSLP = VTT_ChannelReleaseSLP;
350
plug->ServiceCommand = VTT_ServiceCommand;
352
GF_SAFEALLOC(priv, VTTIn);
357
void DeleteVTTInput(void *ifce)
360
GF_InputService *plug = (GF_InputService *)ifce;
363
vttin = (VTTIn *)plug->priv;
365
VTT_CloseService(plug);
373
void DeleteVTTDec(GF_BaseDecoder *plug);
374
//GF_JSUserExtension *NewVTTJS();
375
//void DeleteVTTJS(GF_BaseInterface *ifce);
379
GF_BaseInterface *LoadInterface(u32 InterfaceType)
381
switch (InterfaceType) {
382
case GF_SCENE_DECODER_INTERFACE: return (GF_BaseInterface *)NewVTTDec();
383
case GF_NET_CLIENT_INTERFACE: return (GF_BaseInterface *)NewVTTInput();
384
// case GF_JS_USER_EXT_INTERFACE: return (GF_BaseInterface *)NewVTTJS();
385
default: return NULL;
390
/*interface destroy*/
392
void ShutdownInterface(GF_BaseInterface *ifce)
394
switch (ifce->InterfaceType) {
395
case GF_SCENE_DECODER_INTERFACE:
396
DeleteVTTDec((GF_BaseDecoder *)ifce);
398
case GF_NET_CLIENT_INTERFACE:
399
DeleteVTTInput(ifce);
401
//case GF_JS_USER_EXT_INTERFACE:
402
// DeleteVTTJS(ifce);
412
GF_BaseInterface *LoadInterface(u32 InterfaceType)
418
/*interface destroy*/
420
void ShutdownInterface(GF_BaseInterface *ifce)
428
const u32 *QueryInterfaces()
431
#if !defined(GPAC_DISABLE_VTT)
432
GF_SCENE_DECODER_INTERFACE,
433
GF_NET_CLIENT_INTERFACE,
434
// GF_JS_USER_EXT_INTERFACE,
441
GPAC_MODULE_STATIC_DELARATION( vtt_in )