From: Alessio Treglia Date: Tue, 6 Mar 2012 22:40:10 +0000 (+0100) Subject: Imported Upstream version 0.4.5+svn3950~dfsg0 X-Git-Tag: archive/raspbian/1.0.1+dfsg1-4+rpi1~1^2~15^2~21 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=5dc8a733c1b6c6d0eef370a31bc4a49c3c02d264;p=gpac.git Imported Upstream version 0.4.5+svn3950~dfsg0 --- diff --git a/Makefile b/Makefile index d7635e5..0d13ebb 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,9 @@ install: $(INSTALL) -d "$(DESTDIR)$(prefix)" $(INSTALL) -d "$(DESTDIR)$(prefix)/$(libdir)" $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" +ifeq ($(DISABLE_ISOFF), no) $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Box "$(DESTDIR)$(prefix)/bin" +endif $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Client "$(DESTDIR)$(prefix)/bin" if [ -d $(DESTDIR)$(prefix)/$(libdir)/pkgconfig ] ; then \ $(INSTALL) $(INSTFLAGS) -m 644 gpac.pc "$(DESTDIR)$(prefix)/$(libdir)/pkgconfig" ; \ @@ -112,8 +114,9 @@ ifeq ($(CONFIG_DARWIN),yes) $(INSTALL) -m 755 bin/gcc/libgpac.$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(VERSION).$(DYN_LIB_SUFFIX) ln -sf libgpac.$(VERSION).$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(DYN_LIB_SUFFIX) else - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(DYN_LIB_SUFFIX).$(VERSION) - ln -sf libgpac.$(DYN_LIB_SUFFIX).$(VERSION) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(DYN_LIB_SUFFIX) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) + ln -sf libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so.$(VERSION_MAJOR) + ln -sf libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so ifeq ($(DESTDIR)$(prefix),$(prefix)) ldconfig || true endif diff --git a/applications/Makefile b/applications/Makefile index 872a402..e93a736 100644 --- a/applications/Makefile +++ b/applications/Makefile @@ -4,8 +4,10 @@ APPDIRS=mp4client ifeq ($(DISABLE_ISOFF), no) APPDIRS+=mp4box +ifeq ($(DISABLE_M2TS), no) APPDIRS+=mp42ts endif +endif V4STUDIODIR= INSTDIRS=mp4client diff --git a/applications/mp4box/filedump.c b/applications/mp4box/filedump.c index dc7f8d7..de2b4a0 100644 --- a/applications/mp4box/filedump.c +++ b/applications/mp4box/filedump.c @@ -24,7 +24,7 @@ #include -#ifdef GPAC_DISABLE_ISOM +#if defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE) #error "Cannot compile MP4Box if GPAC is not built with ISO File Format support" @@ -48,7 +48,7 @@ extern u32 get_file_type_by_ext(char *inName); void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist); -#ifndef GPAC_DISABLE_ISOM_WRITE +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample); #endif @@ -180,8 +180,14 @@ GF_Err dump_file_text(char *file, char *inName, u32 dump_mode, Bool do_log) /*SAF*/ else if (ftype==6) { load.isom = gf_isom_open("saf_conv", GF_ISOM_WRITE_EDIT, NULL); - if (load.isom) e = import_file(load.isom, file, 0, 0, 0); - else e = gf_isom_last_error(NULL); +#ifndef GPAC_DISABLE_MEDIA_IMPORT + if (load.isom) + e = import_file(load.isom, file, 0, 0, 0); + else +#else + fprintf(stderr, "Warning: GPAC was compiled without Media Import support\n"); +#endif + e = gf_isom_last_error(NULL); if (e) { fprintf(stdout, "Error importing file: %s\n", gf_error_to_string(e)); @@ -568,8 +574,13 @@ void PrintNode(const char *name, u32 graph_type) fprintf(stdout, "SVG node printing is not supported\n"); return; } else if (graph_type==1) { +#ifndef GPAC_DISABLE_X3D tag = gf_node_x3d_type_by_class_name(name); std_name = "X3D"; +#else + fprintf(stdout, "X3D node printing is not supported (X3D support disabled)\n"); + return; +#endif } else { tag = gf_node_mpeg4_type_by_class_name(name); std_name = "MPEG4"; @@ -676,12 +687,12 @@ void PrintBuiltInNodes(u32 graph_type) u32 i, nb_in, nb_not_in, start_tag, end_tag; if (graph_type==1) { -#ifdef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) + start_tag = GF_NODE_RANGE_FIRST_X3D; + end_tag = TAG_LastImplementedX3D; +#else fprintf(stdout, "X3D scene graph disabled in this build of GPAC\n"); return; -#else - start_tag = GF_NODE_RANGE_FIRST_X3D; - end_tag = TAG_LastImplementedX3D; #endif } else if (graph_type==2) { #ifdef GPAC_DISABLE_SVG @@ -1760,7 +1771,7 @@ void DumpMovieInfo(GF_ISOFile *file) } } -#endif /*GPAC_DISABLE_ISOM*/ +#endif /*defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE)*/ #ifndef GPAC_DISABLE_MPEG2TS @@ -2381,50 +2392,62 @@ static void mpd_start(GF_M2TS_IndexingInfo *index_info, Bool on_demand, const ch char duration_string[100]; char buffer_string[100]; u32 bandwidth, i; +#ifndef GPAC_DISABLE_MEDIA_IMPORT GF_MediaImporter import; +#endif char szCodecs[1000]; u32 width, height, sample_rate, nb_channels, langCode; GF_Err e; FILE *mpd = index_info->mpd_file; /*get codecs*/ +#ifndef GPAC_DISABLE_MEDIA_IMPORT memset(&import, 0, sizeof(GF_MediaImporter)); import.trackID = 0; import.flags = GF_IMPORT_PROBE_ONLY; import.in_name = (char *)media_file_name; e = gf_media_import(&import); +#else + fprintf(stdout, "Warning: generating MPD without media import support\n"); +#endif strcpy(szCodecs, ""); width = height = sample_rate = nb_channels = langCode = 0; + + bandwidth = (u32) (file_size * 8 / file_duration); + mpd_duration(file_duration, duration_string); + mpd_duration(bufferTime, buffer_string); + + if (!index_info->represantation_idx) { + fprintf(mpd, "\n", (on_demand ? "static": "dynamic"), buffer_string); + fprintf(mpd, " \n"); + fprintf(mpd, " MPD for file %s generated with GPAC %s\n", media_file_name, GPAC_FULL_VERSION); + fprintf(mpd, " \n"); + fprintf(mpd, " \n", duration_string, buffer_string); + fprintf(mpd, " \n"); + } + if (!e) { +#ifndef GPAC_DISABLE_MEDIA_IMPORT for (i=0; i\n", import.tk_info[i].track_num); } else if (import.tk_info[i].type==GF_ISOM_MEDIA_AUDIO) { if (!sample_rate) sample_rate = import.tk_info[i].audio_info.sample_rate; if (!nb_channels) nb_channels = import.tk_info[i].audio_info.nb_channels; + fprintf(mpd, " \n", import.tk_info[i].track_num); } if (!langCode && import.tk_info[i].lang) langCode = import.tk_info[i].lang; } - } - - bandwidth = (u32) (file_size * 8 / file_duration); - mpd_duration(file_duration, duration_string); - mpd_duration(bufferTime, buffer_string); - - if (!index_info->represantation_idx) { - fprintf(mpd, "\n", (on_demand ? "static": "dynamic"), buffer_string); - fprintf(mpd, " \n"); - fprintf(mpd, " MPD for file %s generated with GPAC %s\n", media_file_name, GPAC_FULL_VERSION); - fprintf(mpd, " \n"); - fprintf(mpd, " \n", duration_string, buffer_string); - fprintf(mpd, " \n"); +#endif } fprintf(mpd, " represantation_idx+1, szCodecs); @@ -2487,7 +2510,7 @@ static void write_mpd_segment_info(GF_M2TS_IndexingInfo *index_info, char *media /* add startIndex for live scenarios */ if (index_info->init_seg_name) { - fprintf(index_info->mpd_file, " \n", index_info->init_seg_name); + fprintf(index_info->mpd_file, " \n", index_info->init_seg_name); } @@ -2601,6 +2624,7 @@ void dump_mpeg2_ts(char *mpeg2ts_file, char *out_name, Bool prog_num, dumper.index_info.index_file = NULL; dumper.index_info.index_bs = NULL; if (dumper.index_info.use_url_template!=2) { +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS dumper.index_info.index_file = gf_f64_open(dumper.index_info.index_file_name, "wb"); dumper.index_info.index_bs = gf_bs_from_file(dumper.index_info.index_file, GF_BITSTREAM_WRITE); { @@ -2614,6 +2638,7 @@ void dump_mpeg2_ts(char *mpeg2ts_file, char *out_name, Bool prog_num, gf_isom_box_write((GF_Box *)styp, dumper.index_info.index_bs); gf_isom_box_del((GF_Box *)styp); } +#endif } } /*PES dumping*/ diff --git a/applications/mp4box/fileimport.c b/applications/mp4box/fileimport.c index 97fb414..7b180e5 100644 --- a/applications/mp4box/fileimport.c +++ b/applications/mp4box/fileimport.c @@ -32,6 +32,17 @@ #ifndef GPAC_DISABLE_ISOM_WRITE +#include + +typedef struct +{ + const char *root_file; + const char *dir; + GF_List *imports; +} WGTEnum; + +#ifndef GPAC_DISABLE_MEDIA_IMPORT + extern u32 swf_flags; extern Float swf_flatten_angle; extern Bool keep_sys_tracks; @@ -1385,7 +1396,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou u32 di; samp = gf_isom_get_sample(orig, i+1, j+1, &di); last_DTS = samp->DTS; - samp->DTS = (u64) (ts_scale * (s64)samp->DTS) + insert_dts; + samp->DTS = (u64) (ts_scale * samp->DTS + insert_dts); samp->CTS_Offset = (u32) (samp->CTS_Offset * ts_scale); if (gf_isom_is_self_contained(orig, i+1, di)) { @@ -1397,7 +1408,8 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou gf_isom_sample_del(&s); } gf_isom_sample_del(&samp); - if (e) goto err_exit; + if (e) + goto err_exit; gf_set_progress("Appending", nb_done, nb_samp); nb_done++; } @@ -1565,7 +1577,9 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log GF_SceneLoader load; GF_SceneManager *ctx; GF_SceneGraph *sg; +#ifndef GPAC_DISABLE_SCENE_STATS GF_StatManager *statsman = NULL; +#endif sg = gf_sg_new(); ctx = gf_sm_new(sg); @@ -1585,6 +1599,7 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log e = gf_sm_load_run(&load); gf_sm_load_done(&load); +#ifndef GPAC_DISABLE_SCENE_STATS if (opts->auto_quant) { fprintf(stdout, "Analysing Scene for Automatic Quantization\n"); statsman = gf_sm_stats_new(); @@ -1655,6 +1670,7 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log #endif } } +#endif /*GPAC_DISABLE_SCENE_STATS*/ if (e<0) { fprintf(stdout, "Error loading file %s\n", gf_error_to_string(e)); @@ -1676,7 +1692,9 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log gf_isom_modify_alternate_brand(mp4, GF_ISOM_BRAND_ISOM, 1); err_exit: +#ifndef GPAC_DISABLE_SCENE_STATS if (statsman) gf_sm_stats_del(statsman); +#endif gf_sm_del(ctx); gf_sg_del(sg); return e; @@ -1846,8 +1864,8 @@ GF_Err EncodeBIFSChunk(GF_SceneManager *ctx, char *bifsOutputFile, GF_Err (*AUCa */ GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext, const char *tmpdir) { -#ifdef GPAC_DISABLE_BIFS - fprintf(stdout, "BIFS is not supported in this build of GPAC\n"); +#if defined(GPAC_DISABLE_BIFS_ENC) || defined(GPAC_DISABLE_SCENE_ENCODER) || defined (GPAC_DISABLE_SCENE_DUMP) + fprintf(stdout, "BIFS encoding is not supported in this build of GPAC\n"); return GF_NOT_SUPPORTED; #else GF_Err e; @@ -1933,11 +1951,15 @@ exit: gf_sm_del(ctx); gf_sg_del(sg); } + return e; -#endif + +#endif /*defined(GPAC_DISABLE_BIFS_ENC) || defined(GPAC_DISABLE_SCENE_ENCODER) || defined (GPAC_DISABLE_SCENE_DUMP)*/ + } -#include +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + void sax_node_start(void *sax_cbck, const char *node_name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes) { @@ -1960,13 +1982,6 @@ void sax_node_start(void *sax_cbck, const char *node_name, const char *name_spac } } -typedef struct -{ - const char *root_file; - const char *dir; - GF_List *imports; -} WGTEnum; - static Bool wgt_enum_files(void *cbck, char *file_name, char *file_path) { WGTEnum *wgt = (WGTEnum *)cbck; diff --git a/applications/mp4box/live.c b/applications/mp4box/live.c index aafaf5b..efca9d6 100644 --- a/applications/mp4box/live.c +++ b/applications/mp4box/live.c @@ -31,6 +31,14 @@ #include #include +#if defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE) + +#error "Cannot compile MP4Box if GPAC is not built with ISO File Format support" + +#else + +#ifndef GPAC_DISABLE_STREAMING + void PrintStreamerUsage() { fprintf(stdout, "File Streamer Options\n" @@ -797,3 +805,6 @@ exit: } +#endif /*GPAC_DISABLE_STREAMING*/ + +#endif /*defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE)*/ diff --git a/applications/mp4box/main.c b/applications/mp4box/main.c index a516aa9..bc2b0c7 100644 --- a/applications/mp4box/main.c +++ b/applications/mp4box/main.c @@ -46,18 +46,19 @@ /*in fileimport.c*/ #ifndef GPAC_DISABLE_ISOM_WRITE -void convert_file_info(char *inName, u32 trackID); + GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample); GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, char *inName, Double InterleavingTime, Double chunk_start, Bool adjust_split_end, const char *tmpdir); GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat); -#ifndef GPAC_DISABLE_SCENE_ENCODER +#if !defined(GPAC_DISABLE_MEDIA_IMPORT) && !defined(GPAC_DISABLE_SCENE_ENCODER) +void convert_file_info(char *inName, u32 trackID); GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *logs); GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext, const char *tmpdir); #endif - GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool make_wgt); + #endif GF_Err dump_cover_art(GF_ISOFile *file, char *inName); @@ -109,10 +110,10 @@ void dump_mpeg2_ts(char *mpeg2ts_file, char *pes_out_name, Bool prog_num, #ifndef GPAC_DISABLE_STREAMING void PrintStreamerUsage(); int stream_file_rtp(int argc, char **argv); -#endif - int live_session(int argc, char **argv); void PrintLiveUsage(); +#endif + int mp4boxTerminal(int argc, char **argv); u32 quiet = 0; @@ -1203,8 +1204,10 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_SCENE_ENCODER GF_SMEncodeOptions opts; #endif - Double InterleavingTime, split_duration, split_start, import_fps, dash_duration; +#ifndef GPAC_DISABLE_STREAMING SDPLine sdp_lines[MAX_CUMUL_OPS]; +#endif + Double InterleavingTime, split_duration, split_start, import_fps, dash_duration; MetaAction metas[MAX_CUMUL_OPS]; TrackAction tracks[MAX_CUMUL_OPS]; TSELAction tsel_acts[MAX_CUMUL_OPS]; @@ -1793,7 +1796,7 @@ int mp4boxMain(int argc, char **argv) nb_track_act++; i++; } -#ifndef GPAC_DISABLE_MEDIA_EXPORT +#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_MEDIA_IMPORT) else if (!stricmp(arg, "-dref")) import_flags |= GF_IMPORT_USE_DATAREF; else if (!stricmp(arg, "-no-drop") || !stricmp(arg, "-nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; else if (!stricmp(arg, "-packed")) import_flags |= GF_IMPORT_FORCE_PACKED; @@ -1816,7 +1819,7 @@ int mp4boxMain(int argc, char **argv) } else if (!stricmp(arg, "-agg")) { CHECK_NEXT_ARG agg_samples = atoi(argv[i+1]); i++; } else if (!stricmp(arg, "-keep-all") || !stricmp(arg, "-keepall")) import_flags |= GF_IMPORT_KEEP_ALL_TRACKS; -#endif /*GPAC_DISABLE_MEDIA_EXPORT*/ +#endif /*!defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_MEDIA_IMPORT*/ else if (!stricmp(arg, "-keep-sys") || !stricmp(arg, "-keepsys")) keep_sys_tracks = 1; else if (!stricmp(arg, "-ms")) { CHECK_NEXT_ARG mediaSource = argv[i+1]; i++; } else if (!stricmp(arg, "-mp4")) { encode = 1; open_edit = 1; } @@ -1854,12 +1857,14 @@ int mp4boxMain(int argc, char **argv) opts.resolution = atoi(argv[i+1]); i++; } +#ifndef GPAC_DISABLE_SCENE_STATS else if (!stricmp(arg, "-auto-quant")) { CHECK_NEXT_ARG opts.resolution = atoi(argv[i+1]); opts.auto_quant = 1; i++; } +#endif else if (!stricmp(arg, "-coord-bits")) { CHECK_NEXT_ARG opts.coord_bits = atoi(argv[i+1]); @@ -2095,8 +2100,10 @@ int mp4boxMain(int argc, char **argv) else if (!strcmp(argv[i+1], "crypt")) PrintEncryptUsage(); else if (!strcmp(argv[i+1], "meta")) PrintMetaUsage(); else if (!strcmp(argv[i+1], "swf")) PrintSWFUsage(); +#ifndef GPAC_DISABLE_STREAMING else if (!strcmp(argv[i+1], "rtp")) PrintStreamerUsage(); else if (!strcmp(argv[i+1], "live")) PrintLiveUsage (); +#endif else if (!strcmp(argv[i+1], "all")) { PrintGeneralUsage(); PrintExtractUsage(); @@ -2108,8 +2115,10 @@ int mp4boxMain(int argc, char **argv) PrintEncryptUsage(); PrintMetaUsage(); PrintSWFUsage(); +#ifndef GPAC_DISABLE_STREAMING PrintStreamerUsage(); PrintLiveUsage (); +#endif } else PrintUsage(); return 0; @@ -2131,10 +2140,10 @@ int mp4boxMain(int argc, char **argv) return 1; } +#ifndef GPAC_DISABLE_STREAMING if (live_scene) { return live_session(argc, argv); } -#ifndef GPAC_DISABLE_STREAMING if (stream_rtp) { return stream_file_rtp(argc, argv); } @@ -2357,7 +2366,7 @@ int mp4boxMain(int argc, char **argv) } #endif -#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT) else if (chunk_mode) { if (!inName) { fprintf(stdout, "chunk encoding syntax: [-outctx outDump] -inctx inScene auFile\n"); @@ -2369,7 +2378,7 @@ int mp4boxMain(int argc, char **argv) } #endif else if (encode) { -#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT) FILE *logs = NULL; if (do_log) { char logfile[5000]; @@ -2470,6 +2479,7 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_ISOM_WRITE else if (!open_edit && file_exists /* && !gf_isom_probe_file(inName) */ && !dump_mode) { /*************************************************************************************************/ +#ifndef GPAC_DISABLE_MEDIA_IMPORT if(dvbhdemux) { GF_MediaImporter import; @@ -2486,6 +2496,7 @@ int mp4boxMain(int argc, char **argv) return 1; } } +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ if (dash_duration) { if (subsegs_per_sidx<0) subsegs_per_sidx = 0; @@ -2503,14 +2514,14 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_MPEG2TS dump_mpeg2_ts(inName, pes_dump, program_number, 0, 0, 0, NULL, NULL, 0, 0, 0, 0); #endif +#ifndef GPAC_DISABLE_MEDIA_IMPORT } else { convert_file_info(inName, info_track_id); +#endif } return 0; } - - -#endif +#endif /*GPAC_DISABLE_ISOM_WRITE*/ else if (open_edit) { file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, tmpdir); if (!outName && file) outName = inName; @@ -2640,7 +2651,7 @@ int mp4boxMain(int argc, char **argv) } } -#ifndef GPAC_DISABLE_ISOM_WRITE +#if !(definedGPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) if (split_duration || split_size) { split_isomedia_file(file, split_duration, split_size, inName, InterleavingTime, split_start, adjust_split_end, tmpdir); /*never save file when splitting is desired*/ @@ -2825,6 +2836,7 @@ int mp4boxMain(int argc, char **argv) strcat(outfile, ".m21"); } } +#ifndef GPAC_DISABLE_MEDIA_IMPORT if ((conv_type == GF_ISOM_CONV_TYPE_ISMA) || (conv_type == GF_ISOM_CONV_TYPE_ISMA_EX)) { fprintf(stdout, "Converting to ISMA Audio-Video MP4 file...\n"); /*keep ESIDs when doing ISMACryp*/ @@ -2844,6 +2856,7 @@ int mp4boxMain(int argc, char **argv) if (e) goto err_exit; needSave = 1; } +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ if (conv_type == GF_ISOM_CONV_TYPE_IPOD) { u32 major_brand = 0; @@ -3253,7 +3266,7 @@ int mp4boxMain(int argc, char **argv) } if (!seg_name) use_url_template = 0; - gf_media_mpd_start(szMPD, (char *)gf_isom_get_filename(file), use_url_template, single_segment, dash_ctx, szInit, period_duration); + gf_media_mpd_start(szMPD, (char *)gf_isom_get_filename(file), use_url_template, single_segment, dash_ctx, init_seg, period_duration); for (i=0; i1) { fprintf(stdout, "DASHing file %s\n", dash_inputs[i]); } +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS e = gf_media_fragment_file(in, outfile, szMPD, InterleavingTime, seg_at_rap ? 2 : 1, dash_duration, segment_name, seg_ext, subsegs_per_sidx, daisy_chain_sidx, use_url_template, single_segment, dash_ctx, init_seg, i+1); +#else + fprintf(stderr, "GPAC was compiled without fragment support\n"); + e = GF_NOT_SUPPORTED; +#endif if (e) { fprintf(stdout, "Error while DASH-ing file: %s\n", gf_error_to_string(e)); break; @@ -3301,6 +3319,7 @@ int mp4boxMain(int argc, char **argv) gf_isom_delete(file); gf_sys_close(); return (e!=GF_OK) ? 1 : 0; +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS } else if (Frag) { if (!InterleavingTime) InterleavingTime = 0.5; if (HintIt) fprintf(stdout, "Warning: cannot hint and fragment - ignoring hint\n"); @@ -3314,6 +3333,7 @@ int mp4boxMain(int argc, char **argv) } gf_sys_close(); return (e!=GF_OK) ? 1 : 0; +#endif } #ifndef GPAC_DISABLE_ISOM_HINTING @@ -3380,8 +3400,13 @@ int mp4boxMain(int argc, char **argv) if (e) goto err_exit; } if (chap_file) { +#ifndef GPAC_DISABLE_MEDIA_IMPORT e = gf_media_import_chapters(file, chap_file, import_fps); needSave = 1; +#else + fprintf(stdout, "Warning: GPAC compiled without Media Import, chapters can't be imported\n"); + e = GF_NOT_SUPPORTED; +#endif if (e) goto err_exit; } diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c index 7185f69..f43d16b 100644 --- a/applications/mp4client/main.c +++ b/applications/mp4client/main.c @@ -236,7 +236,8 @@ void PrintHelp() "\n" "\tp: play/pause the presentation\n" "\ts: step one frame ahead\n" - "\tz: seek into presentation\n" + "\tz: seek into presentation by percentage\n" + "\tT: seek into presentation by time\n" "\tt: print current timing\n" "\n" "\tu: sends a command (BIFS or LASeR) to the main scene\n" @@ -1407,6 +1408,7 @@ force_input: break; case 'z': + case 'T': if (!CanSeek || (Duration<=2000)) { fprintf(stdout, "scene not seekable\n"); } else { @@ -1415,12 +1417,28 @@ force_input: fprintf(stdout, "Duration: "); PrintTime(Duration); res = gf_term_get_time_in_ms(term); - res *= 100; res /= (s64)Duration; - fprintf(stdout, " (current %.2f %%)\nEnter Seek percentage:\n", res); - if (scanf("%d", &seekTo) == 1) { - if (seekTo > 100) seekTo = 100; - res = (Double)(s64)Duration; res /= 100; res *= seekTo; - gf_term_play_from_time(term, (u64) (s64) res, 0); + if (c=='z') { + res *= 100; res /= (s64)Duration; + fprintf(stdout, " (current %.2f %%)\nEnter Seek percentage:\n", res); + if (scanf("%d", &seekTo) == 1) { + if (seekTo > 100) seekTo = 100; + res = (Double)(s64)Duration; res /= 100; res *= seekTo; + gf_term_play_from_time(term, (u64) (s64) res, 0); + } + } else { + u32 r, h, m, s; + fprintf(stdout, " - Current Time: "); + PrintTime((u64) res); + fprintf(stdout, "\nEnter seek time (Format: s, m:s or h:m:s):\n"); + h = m = s = 0; + r =scanf("%d:%d:%d", &h, &m, &s); + if (r==2) { s = m; m = h; h = 0; } + else if (r==1) { s = h; m = h = 0; } + + if (r && (r<=3)) { + u64 time = h*3600 + m*60 + s; + gf_term_play_from_time(term, time*1000, 0); + } } } break; diff --git a/bin/arm_ppc02_rel/install/do.bat b/bin/arm_ppc02_rel/install/do.bat deleted file mode 100644 index 18c79f4..0000000 --- a/bin/arm_ppc02_rel/install/do.bat +++ /dev/null @@ -1,4 +0,0 @@ -CabWiz gpac.inf -ezsetup -l english -i gpac.ini -r readme.txt -e ../../../COPYING -o GPAC_0.4.2_Setup_arm_ppc02.exe -del *.cab -del *.dat diff --git a/bin/arm_ppc02_rel/install/gpac.inf b/bin/arm_ppc02_rel/install/gpac.inf deleted file mode 100644 index 231ee09..0000000 --- a/bin/arm_ppc02_rel/install/gpac.inf +++ /dev/null @@ -1,134 +0,0 @@ -[Version] -Signature = "$Windows NT$" -Provider = "GPAC 0.4.2" -CESignature = "$Windows CE$" - -[CEStrings] -;Osmo4 for PocketPC install, Osmophone for Smartphone install -AppName = Osmo4 -InstallDir = \Program Files\GPAC - -[Strings] -;Osmo4.exe for PocketPC install, Osmophone.exe for Smartphone install -ExeName = Osmo4.exe - -[DefaultInstall] -CopyFiles = BinFiles , Exefiles -AddReg = GPACReg -CEShortcuts = Shortcut , ProgLink -CESelfRegister=GPAX.dll - -[SourceDisksNames] - -1 =, "Common Files",, .. -2 =, "Extra Files",, . - -[SourceDisksFiles] -libgpac.dll = 1 -%ExeName% = 1 -GPAX.dll = 1 - -;comment this one if not using SpiderMonkey -js.dll = 1 - -;uncomment if your device doesn't have GX installed (I think most do) -;gx.dll = 2 - -;all gpac modules - comment the ones you haven't compiled -gm_aac_in.dll = 1 -gm_amr_dec.dll = 1 -;gm_amr_float_dec.dll = 1 -gm_bifs_dec.dll = 1 -gm_ctx_load.dll = 1 -gm_dummy_in.dll = 1 -;gm_ffmpeg_in.dll = 1 -gm_ft_font.dll = 1 -gm_gapi.dll = 1 -gm_img_in.dll = 1 -gm_isom_in.dll = 1 -gm_mp3_in.dll = 1 -gm_odf_dec.dll = 1 -gm_render2d.dll = 1 -gm_rtp_in.dll = 1 -gm_timedtext.dll = 1 -gm_soft_raster.dll = 1 -gm_wav_out.dll = 1 -gm_xvid_dec.dll = 1 -;gm_ogg_xiph.dll = 1 - -;these 2 go together -;gm_render3d.dll = 1 -;libGLES_CM.dll = 1 - -;these 2 go together -gm_svg_loader.dll = 1 -libxml2.dll = 1 - -;================================================== - - - -; Ouput directories for files & shortcuts - -[DestinationDirs] -BinFiles = 0, %CE2% -Exefiles = 0, %InstallDir% -Shortcut = 0, %CE17% -ProgLink = 0, %CE11% -DefaultDestDir = 0, %InstallDir% - -[BinFiles] -;"gx.dll" -"libgpac.dll" -"GPAX.dll" -"js.dll" -"libGLES_CM.dll" -;"libxml2.dll" - - -[Exefiles] -"gm_aac_in.dll" -"gm_amr_dec.dll" -;"gm_amr_float_dec.dll" -"gm_bifs_dec.dll" -"gm_ctx_load.dll" -"gm_dummy_in.dll" -;"gm_ffmpeg_in.dll" -"gm_ft_font.dll" -"gm_gapi.dll" -"gm_img_in.dll" -"gm_isom_in.dll" -"gm_mp3_in.dll" -"gm_odf_dec.dll" -"gm_render2d.dll" -"gm_rtp_in.dll" -"gm_soft_raster.dll" -"gm_timedtext.dll" -"gm_wav_out.dll" -"gm_xvid_dec.dll" -;"gm_ogg_xiph.dll" - -"gm_render3d.dll" - -;"gm_svg_loader.dll" - -[GPACReg] -;GPAC cfg file location -HKCR,GPAC,InstallDir,0x00000000,%InstallDir% - -;UDP socket overwrite -HKLM,Comm\Afd,DgramBuffer,0x00010001,16 -;GPAC cfg file association -HKCR,.cfg,,0x00000000,txtfile -;MP4 file association -HKCR,.mp4,,0x00000000,mp4file -HKCR,mp4file\Shell\Open\Command,,0x00000000,"""%InstallDir%\%ExeName%""" """%%L""" -;Icon number is bin ID of ressource in app -HKCR,mp4file\DefaultIcon,,0x00000000,"%InstallDir%\%ExeName%,-128" - -[Shortcut] -"%AppName%", 0, "%ExeName%" - -[ProgLink] -"AppName", 0, "%ExeName%" - diff --git a/bin/arm_ppc02_rel/install/gpac.ini b/bin/arm_ppc02_rel/install/gpac.ini deleted file mode 100644 index 92ba500..0000000 --- a/bin/arm_ppc02_rel/install/gpac.ini +++ /dev/null @@ -1,10 +0,0 @@ -[CEAppManager] -Version = 1.0 -Component = GPAC for PocketPC 2002 - -[GPAC for PocketPC 2002] -Description = GPAC Osmo4 -Uninstall = GPAC Osmo4 -IconFile = ..\..\w32_rel\Osmo4.ico -IconIndex = 0 -CabFiles = GPAC.cab diff --git a/bin/arm_ppc02_rel/install/readme.txt b/bin/arm_ppc02_rel/install/readme.txt deleted file mode 100644 index 056b17b..0000000 --- a/bin/arm_ppc02_rel/install/readme.txt +++ /dev/null @@ -1,6 +0,0 @@ -This will install Osmo4 / GPAC version 0.4.2 for PocketPC/SmartPhone 2002 - -GPAC is an open source MPEG-4 framework developped by ENST and available at: - http://gpac.sourceforge.net - -WARNING: THIS RELEASE COMES WITH NO WARRANTY, AND MAY EVEN DAMAGE YOUR HANDHELD DEVICE. PLEASE READ CAREFULLY THE LICENSE HEREJOIN diff --git a/bin/arm_ppc03_rel/install/do.bat b/bin/arm_ppc03_rel/install/do.bat deleted file mode 100644 index 783f2ff..0000000 --- a/bin/arm_ppc03_rel/install/do.bat +++ /dev/null @@ -1,4 +0,0 @@ -CabWiz gpac.inf -ezsetup -l english -i gpac.ini -r readme.txt -e ../../../COPYING -o GPAC_0.4.5_Setup_arm_ppc03.exe -del *.cab -del *.dat diff --git a/bin/arm_ppc03_rel/install/gpac.inf b/bin/arm_ppc03_rel/install/gpac.inf deleted file mode 100644 index 81b6545..0000000 --- a/bin/arm_ppc03_rel/install/gpac.inf +++ /dev/null @@ -1,141 +0,0 @@ -[Version] -Signature = "$Windows NT$" -Provider = "GPAC 0.4.5" -CESignature = "$Windows CE$" - -[CEStrings] -;Osmo4 for PocketPC install, Osmophone for Smartphone install -AppName = Osmophone -InstallDir = \Program Files\GPAC - -[Strings] -;Osmo4.exe for PocketPC install, Osmophone.exe for Smartphone install -ExeName = Osmophone.exe - -[DefaultInstall] -CopyFiles = BinFiles , Exefiles -AddReg = GPACReg -CEShortcuts = Shortcut , ProgLink -CESelfRegister=GPAX.dll - - -[SourceDisksNames] - -1 =, "Common Files",, .. -2 =, "Extra Files",, . -3 =, "Doc Files",, ..\..\..\doc\ - -[SourceDisksFiles] -libgpac.dll = 1 -%ExeName% = 1 -;Osmo4.exe = 1 -GPAX.dll = 1 -gpac.mp4 = 3 - -;comment this one if not using OpenGL -libGLES_CM.dll = 1 - -;comment this one if not using SpiderMonkey -js.dll = 1 - -;uncomment if your device doesn't have GX installed (I think most do) -;gx.dll = 2 - -;all gpac modules - comment the ones you haven't compiled -gm_aac_in.dll = 1 -gm_amr_dec.dll = 1 -;gm_amr_float_dec.dll = 1 -gm_bifs_dec.dll = 1 -gm_ctx_load.dll = 1 -gm_dummy_in.dll = 1 -gm_ffmpeg_in.dll = 1 -gm_ft_font.dll = 1 -gm_gapi.dll = 1 -gm_img_in.dll = 1 -gm_ismacryp.dll = 1 -gm_isom_in.dll = 1 -gm_laser_dec.dll = 1 -gm_mp3_in.dll = 1 -gm_odf_dec.dll = 1 -gm_rtp_in.dll = 1 -gm_timedtext.dll = 1 -gm_soft_raster.dll = 1 -gm_svg_in.dll = 1 -gm_wav_out.dll = 1 -gm_xvid_dec.dll = 1 -;gm_ogg_xiph.dll = 1 - - -;ENST Proprietary modules -;gm_upnp.dll = 1 - -;================================================== - - - -; Ouput directories for files & shortcuts - -[DestinationDirs] -BinFiles = 0, %CE2% -Exefiles = 0, %InstallDir% -Shortcut = 0, %CE17% -ProgLink = 0, %CE11% -DefaultDestDir = 0, %InstallDir% - -[BinFiles] -;"gx.dll" -"libgpac.dll" -"GPAX.dll" -"js.dll" -"libGLES_CM.dll" -;"libxml2.dll" - -[Exefiles] -"%ExeName%" -;"Osmo4.exe" -"gpac.mp4" -"gm_aac_in.dll" -"gm_amr_dec.dll" -;"gm_amr_float_dec.dll" -"gm_bifs_dec.dll" -"gm_ctx_load.dll" -"gm_dummy_in.dll" -"gm_ffmpeg_in.dll" -"gm_ft_font.dll" -"gm_gapi.dll" -"gm_img_in.dll" -"gm_ismacryp.dll" -"gm_isom_in.dll" -"gm_laser_dec.dll" -"gm_mp3_in.dll" -"gm_odf_dec.dll" -"gm_rtp_in.dll" -"gm_soft_raster.dll" -"gm_svg_in.dll" -"gm_timedtext.dll" -"gm_wav_out.dll" -"gm_xvid_dec.dll" -;"gm_ogg_xiph.dll" - -;"gm_upnp.dll" - -[GPACReg] -;GPAC cfg file location -HKCR,GPAC,InstallDir,0x00000000,%InstallDir% - -;GPAC cfg file association -HKCR,.cfg,,0x00000000,txtfile - -;MP4 file association -HKCR,.mp4,,0x00000000,mp4file -HKCR,mp4file\Shell\Open\Command,,0x00000000,"""%InstallDir%\%ExeName%""" """%%L""" - -;Icon number is bin ID of ressource in app -HKCR,mp4file\DefaultIcon,,0x00000000,"%InstallDir%\%ExeName%,-128" - -[Shortcut] -"%AppName%", 0, "%ExeName%" - -[ProgLink] -"%AppName%", 0, "%ExeName%" - diff --git a/bin/arm_ppc03_rel/install/gpac.ini b/bin/arm_ppc03_rel/install/gpac.ini deleted file mode 100644 index 830a9c1..0000000 --- a/bin/arm_ppc03_rel/install/gpac.ini +++ /dev/null @@ -1,10 +0,0 @@ -[CEAppManager] -Version = 1.0 -Component = GPAC for PocketPC 2003 - -[GPAC for PocketPC 2003] -Description = GPAC PocketPC MPEG-4 Player -Uninstall = GPAC Osmo4 -IconFile = ..\..\w32_rel\Osmo4.ico -IconIndex = 0 -CabFiles = GPAC.cab diff --git a/bin/arm_ppc03_rel/install/readme.txt b/bin/arm_ppc03_rel/install/readme.txt deleted file mode 100644 index 91f5956..0000000 --- a/bin/arm_ppc03_rel/install/readme.txt +++ /dev/null @@ -1,6 +0,0 @@ -This will install GPAC version 0.4.5 for ARM PocketPC/SmartPhones 2003 Platforms - -GPAC is an open source MPEG-4 framework developped by ENST and available at: - http://gpac.sourceforge.net - -WARNING: THIS RELEASE COMES WITH NO WARRANTY, AND MAY EVEN DAMAGE YOUR HANDHELD DEVICE. PLEASE READ CAREFULLY THE LICENSE HEREJOIN diff --git a/configure b/configure index a117a4a..4c956c1 100755 --- a/configure +++ b/configure @@ -135,6 +135,7 @@ disable_loader_isoff="no" disable_loader_bt="no" disable_loader_xmt="no" disable_od_dump="no" +disable_isom_dump="no" disable_mcrypt="no" disable_isoff="no" disable_isoff_write="no" @@ -239,7 +240,8 @@ Configuration options for libgpac - all options can be enabled with --enable-opt --disable-vrml disable MPEG-4/VRML/X3D --disable-x3d disable X3D only --disable-odf disable full support of MPEG-4 OD Framework - --disable-bifs disable BIFS coder + --disable-bifs disable BIFS + --disable-bifs-enc disable BIFS coder --disable-laser disable LASeR coder --disable-beng disable scene encoder engine --disable-qtvr disable import of Cubic QTVR files @@ -255,12 +257,13 @@ Configuration options for libgpac - all options can be enabled with --enable-opt --disable-swf disable SWF import --disable-scene-stats disable scene graph statistics --disable-scene-dump disable scene graph dump - --disable-od-dump disable OD dump - --disable-mcrypt disable mcrypt --disable-scene-encode disable BIFS & LASeR to ISO File Format encoding --disable-loader-isoff disable scene loading from ISO File Format --disable-loader-bt disable scene loading from ISO File Format --disable-loader-xmt disable scene loading from ISO File Format + --disable-od-dump disable OD dump + --disable-isom-dump disable ISOM dump + --disable-mcrypt disable mcrypt --disable-isoff disable ISO File Format --disable-isoff-write disable ISO File Format edit/write --disable-isoff-hint disable ISO File Format hinting @@ -298,7 +301,7 @@ for opt do ;; --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` ;; - --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` && echo "cross-prefix detected: $cross_prefix" + --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` && echo "\ncross-prefix detected: $cross_prefix" ;; --cc=*) cc=`echo $opt | cut -d '=' -f 2` ;; @@ -402,8 +405,10 @@ pkg_config="${cross_prefix}${pkg_config}" #check pkg_config -if ! $pkg_config --version >/dev/null 2>&1 ; then - echo "$pkg_config not found, configure may detect wrong libraries" +if test "$cross_prefix" = "" ; then + if ! $pkg_config --version >/dev/null 2>&1 ; then + echo "$pkg_config not found, configure may detect wrong libraries" + fi fi @@ -542,7 +547,7 @@ EOF Linux) js_flags="-DXP_UNIX -I/usr/include/js" - LDFLAGS="$LDFLAGS -Wl,--warn-common" + LDFLAGS="$LDFLAGS -Wl,--warn-common -Wl,-z,defs" #OSS_LDFLAGS="-laoss" linux="yes" case "$cpu" in @@ -594,13 +599,9 @@ fi #GCC opt if test "$no_gcc_opt" = "no"; then - if $cc --version | grep 'sbox-arm-linux-gcc (GCC) 3.4.4' - then - echo "Detected buggy arm GCC (diablo), using -O2" - CFLAGS="-O2 $CFLAGS" - else - CFLAGS="-O3 $CFLAGS" - fi + CFLAGS="-O3 $CFLAGS" +else + CFLAGS="-O0 $CFLAGS" fi @@ -737,9 +738,10 @@ EOF fi fi +new_js_api="no" if test "$has_js" != "no" ; then js_flags="-DSPIDERMONKEY_NEW_API $js_flags" - echo "SpiderMonkey new API detected" # (version > 1.8.0rc1) + new_js_api="yes" fi #spidermonkey test for regular API @@ -807,20 +809,26 @@ EOF fi - if test "$has_js" != "no" ; then if test "$linux" = "yes" ; then if test "$cpu" != "sh4"; then - #WARNING: there is a bug in MOZJS packages, the MOZILLA_1_8_BRANCH macro is not signaled, there is no way of knowing #if the lib has been compiled with or without the macro. We currently just decide that if the macro is present #in the header, it was enabled in the build - if grep "MOZILLA_1_8_BRANCH" $js_inc/jsapi.h > /dev/null 2>&1 ; then - js_flags="-DMOZILLA_1_8_BRANCH $js_flags" - echo "WARNING: Turning on MOZILLA_1_8_BRANCH SpiderMonkey macro" - echo "If you have troubles with scripts in GPAC, disable this macro and recompile" + if test "$new_js_api" = "no" ; then + if grep MOZILLA_1_8_BRANCH $js_inc/jsapi.h > /dev/null 2>&1 ; then + js_flags="-DMOZILLA_1_8_BRANCH $js_flags" + echo "WARNING: Turning on MOZILLA_1_8_BRANCH SpiderMonkey macro" + echo "If you have troubles with scripts in GPAC, disable this macro and recompile" + fi + else + #check presence of ***RuntimeThread + if grep RuntimeThread $js_inc/jsapi.h > /dev/null 2>&1 ; then + js_flags="$js_flags" + else + js_flags="-DNO_JS_RUNTIMETHREAD $js_flags" + fi fi - fi fi fi @@ -837,7 +845,7 @@ cat > $TMPC << EOF #include int main( void ) { return 0; } EOF -if $cpp -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib 2> /dev/null ; then +if $cpp -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread 2> /dev/null ; then has_platinum="yes" fi @@ -854,7 +862,7 @@ int main( void ) { DeviceDescriptor* dd = 0; for (DeviceCollector::DeviceList::const_iterator i = dl.begin(); i != dl.end(); i++) { dd = *i; - std::cout << dd->getName().c_str() << "\n"; + std::cout << dd->getName().c_str() << "\n"; } return 0; } @@ -870,7 +878,7 @@ else avcap_ldflags="-lavcap -lpthread" fi if $cpp -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags 2> /dev/null ; then - has_avcap="yes" + has_avcap="yes" avcap_ldflags="-L../../$local_lib $avcap_ldflags" fi fi @@ -1201,7 +1209,18 @@ fi -#look for MAD support +#look for FREENECT support +freenect_flags="" +freenect_ld="-lfreenect" + +if $pkg_config --exists libfreenect 2> /dev/null ; then + freenect_flags=`$pkg_config --cflags libfreenect` + freenect_libs=`$pkg_config --libs libfreenect` + has_freenect="system" + freenect_flags="-DFREENECT_FLAT_HEADERS $freenect_flags" + +else + has_freenect="no" cat > $TMPC << EOF #include @@ -1214,15 +1233,21 @@ if test "$cross_prefix" = "" ; then elif test "$alt_macosx_dir" != "" ; then if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfreenect 2> /dev/null ; then has_freenect="system" + freenect_flags=-I$alt_macosx_dir/include + freenect_ld=-L$alt_macosx_dir/lib -lfreenect fi fi fi if test "$has_freenect" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/mad -L$local_lib -lfreenect 2> /dev/null ; then + if $cc -o $TMPO $TMPC -I$local_inc/freenect -L$local_lib -lfreenect 2> /dev/null ; then has_freenect="local" + freenect_flags=-I$local_inc/freenect + freenect_ld=-L$local_lib -lfreenect fi fi +fi + #look for vorbis support cat > $TMPC << EOF @@ -1283,13 +1308,14 @@ fi #look for OSS support if test "$darwin" = "yes" ; then + cat > $TMPC << EOF #include int main( void ) { return 0; } EOF if $cc -o $TMPO $TMPC -DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss -L$alt_macosx_dir/lib -loss $LDFLAGS 2> /dev/null ; then - has_oss_audio="SYS" + has_oss_audio="yes" OSS_CFLAGS="-DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss" OSS_LDFLAGS="-L$alt_macosx_dir/lib -loss" fi @@ -1305,7 +1331,7 @@ int main( void ) { return 0; } EOF if $cc -o $TMPO $TMPC 2> /dev/null ; then - has_oss_audio="SYS" + has_oss_audio="yes" else cat > $TMPC << EOF #include @@ -1316,7 +1342,7 @@ int main( void ) { return 0; } EOF if $cc -o $TMPO $TMPC $LDFLAGS 2> /dev/null ; then - has_oss_audio="YES" + has_oss_audio="yes" fi fi @@ -1328,44 +1354,44 @@ fi has_wx="no" wx_too_old="no" -if type wx-config >/dev/null 2>&1; then +if test "$cross_prefix" = "" ; then + if type wx-config >/dev/null 2>&1; then - wx_version=`wx-config --version | sed 's/[^0-9]//g'` + wx_version=`wx-config --version | sed 's/[^0-9]//g'` - if test "$wx_version" -lt 250 ; then - wx_too_old="yes" - has_wx="yes" - else - if test "$wx_version" -lt 260 ; then + if test "$wx_version" -lt 250 ; then + wx_too_old="yes" has_wx="yes" - wx_cflags=`wx-config --cppflags` - wx_lflags=`wx-config --libs` else - has_wx="yes" - wx_cflags=`wx-config --cppflags core, base` - wx_lflags=`wx-config --libs core, base` - fi + if test "$wx_version" -lt 260 ; then + has_wx="yes" + wx_cflags=`wx-config --cppflags` + wx_lflags=`wx-config --libs` + else + has_wx="yes" + wx_cflags=`wx-config --cppflags core, base` + wx_lflags=`wx-config --libs core, base` + fi - if test "$darwin" = "yes" ; then - wx_lflags="-Wl,-bind_at_load $wx_lflags -lstdc++" #10.4 needs it, not sure about 10.3 + if test "$darwin" = "yes" ; then + wx_lflags="-Wl,-bind_at_load $wx_lflags -lstdc++" #10.4 needs it, not sure about 10.3 + fi fi - fi - - cat > $TMPCPP << EOF + cat > $TMPCPP << EOF #include int main( void ) { return 0; } EOF - if $cc $wx_cflags -o $TMPO $TMPCPP $wx_lflags > /dev/null 2>&1 ; then - wx_version=`wx-config --version | sed 's/[^0-9]//g'` - if test "$wx_version" -lt 254 ; then - wx_too_old="yes" - else - has_wx="yes" + if $cc $wx_cflags -o $TMPO $TMPCPP $wx_lflags > /dev/null 2>&1 ; then + wx_version=`wx-config --version | sed 's/[^0-9]//g'` + if test "$wx_version" -lt 254 ; then + wx_too_old="yes" + else + has_wx="yes" + fi fi fi - fi #end wx test @@ -1648,7 +1674,7 @@ for opt do --enable-pulseaudio=*) has_pulseaudio="yes" ;; - --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_beng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_mcrypt="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no" + --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_beng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no" ;; --disable-3d) disable_3d="yes" @@ -1757,6 +1783,10 @@ for opt do ;; --enable-od-dump) disable_od_dump="no" ;; + --disable-isom-dump) disable_isom_dump="yes" + ;; + --enable-isom-dump) disable_isom_dump="no" + ;; --disable-mcrypt) disable_mcrypt="yes" ;; --enable-mcrypt) disable_mcrypt="no" @@ -1920,30 +1950,32 @@ if test "$sdl_local" = "yes"; then sdl_static="yes" fi -if type $sdl_config >/dev/null 2>&1; then - cat > $TMPC << EOF +if test "$cross_prefix" = "" ; then + if type $sdl_config >/dev/null 2>&1; then + + cat > $TMPC << EOF #include #undef main int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } EOF - if test "$sdl_static" = "yes"; then - sdl_lib_flags=`$sdl_config --static-libs` - else - sdl_lib_flags=`$sdl_config --libs` - fi - sdl_cflags=`$sdl_config --cflags` - - if $cc -o $TMPO $sdl_cflags $TMPC $LDFLAGS $sdl_lib_flags > /dev/null 2>&1 ; then - _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` - if test "$_sdlversion" -lt 121 ; then - sdl_too_old=yes + if test "$sdl_static" = "yes"; then + sdl_lib_flags=`$sdl_config --static-libs` else - has_sdl=yes + sdl_lib_flags=`$sdl_config --libs` fi - fi + sdl_cflags=`$sdl_config --cflags` + if $cc -o $TMPO $sdl_cflags $TMPC $LDFLAGS $sdl_lib_flags > /dev/null 2>&1 ; then + _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` + if test "$_sdlversion" -lt 121 ; then + sdl_too_old=yes + else + has_sdl=yes + fi + fi + fi fi #end SDL check @@ -2009,6 +2041,10 @@ echo "#define GF_CONFIG_H" >> $TMPH echo "#define GPAC_CONFIGURATION \"$GPAC_CONFIGURATION\"" >> $TMPH version="`grep '#define GPAC_VERSION ' \"$source_path/include/gpac/tools.h\" | cut -d '"' -f 2`" +version_major=`grep '#define GPAC_VERSION_MAJOR ' $source_path/include/gpac/tools.h | sed -e 's/.*\([0-9]\)\+$/\1/'` +version_minor=`grep '#define GPAC_VERSION_MINOR ' $source_path/include/gpac/tools.h | sed -e 's/.*\([0-9]\)\+$/\1/'` +version_micro=`grep '#define GPAC_VERSION_MICRO ' $source_path/include/gpac/tools.h | sed -e 's/.*\([0-9]\)\+$/\1/'` +soname_version="${version_major}.${version_minor}.${version_micro}" if which svnversion >/dev/null then @@ -2141,6 +2177,10 @@ if test "$disable_od_dump" = "yes" ; then echo "OD dump disabled" echo "#define GPAC_DISABLE_OD_DUMP" >> $TMPH fi +if test "$disable_isom_dump" = "yes" ; then + echo "ISOM dump disabled" + echo "#define GPAC_DISABLE_ISOM_DUMP" >> $TMPH +fi if test "$disable_mcrypt" = "yes" ; then echo "MCrypt disabled" echo "#define GPAC_DISABLE_MCRYPT" >> $TMPH @@ -2244,8 +2284,8 @@ if test "$enable_renoir" = "yes" ; then echo "Renoir enabled - make sure the driver libraries are present in modules/viren_out directory" fi -echo "" if test "$has_amr_nb_fixed" = "yes" ; then + echo "" echo "*** AMR NB FIXED-POINT NOTICE ***" echo "Make sure you have downloaded TS26.073 from:" echo "http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-*.zip" @@ -2254,8 +2294,8 @@ if test "$has_amr_nb_fixed" = "yes" ; then echo "" fi -echo "" if test "$has_amr_nb" = "yes" ; then + echo "" echo "*** AMR NB NOTICE ***" echo "Make sure you have downloaded TS26.104 from:" echo "http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-*.zip" @@ -2265,8 +2305,8 @@ if test "$has_amr_nb" = "yes" ; then fi -echo "" if test "$has_amr_wb" = "yes" ; then + echo "" echo "*** AMR WB NOTICE ***" echo "Make sure you have downloaded TS26.204 from:" echo "http://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-*.zip" @@ -2275,6 +2315,7 @@ if test "$has_amr_wb" = "yes" ; then echo "" fi +echo "" if test "$use_memory_tracking" = "yes"; then echo "!! WARNING: GPAC Memory tracking is enabled !!" echo "!! This may corrupt third-party tools using libgpac !!" @@ -2349,6 +2390,8 @@ if test "$bigendian" = "yes" ; then fi echo "EXTRALIBS=$extralibs" >> config.mak echo "VERSION=$version" >>config.mak +echo "VERSION_MAJOR=$version_major" >>config.mak +echo "VERSION_SONAME=$soname_version" >>config.mak if test "$use_fixed_point" = "yes"; then echo "#define GPAC_FIXED_POINT" >> $TMPH @@ -2446,19 +2489,29 @@ echo "CONFIG_JACK=$has_jack" >> config.mak echo "CONFIG_A52=$has_a52" >> config.mak echo "CONFIG_PULSEAUDIO=$has_pulseaudio" >> config.mak echo "CONFIG_FREENECT=$has_freenect" >> config.mak +if test "$has_freenect" != "no" +then + echo "FREENECT_CFLAGS=$freenect_flags" >> config.mak + echo "FREENECT_LDLAGS=$freenect_ld" >> config.mak +fi echo "DISABLE_SVG=$disable_svg" >> config.mak +echo "DISABLE_LOADER_BT=$disable_loader_bt" >> config.mak echo "HAS_LIBXML2=$has_libxml2" >> config.mak if test "$has_libxml2" = "yes"; then echo "XML2_CFLAGS=$libxml2_cflags" >> config.mak echo "XML2_LIBS=$libxml2_lib_flags" >> config.mak fi - +if test "$disable_m2ts_mux" = "yes" -o "$disable_m2ts" = "yes" ; then + echo "DISABLE_M2TS=yes" >> config.mak +fi echo "GPAC_USE_TINYGL=$has_tinygl" >> config.mak echo "OGL_INCLS=$INCL3D" >> config.mak -echo "DISABLE_ISOFF=$disable_isoff" >> config.mak +if test "$disable_isoff" = "yes" -o "$disable_isoff_write" = "yes" ; then + echo "DISABLE_ISOFF=$disable_isoff" >> config.mak +fi echo "HAS_OPENGL=$has_opengl" >> config.mak diff --git a/include/gpac/ait.h b/include/gpac/ait.h index f393fa3..545148e 100644 --- a/include/gpac/ait.h +++ b/include/gpac/ait.h @@ -5,8 +5,6 @@ #ifndef _GF_AIT_H_ #define _GF_AIT_H_ -#ifndef GPAC_DISABLE_MPEG2TS - #ifdef __cplusplus extern "C" { #endif @@ -17,6 +15,9 @@ extern "C" { #include +#ifndef GPAC_DISABLE_MPEG2TS + + #define AIT_SECTION_LENGTH_MAX 1021 #define APPLICATION_TYPE_HTTP_APPLICATION 16 #define DSMCC_SECTION_LENGTH_MAX 4093 @@ -231,10 +232,11 @@ GF_M2TS_ES *gf_ait_section_new(u32 service_id); GF_M2TS_CHANNEL_APPLICATION_INFO* gf_m2ts_get_channel_application_info(GF_List* ChannelAppList, u32 ait_service_id); void gf_m2ts_delete_channel_application_info(GF_M2TS_CHANNEL_APPLICATION_INFO* ChannelApp); +#endif /*GPAC_DISABLE_MPEG2TS*/ + #ifdef __cplusplus } #endif -#endif #endif //_GF_CAROUSSEL_H_ diff --git a/include/gpac/dsmcc.h b/include/gpac/dsmcc.h index 4fd2add..3812761 100644 --- a/include/gpac/dsmcc.h +++ b/include/gpac/dsmcc.h @@ -7,9 +7,6 @@ #ifndef _GF_DSMCC_H_ #define _GF_DSMCC_H_ -#ifndef GPAC_DISABLE_MPEG2TS - - #ifdef __cplusplus extern "C" { #endif @@ -18,6 +15,10 @@ extern "C" { #include #include + +#ifndef GPAC_DISABLE_MPEG2TS + + #define DSMCC_SECTION_LENGTH_MAX 4093 typedef enum{ @@ -626,7 +627,7 @@ typedef struct Bool get_index; /* Number of the application that uses the carousel*/ u32 application_id; -}GF_M2TS_DSMCC_OVERLORD; +} GF_M2TS_DSMCC_OVERLORD; void on_dsmcc_section(GF_M2TS_Demuxer *ts, u32 evt_type, void *par); GF_Err gf_m2ts_process_dsmcc(GF_M2TS_DSMCC_OVERLORD* dsmcc_overlord,GF_M2TS_DSMCC_SECTION *dsmcc, char *data, u32 data_size, u32 table_id); @@ -634,10 +635,11 @@ GF_M2TS_DSMCC_OVERLORD* gf_m2ts_init_dsmcc_overlord(u32 service_id); GF_M2TS_DSMCC_OVERLORD* gf_m2ts_get_dmscc_overlord(GF_List* Dsmcc_controller,u32 service_id); void gf_m2ts_delete_dsmcc_overlord(GF_M2TS_DSMCC_OVERLORD* dsmcc_overlord); +#endif /*GPAC_DISABLE_MPEG2TS*/ + #ifdef __cplusplus } #endif -#endif #endif //_GF_CAROUSSEL_H_ diff --git a/include/gpac/internal/isomedia_dev.h b/include/gpac/internal/isomedia_dev.h index 41fd6bc..fa6e92e 100644 --- a/include/gpac/internal/isomedia_dev.h +++ b/include/gpac/internal/isomedia_dev.h @@ -1865,7 +1865,6 @@ typedef struct __oma_kms_box GF_OMADRMAUFormatBox *fmt; } GF_OMADRMKMSBox; -#ifndef GPAC_DISABLE_ISOM_FRAGMENTS typedef struct { @@ -1888,7 +1887,6 @@ typedef struct __sidx_box u32 nb_refs; GF_SIDXReference *refs; } GF_SegmentIndexBox; -#endif @@ -3421,12 +3419,14 @@ GF_Err subs_Size(GF_Box *s); GF_Err subs_Read(GF_Box *s, GF_BitStream *bs); GF_Err subs_dump(GF_Box *a, FILE * trace); +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS GF_Box *tfdt_New(); void tfdt_del(GF_Box *); GF_Err tfdt_Write(GF_Box *s, GF_BitStream *bs); GF_Err tfdt_Size(GF_Box *s); GF_Err tfdt_Read(GF_Box *s, GF_BitStream *bs); GF_Err tfdt_dump(GF_Box *a, FILE * trace); +#endif GF_Box *rvcc_New(); void rvcc_del(GF_Box *); diff --git a/include/gpac/internal/smjs_api.h b/include/gpac/internal/smjs_api.h index 057dc49..03cd58b 100644 --- a/include/gpac/internal/smjs_api.h +++ b/include/gpac/internal/smjs_api.h @@ -62,11 +62,8 @@ #define SMJS_FREE(__c, __str) if (__str) JS_free(__c, __str) -#define SMJS_OBJ_CONSTRUCTOR JSObject *obj = NULL;\ - if (!JS_IsConstructing_PossiblyWithGivenThisObject(c, argsvp, &obj)) { \ - return JS_FALSE;\ - }\ - if (obj == NULL) obj = JS_NewObjectForConstructor(c, argsvp); \ +#define SMJS_OBJ_CONSTRUCTOR \ + JSObject *obj = JS_NewObjectForConstructor(c, argsvp); \ SMJS_SET_RVAL(OBJECT_TO_JSVAL(obj));\ #define JS_GetFunctionName(_v) (JS_GetFunctionId(_v)!=NULL) ? SMJS_CHARS_FROM_STRING(c, JS_GetFunctionId(_v)) : NULL diff --git a/include/gpac/isomedia.h b/include/gpac/isomedia.h index c64d5d7..6010705 100644 --- a/include/gpac/isomedia.h +++ b/include/gpac/isomedia.h @@ -1091,7 +1091,7 @@ GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables); if end_range>start_range, restricts the URL to the given byterange when parsing*/ GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range); -#ifndef GPAC_DISBALE_ISOM_FRAGMENTS +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS /* Movie Fragments Writing API @@ -1223,7 +1223,7 @@ GF_Err gf_isom_fragment_append_data(GF_ISOFile *the_file, u32 TrackID, char *dat void gf_isom_reset_fragment_info(GF_ISOFile *movie); -#endif /*GPAC_DISBALE_ISOM_FRAGMENTS*/ +#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ /****************************************************************** diff --git a/include/gpac/media_tools.h b/include/gpac/media_tools.h index 8c4a3f3..a9bf5c7 100644 --- a/include/gpac/media_tools.h +++ b/include/gpac/media_tools.h @@ -38,6 +38,7 @@ extern "C" { /*creates (if needed) a GF_ESD for the given track - THIS IS RESERVED for local playback only, since the OTI used when emulated is not standard...*/ GF_ESD *gf_media_map_esd(GF_ISOFile *mp4, u32 track); + #endif @@ -224,11 +225,6 @@ GF_Err gf_media_import(GF_MediaImporter *importer); /*adds chapter info contained in file - import_fps is optional (most formats don't use it), defaults to 25*/ GF_Err gf_media_import_chapters(GF_ISOFile *file, char *chap_file, Double import_fps); - -/*save file as fragmented movie -@dash_mode: 0 = DASH not used, 1 = DASH used without GOP spliting, 2 = DASH used with GOP spliting, */ -GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file_radical, const char *mpd_name, Double max_duration_sec, u32 dash_mode, Double dash_duration_sec, char *seg_rad_name, char *seg_ext, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool use_url_template, Bool use_single_segment, const char *dash_ctx, GF_ISOFile *sample_descs, u32 rep_id); - /*make the file ISMA compliant: creates ISMA BIFS / OD tracks if needed, and update audio/video IDs the file should not contain more than one audio and one video track @keepImage: if set, generates system info if image is found - only used for image imports @@ -243,9 +239,6 @@ GF_Err gf_media_make_3gpp(GF_ISOFile *mp4file); */ GF_Err gf_media_make_psp(GF_ISOFile *mp4file); -/*changes pixel aspect ratio for visual tracks if supported. Negative values remove any PAR info*/ -GF_Err gf_media_change_par(GF_ISOFile *file, u32 track, s32 ar_num, s32 ar_den); - /*changes the profile (if not 0) and level (if not 0) indication of the media - only AVC/H264 supported for now*/ GF_Err gf_media_change_pl(GF_ISOFile *file, u32 track, u32 profile, u32 level); @@ -255,6 +248,24 @@ GF_Err gf_media_avc_rewrite_samples(GF_ISOFile *file, u32 track, u32 prev_size_i #endif /*GPAC_DISABLE_MEDIA_IMPORT*/ +/*changes pixel aspect ratio for visual tracks if supported. Negative values remove any PAR info*/ +GF_Err gf_media_change_par(GF_ISOFile *file, u32 track, s32 ar_num, s32 ar_den); + + +#ifndef GPAC_DISABLE_ISOM_WRITE + +/*starts MPD file */ +GF_Err gf_media_mpd_start(char *mpd_name, char *title, Bool use_url_template, Bool single_segment, char *dash_ctx, GF_ISOFile *init_segment, Double period_duration); +GF_Err gf_media_mpd_end(char *mpd_name); + +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS +/*save file as fragmented movie +@dash_mode: 0 = DASH not used, 1 = DASH used without GOP spliting, 2 = DASH used with GOP spliting, */ +GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file_radical, const char *mpd_name, Double max_duration_sec, u32 dash_mode, Double dash_duration_sec, char *seg_rad_name, char *seg_ext, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool use_url_template, Bool use_single_segment, const char *dash_ctx, GF_ISOFile *sample_descs, u32 rep_id); +#endif + +#endif + #ifndef GPAC_DISABLE_MEDIA_EXPORT @@ -391,8 +402,6 @@ if force_end_of_session is set, this flushes the SAF Session - no more operation GF_Err gf_saf_mux_for_time(GF_SAFMuxer *mux, u32 time_ms, Bool force_end_of_session, char **out_data, u32 *out_size); -GF_Err gf_media_mpd_start(char *mpd_name, char *title, Bool use_url_template, Bool single_segment, char *dash_ctx, char *init_segment, Double period_duration); -GF_Err gf_media_mpd_end(char *mpd_name); #ifdef __cplusplus } diff --git a/include/gpac/rtp_streamer.h b/include/gpac/rtp_streamer.h index 7a96f2d..77584f3 100644 --- a/include/gpac/rtp_streamer.h +++ b/include/gpac/rtp_streamer.h @@ -46,7 +46,7 @@ extern "C" { #include #include -#ifndef GPAC_DISABLE_STREAMING +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_ISOM) typedef struct __rtp_streamer GF_RTPStreamer; @@ -108,7 +108,7 @@ GF_Err gf_rtp_streamer_send_rtcp(GF_RTPStreamer *streamer, Bool force_ts, u32 rt } #endif -#endif //GPAC_DISABLE_STREAMING +#endif //GPAC_DISABLE_ISOM && GPAC_DISABLE_STREAMING #endif /*_GF_RTPSTREAMER_H_*/ diff --git a/include/gpac/setup.h b/include/gpac/setup.h index 437f8dd..7c7c0a4 100644 --- a/include/gpac/setup.h +++ b/include/gpac/setup.h @@ -449,6 +449,15 @@ void gf_memory_print(void); /*prints the state of current allocations*/ # ifndef GPAC_DISABLE_MPEG2PS # define GPAC_DISABLE_MPEG2PS # endif +# ifndef GPAC_DISABLE_ISOM_HINTING +# define GPAC_DISABLE_ISOM_HINTING +# endif +# ifndef GPAC_DISABLE_MEDIA_IMPORT +# define GPAC_DISABLE_MEDIA_IMPORT +# endif +# ifndef GPAC_DISABLE_MPEG2TS_MUX +# define GPAC_DISABLE_MPEG2TS_MUX +# endif #endif #ifdef GPAC_DISABLE_ISOM @@ -467,12 +476,27 @@ void gf_memory_print(void); /*prints the state of current allocations*/ # ifndef GPAC_DISABLE_ISOM_DUMP # define GPAC_DISABLE_ISOM_DUMP # endif +# ifndef GPAC_DISABLE_LOADER_ISOM +# define GPAC_DISABLE_LOADER_ISOM +# endif +# ifndef GPAC_DISABLE_MEDIA_EXPORT +# define GPAC_DISABLE_MEDIA_EXPORT +# endif #endif #ifdef GPAC_DISABLE_ISOM_WRITE # ifndef GPAC_DISABLE_MEDIA_IMPORT # define GPAC_DISABLE_MEDIA_IMPORT # endif +# ifndef GPAC_DISABLE_QTVR +# define GPAC_DISABLE_QTVR +# endif +# ifndef GPAC_DISABLE_ISOM_HINTING +# define GPAC_DISABLE_ISOM_HINTING +# endif +# ifndef GPAC_DISABLE_SCENE_ENCODER +# define GPAC_DISABLE_SCENE_ENCODER +# endif #endif #ifdef GPAC_DISABLE_STREAMING diff --git a/include/gpac/tools.h b/include/gpac/tools.h index 72b2460..11af405 100644 --- a/include/gpac/tools.h +++ b/include/gpac/tools.h @@ -57,8 +57,14 @@ extern "C" { * * Macro giving GPAC version expressed as a printable string */ -/*KEEP SPACE SEPARATORS FOR MAKE / GREP (SEE MAIN MAKEFILE)!!!, and NO SPACE in GPAC_VERSION for proper install*/ -#define GPAC_VERSION "0.4.6-DEV" +/* KEEP SPACE SEPARATORS FOR MAKE / GREP (SEE MAIN MAKEFILE) + * NO SPACE in GPAC_VERSION for proper install + * SONAME versions must be digits (not strings) + */ +#define GPAC_VERSION "0.4.6-DEV" +#define GPAC_VERSION_MAJOR 1 +#define GPAC_VERSION_MINOR 1 +#define GPAC_VERSION_MICRO 0 #include #define GPAC_FULL_VERSION GPAC_VERSION"-rev"GPAC_SVN_REVISION diff --git a/modules/Makefile b/modules/Makefile index acd7af0..5de07db 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -1,10 +1,13 @@ include ../config.mak #all OS and lib independent -PLUGDIRS=aac_in ac3_in audio_filter bifs_dec ctx_load dummy_in soft_raster mp3_in isom_in odf_dec rtp_in timedtext img_in svg_in saf_in mpegts_in ismacryp widgetman mpd_in osd +PLUGDIRS=aac_in ac3_in audio_filter bifs_dec ctx_load dummy_in soft_raster mp3_in isom_in odf_dec rtp_in timedtext img_in svg_in saf_in mpegts_in ismacryp mpd_in ifeq ($(DISABLE_SVG), no) -PLUGDIRS+=laser_dec svg_in +PLUGDIRS+=laser_dec svg_in widgetman +ifeq ($(DISABLE_LOADER_BT),no) +PLUGDIRS+=osd +endif endif ifeq ($(CONFIG_FT), no) diff --git a/modules/dx_hw/dx_2d.c b/modules/dx_hw/dx_2d.c index 0ce8e59..6a21969 100644 --- a/modules/dx_hw/dx_2d.c +++ b/modules/dx_hw/dx_2d.c @@ -122,10 +122,13 @@ GF_Err CreateBackBuffer(GF_VideoOutput *dr, u32 Width, u32 Height, Bool use_syst DDCONTEXT; opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "HardwareMemory"); - if (use_system_memory) { - if (opt && !strcmp(opt, "Always")) use_system_memory = 0; - } else { - if (opt && !strcmp(opt, "Never")) use_system_memory = 1; + if (opt) { + if (use_system_memory) { + if (!strcmp(opt, "Always")) use_system_memory = 0; + } else { + if (!strcmp(opt, "Never")) use_system_memory = 1; + else if (!strcmp(opt, "Auto")) dd->force_video_mem_for_yuv = 1; + } } force_reinit = 0; @@ -190,6 +193,7 @@ GF_Err CreateBackBuffer(GF_VideoOutput *dr, u32 Width, u32 Height, Bool use_syst return GF_OK; } + GF_Err InitDirectDraw(GF_VideoOutput *dr, u32 Width, u32 Height) { HRESULT hr; @@ -210,6 +214,7 @@ GF_Err InitDirectDraw(GF_VideoOutput *dr, u32 Width, u32 Height) ddraw->lpVtbl->Release(ddraw); if (FAILED(hr)) return GF_IO_ERR; + dd->switch_res = 0; cooplev = DDSCL_NORMAL; /*Setup FS*/ @@ -292,6 +297,7 @@ GF_Err InitDirectDraw(GF_VideoOutput *dr, u32 Width, u32 Height) return GF_IO_ERR; } pcClipper->lpVtbl->Release(pcClipper); + dd->ddraw_init = 1; /*if YUV not initialize, init using HW video memory to setup HW caps*/ return CreateBackBuffer(dr, Width, Height, dd->yuv_init); @@ -393,6 +399,9 @@ static GF_Err DD_BlitSurface(DDContext *dd, DDSurface *src, GF_Window *src_wnd, if (key) flags |= DDBLT_KEYSRC; hr = dd->pBack->lpVtbl->Blt(dd->pBack, dst_wnd ? &r_dst : NULL, src->pSurface, src_wnd ? &r_src : NULL, flags, NULL); } + + if (src->is_yuv && dd->force_video_mem_for_yuv && dd->systems_memory) return GF_IO_ERR; + GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[DX Out] Hardware blit src w=%d,h=%d to dst w=%d,h=%d - result: %08x\n", src_w, src_h, dst_w, dst_h, hr)); return FAILED(hr) ? GF_IO_ERR : GF_OK; } @@ -422,6 +431,7 @@ static DDSurface *DD_GetSurface(GF_VideoOutput *dr, u32 width, u32 height, u32 p SAFE_DD_RELEASE(yuvp->pSurface); memset(yuvp, 0, sizeof(DDSurface)); + yuvp->is_yuv = 1; memset (&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); @@ -688,6 +698,7 @@ void DD_InitYUV(GF_VideoOutput *dr) if (dd->yuv_pool.pSurface) { SAFE_DD_RELEASE(dd->yuv_pool.pSurface); memset(&dd->yuv_pool, 0, sizeof(DDSurface)); + dd->yuv_pool.is_yuv = 1; } dr->yuv_pixel_format = formats[i]; @@ -734,6 +745,7 @@ rem_fmt: if (dd->yuv_pool.pSurface) { SAFE_DD_RELEASE(dd->yuv_pool.pSurface); memset(&dd->yuv_pool, 0, sizeof(DDSurface)); + dd->yuv_pool.is_yuv = 1; } if (best_planar && (min_planar <= min_packed )) { diff --git a/modules/dx_hw/dx_hw.h b/modules/dx_hw/dx_hw.h index d6ba1be..12bb34a 100644 --- a/modules/dx_hw/dx_hw.h +++ b/modules/dx_hw/dx_hw.h @@ -91,6 +91,7 @@ typedef struct { LPDDRAWSURFACE pSurface; u32 width, height, format, pitch; + Bool is_yuv; } DDSurface; @@ -181,11 +182,10 @@ typedef struct Bool windowless, hidden; Bool dd_lost; - + Bool force_video_mem_for_yuv; HMODULE hDDrawLib; DIRECTDRAWCREATEPROC DirectDrawCreate; - } DDContext; void DD_SetupWindow(GF_VideoOutput *dr, Bool hide); diff --git a/modules/dx_hw/dx_video.c b/modules/dx_hw/dx_video.c index 1280ba3..2ccce39 100644 --- a/modules/dx_hw/dx_video.c +++ b/modules/dx_hw/dx_video.c @@ -167,6 +167,7 @@ void DestroyObjectsEx(DDContext *dd, Bool only_3d) memset(&dd->rgb_pool, 0, sizeof(DDSurface)); SAFE_DD_RELEASE(dd->yuv_pool.pSurface); memset(&dd->yuv_pool, 0, sizeof(DDSurface)); + dd->yuv_pool.is_yuv = 1; SAFE_DD_RELEASE(dd->pPrimary); SAFE_DD_RELEASE(dd->pBack); diff --git a/modules/ffmpeg_in/ffmpeg_decode.c b/modules/ffmpeg_in/ffmpeg_decode.c index c2ff738..db7d65e 100644 --- a/modules/ffmpeg_in/ffmpeg_decode.c +++ b/modules/ffmpeg_in/ffmpeg_decode.c @@ -1021,9 +1021,9 @@ static u32 FFDEC_CanHandleStream(GF_BaseDecoder *plug, u32 StreamType, GF_ESD *e static const char *FFDEC_GetCodecName(GF_BaseDecoder *dec) { FFDec *ffd; - if (!dec) - return NULL; - ffd = dec->privateStack; + if (!dec) + return NULL; + ffd = dec->privateStack; if (ffd && ffd->base_codec) { sprintf(ffd->szCodec, "FFMPEG %s", ffd->base_codec->name ? ffd->base_codec->name : "unknown"); return ffd->szCodec; @@ -1038,10 +1038,12 @@ void *FFDEC_Load() FFDec *priv; /* Note for valgrind : those two functions cause a leak in valgrind */ - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[FFMPEG Decoder] Registering all ffmpeg codecs...\n") ); + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[FFMPEG Decoder] Registering all ffmpeg codecs...\n") ); +#ifdef FF_API_AVCODE_INIT /*commit ffmpeg 3211932c513338566b31d990d06957e15a644d13*/ avcodec_init(); +#endif avcodec_register_all(); - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG Decoder] Done registering all ffmpeg codecs.\n") ); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG Decoder] Done registering all ffmpeg codecs.\n") ); GF_SAFEALLOC(ptr , GF_MediaDecoder); diff --git a/modules/ffmpeg_in/ffmpeg_demux.c b/modules/ffmpeg_in/ffmpeg_demux.c index 6f0e71f..9e801f9 100644 --- a/modules/ffmpeg_in/ffmpeg_demux.c +++ b/modules/ffmpeg_in/ffmpeg_demux.c @@ -90,7 +90,7 @@ static u32 FFDemux_Run(void *par) pkt.stream_index = -1; /*EOF*/ - if (av_read_frame(ffd->ctx, &pkt) <0) break; + if (av_read_frame(ffd->ctx, &pkt) <0) break; if (pkt.pts == AV_NOPTS_VALUE) pkt.pts = pkt.dts; if (!pkt.dts) pkt.dts = pkt.pts; @@ -230,8 +230,8 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) Bool ret = 0; char *ext, szName[1000], szExt[20]; const char *szExtList; - if (!plug || !url) - return 0; + if (!plug || !url) + return 0; /*disable RTP/RTSP from ffmpeg*/ if (!strnicmp(url, "rtsp://", 7)) return 0; if (!strnicmp(url, "rtspu://", 8)) return 0; @@ -294,19 +294,19 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) /*figure out if we can use codecs or not*/ has_video = has_audio = 0; - for(i = 0; i < (s32)ctx->nb_streams; i++) { - AVCodecContext *enc = ctx->streams[i]->codec; - switch(enc->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (!has_audio) has_audio = 1; - break; - case AVMEDIA_TYPE_VIDEO: - if (!has_video) has_video= 1; - break; - default: - break; - } - } + for(i = 0; i < (s32)ctx->nb_streams; i++) { + AVCodecContext *enc = ctx->streams[i]->codec; + switch(enc->codec_type) { + case AVMEDIA_TYPE_AUDIO: + if (!has_audio) has_audio = 1; + break; + case AVMEDIA_TYPE_VIDEO: + if (!has_video) has_video= 1; + break; + default: + break; + } + } if (!has_audio && !has_video) goto exit; ret = 1; #if LIBAVFORMAT_VERSION_MAJOR < 53 && LIBAVFORMAT_VERSION_MINOR < 45 @@ -354,9 +354,9 @@ static GF_ESD *FFD_GetESDescriptor(FFDemux *ffd, Bool for_audio) /*remap std object types - depending on input formats, FFMPEG may not have separate DSI from initial frame. In this case we have no choice but using FFMPEG decoders*/ if (for_audio) { - AVCodecContext *dec = ffd->ctx->streams[ffd->audio_st]->codec; + AVCodecContext *dec = ffd->ctx->streams[ffd->audio_st]->codec; esd->slConfig->timestampResolution = ffd->audio_tscale.den; - switch (dec->codec_id) { + switch (dec->codec_id) { case CODEC_ID_MP2: esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1; break; @@ -395,7 +395,7 @@ opaque_audio: } dont_use_sl = ffd->unreliable_audio_timing; } else { - AVCodecContext *dec = ffd->ctx->streams[ffd->video_st]->codec; + AVCodecContext *dec = ffd->ctx->streams[ffd->video_st]->codec; esd->slConfig->timestampResolution = ffd->video_tscale.den; switch (dec->codec_id) { case CODEC_ID_MPEG4: @@ -569,7 +569,7 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG] opening file %s - local %d - av_in %08x\n", url, is_local, av_in)); if (!is_local) { - AVProbeData pd; + AVProbeData pd; /*setup wraper for FFMPEG I/O*/ ffd->buffer_size = 8192; @@ -579,12 +579,8 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, #ifdef FFMPEG_DUMP_REMOTE ffd->outdbg = gf_f64_open("ffdeb.raw", "wb"); #endif -/*#ifdef USE_PRE_0_7*/ - init_put_byte(&ffd->io, ffd->buffer, ffd->buffer_size, 0, ffd, ff_url_read, NULL, NULL); -/*#else - ffio_init_context(&ffd->io, ffd->buffer, ffd->buffer_size, 0, ffd, ff_url_read, NULL, NULL); -#endif*/ #ifdef USE_PRE_0_7 + init_put_byte(&ffd->io, ffd->buffer, ffd->buffer_size, 0, ffd, ff_url_read, NULL, NULL); ffd->io.is_streamed = 1; #else ffd->io.seekable = 1; @@ -616,7 +612,11 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, } /*setup downloader*/ av_in->flags |= AVFMT_NOFILE; +#if FF_API_FORMAT_PARAMETERS /*commit ffmpeg 603b8bc2a109978c8499b06d2556f1433306eca7*/ + res = avformat_open_input(&ffd->ctx, szName, av_in, NULL); +#else res = av_open_input_stream(&ffd->ctx, &ffd->io, szName, av_in, NULL); +#endif } } else { res = open_file(&ffd->ctx, szName, av_in); @@ -645,25 +645,25 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, /*figure out if we can use codecs or not*/ ffd->audio_st = ffd->video_st = -1; - for (i = 0; i < ffd->ctx->nb_streams; i++) { - AVCodecContext *enc = ffd->ctx->streams[i]->codec; - switch(enc->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if ((ffd->audio_st<0) && (ffd->service_type!=1)) { + for (i = 0; i < ffd->ctx->nb_streams; i++) { + AVCodecContext *enc = ffd->ctx->streams[i]->codec; + switch(enc->codec_type) { + case AVMEDIA_TYPE_AUDIO: + if ((ffd->audio_st<0) && (ffd->service_type!=1)) { ffd->audio_st = i; ffd->audio_tscale = ffd->ctx->streams[i]->time_base; } - break; - case AVMEDIA_TYPE_VIDEO: - if ((ffd->video_st<0) && (ffd->service_type!=2)) { + break; + case AVMEDIA_TYPE_VIDEO: + if ((ffd->video_st<0) && (ffd->service_type!=2)) { ffd->video_st = i; ffd->video_tscale = ffd->ctx->streams[i]->time_base; } - break; - default: - break; - } - } + break; + default: + break; + } + } if ((ffd->service_type==1) && (ffd->video_st<0)) goto err_exit; if ((ffd->service_type==2) && (ffd->audio_st<0)) goto err_exit; if ((ffd->video_st<0) && (ffd->audio_st<0)) { @@ -911,12 +911,12 @@ static Bool FFD_CanHandleURLInService(GF_InputService *plug, const char *url) char szURL[2048], *sep; FFDemux *ffd; const char *this_url; - if (!plug || !url) - return 0; - ffd = (FFDemux *)plug->priv; - this_url = gf_term_get_service_url(ffd->service); + if (!plug || !url) + return 0; + ffd = (FFDemux *)plug->priv; + this_url = gf_term_get_service_url(ffd->service); if (!this_url) - return 0; + return 0; strcpy(szURL, this_url); sep = strrchr(szURL, '#'); @@ -965,19 +965,19 @@ void Delete_FFMPEG_Demux(void *ifce) { FFDemux *ffd; GF_InputService *ptr = (GF_InputService *)ifce; - if (!ptr) - return; + if (!ptr) + return; ffd = ptr->priv; - if (ffd){ - if (ffd->thread) - gf_th_del(ffd->thread); - ffd->thread = NULL; - if (ffd->mx) - gf_mx_del(ffd->mx); - ffd->mx = NULL; - gf_free(ffd); - ptr->priv = NULL; - } + if (ffd) { + if (ffd->thread) + gf_th_del(ffd->thread); + ffd->thread = NULL; + if (ffd->mx) + gf_mx_del(ffd->mx); + ffd->mx = NULL; + gf_free(ffd); + ptr->priv = NULL; + } gf_free(ptr); } diff --git a/modules/freenect/freenect.c b/modules/freenect/freenect.c index bf4b9cf..d7dcdd3 100644 --- a/modules/freenect/freenect.c +++ b/modules/freenect/freenect.c @@ -29,10 +29,20 @@ #include #include +#ifdef FREENECT_FLAT_HEADERS +#include +#else #include +#endif #include + +#ifndef FREENECT_RESOLUTION_MEDIUM +#define FREENECT_MINIMAL +#endif + + typedef struct { /*the service we're responsible for*/ @@ -240,9 +250,10 @@ GF_Err Freenect_ConnectService(GF_InputService *plug, GF_ClientService *serv, co if (!vcap->f_ctx) { int i; - Bool use_depth = 1; +#ifndef FREENECT_MINIMAL freenect_frame_mode frame_mode; freenect_resolution frame_format = FREENECT_RESOLUTION_MEDIUM; +#endif char *name, *params; int res = freenect_init(&vcap->f_ctx, NULL); if (res < 0) { @@ -251,8 +262,9 @@ GF_Err Freenect_ConnectService(GF_InputService *plug, GF_ClientService *serv, co } freenect_set_log_level(vcap->f_ctx, FREENECT_LOG_DEBUG); freenect_set_log_callback(vcap->f_ctx, Freenect_Logs); +#ifndef FREENECT_MINIMAL freenect_select_subdevices(vcap->f_ctx, FREENECT_DEVICE_CAMERA); - +#endif res = freenect_num_devices (vcap->f_ctx); GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Freenect] %d devices found\n", res)); if (res<1) { @@ -273,7 +285,6 @@ GF_Err Freenect_ConnectService(GF_InputService *plug, GF_ClientService *serv, co if (name) name += 3; if (!stricmp(name, "color")) { - use_depth = 0; } if (params) { @@ -287,12 +298,14 @@ GF_Err Freenect_ConnectService(GF_InputService *plug, GF_ClientService *serv, co GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[VideoCapture] Set camera option %s\n", params)); if (!strnicmp(params, "resolution=", 11)) { +#ifndef FREENECT_MINIMAL u32 w, h; if (sscanf(params+11, "%dx%d", &w, &h)==2) { if ((w<=320) || (h<=240)) frame_format = FREENECT_RESOLUTION_LOW; else if ((w<=640) || (h<=480)) frame_format = FREENECT_RESOLUTION_MEDIUM; else frame_format = FREENECT_RESOLUTION_HIGH; } +#endif } else if (!strnicmp(params, "format=", 7)) { if (!stricmp(params+7, "standard")) vcap->depth_format = 0; @@ -312,13 +325,20 @@ GF_Err Freenect_ConnectService(GF_InputService *plug, GF_ClientService *serv, co params = sep+1; } +#ifndef FREENECT_MINIMAL frame_mode = freenect_find_video_mode(frame_format, FREENECT_VIDEO_RGB); res = freenect_set_video_mode(vcap->f_dev, frame_mode); res = freenect_set_depth_mode(vcap->f_dev, freenect_find_depth_mode(frame_format, FREENECT_DEPTH_11BIT)); - vcap->width = frame_mode.width; vcap->height = frame_mode.height; vcap->fps = frame_mode.framerate; +#else + freenect_set_video_format(vcap->f_dev, FREENECT_VIDEO_RGB); + res = freenect_set_depth_format(vcap->f_dev, FREENECT_DEPTH_11BIT); + vcap->width = FREENECT_FRAME_W; + vcap->height = FREENECT_FRAME_H; + vcap->fps = 30; +#endif /*currently hardcoded*/ vcap->color_pixel_format = GF_PIXEL_RGB_24; vcap->color_stride = 3*vcap->width; @@ -353,7 +373,7 @@ GF_Err Freenect_ConnectService(GF_InputService *plug, GF_ClientService *serv, co res = freenect_set_video_buffer(vcap->f_dev, vcap->vid_buf); - GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Freenect] Device configured - resolution %dx%d - Frame Rate %d - Depth Pixel Format %s\n", vcap->width, vcap->height, vcap->fps, gf_4cc_to_str(vcap->depth_pixel_format) )); + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Freenect] Device configured - resolution %dx%d - Frame Rate %d - Depth Pixel Format %s\n", vcap->width, vcap->height, vcap->fps, gf_4cc_to_str(vcap->depth_pixel_format) )); for (i=0; i<2048; i++) { diff --git a/modules/gpac_js/gpac_js.c b/modules/gpac_js/gpac_js.c index 0591097..10937c1 100644 --- a/modules/gpac_js/gpac_js.c +++ b/modules/gpac_js/gpac_js.c @@ -674,7 +674,9 @@ static JSBool gpacevt_getProperty(JSContext *c, JSObject *obj, SMJS_PROP_GETTER, *vp = INT_TO_JSVAL(evt->type); break; case 1: +#ifndef GPAC_DISABLE_SVG *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, gf_dom_get_key_name(evt->key.key_code) )); +#endif break; case 2: *vp = INT_TO_JSVAL(evt->mouse.x); @@ -760,7 +762,7 @@ static JSBool SMJS_FUNCTION(gpac_set_event_filter) SMJS_ARGS GF_GPACJSExt *gjs = (GF_GPACJSExt *)JS_GetPrivate(c, obj); if (!argc || !JSVAL_IS_OBJECT(argv[0])) return JS_FALSE; - if (gjs->evt_fun) return JS_TRUE; + if (JSVAL_IS_NULL(gjs->evt_fun) ) return JS_TRUE; gjs->evt_fun = argv[0]; gjs->evt_filter_obj = obj; @@ -814,13 +816,17 @@ static JSBool SMJS_FUNCTION(gpac_get_scene) if (!elt) return JS_TRUE; switch (elt->sgprivate->tag) { case TAG_MPEG4_Inline: +#ifndef GPAC_DISABLE_X3D case TAG_X3D_Inline: +#endif scene = (GF_Scene *)gf_node_get_private(elt); break; +#ifndef GPAC_DISABLE_SVG case TAG_SVG_animation: sg = gf_sc_animation_get_scenegraph(elt); scene = (GF_Scene *)gf_sg_get_private(sg); break; +#endif default: return JS_TRUE; } diff --git a/modules/isom_in/read_ch.c b/modules/isom_in/read_ch.c index 8328e3c..3011102 100644 --- a/modules/isom_in/read_ch.c +++ b/modules/isom_in/read_ch.c @@ -201,6 +201,7 @@ void isor_reader_get_sample(ISOMChannel *ch) gf_isom_sample_del(&ch->sample); if (s2 && s1) { + assert(s2->DTS >= s1->DTS); time_diff = (u32) (s2->DTS - s1->DTS); e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + time_diff, &ivar, GF_ISOM_SEARCH_FORWARD, &ch->sample, &ch->sample_num); } else if (s1 && !s2) { diff --git a/modules/mpd_in/mpd_in.c b/modules/mpd_in/mpd_in.c index c7734f1..48d4751 100644 --- a/modules/mpd_in/mpd_in.c +++ b/modules/mpd_in/mpd_in.c @@ -152,16 +152,17 @@ typedef struct __mpd_module { /* 0 not started, 1 download in progress */ MPD_STATE mpd_is_running; Bool mpd_stop_request; - + Bool in_period_setup; /* TODO - handle playback status for SPEED/SEEK through SIDX */ Double playback_speed, playback_start_range, previous_start_range; + Double start_range_in_segment_at_next_period; Bool in_seek; } GF_MPD_In; void MPD_ResetGroups(GF_MPD_In *mpdin); GF_Err MPD_SetupPeriod(GF_MPD_In *mpdin); -void MPD_SeekGroupsDownloads(GF_MPD_In *mpdin); + static const char *MPD_GetMimeType(GF_MPD_SubRepresentation *subrep, GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set) @@ -551,6 +552,7 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) return GF_OK; } if (param->command_type==GF_NET_SERVICE_QUERY_NEXT) { + Bool discard_first_cache_entry = 1; u32 timer = gf_sys_clock(); GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[MPD_IN] Received Service Query Next request from terminal\n")); gf_mx_p(mpdin->dl_mutex); @@ -560,6 +562,7 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) if (mpdin->in_seek) { mpdin->in_seek = 0; param->url_query.discontinuity_type = 2; + discard_first_cache_entry = 0; } for (i=0; igroups); i++) { @@ -578,7 +581,7 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) while (mpdin->mpd_is_running && group->nb_cached_segments<2) { gf_mx_v(mpdin->dl_mutex); if (group->done) { - if (!mpdin->request_period_switch && (mpdin->active_period_indexmpd->periods))) { + if (!mpdin->request_period_switch && (mpdin->active_period_index+1 < gf_list_count(mpdin->mpd->periods))) { GF_NetworkCommand com; memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_BUFFER_QUERY; @@ -590,7 +593,7 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) } gf_sleep(20); } - } + } return GF_EOS; } gf_sleep(16); @@ -603,25 +606,29 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[MPD_IN] Had to wait for %u ms for the only cache file to be downloaded\n", (gf_sys_clock() - timer))); } - if (group->cached[0].cache) { - if (group->urlToDeleteNext) { - if (!group->local_files && !mpdin->keep_files) - gf_dm_delete_cached_file_entry_session(group->segment_dnload, group->urlToDeleteNext); - gf_free( group->urlToDeleteNext); - group->urlToDeleteNext = NULL; - } - assert( group->cached[0].url ); - GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[MPD_IN] deleting cache file %s : %s\n", group->cached[0].url, group->cached[0].cache)); - group->urlToDeleteNext = gf_strdup( group->cached[0].url ); - gf_free(group->cached[0].cache); - gf_free(group->cached[0].url); - group->cached[0].url = NULL; - group->cached[0].cache = NULL; - } - memmove(&group->cached[0], &group->cached[1], sizeof(segment_cache_entry)*(group->nb_cached_segments-1)); - memset(&(group->cached[group->nb_cached_segments-1]), 0, sizeof(segment_cache_entry)); - group->nb_cached_segments--; + if (discard_first_cache_entry) { + if (group->cached[0].cache) { + if (group->urlToDeleteNext) { + if (!group->local_files && !mpdin->keep_files) + gf_dm_delete_cached_file_entry_session(group->segment_dnload, group->urlToDeleteNext); + + gf_free( group->urlToDeleteNext); + group->urlToDeleteNext = NULL; + } + assert( group->cached[0].url ); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[MPD_IN] deleting cache file %s : %s\n", group->cached[0].url, group->cached[0].cache)); + group->urlToDeleteNext = gf_strdup( group->cached[0].url ); + gf_free(group->cached[0].cache); + gf_free(group->cached[0].url); + group->cached[0].url = NULL; + group->cached[0].cache = NULL; + } + memmove(&group->cached[0], &group->cached[1], sizeof(segment_cache_entry)*(group->nb_cached_segments-1)); + memset(&(group->cached[group->nb_cached_segments-1]), 0, sizeof(segment_cache_entry)); + group->nb_cached_segments--; + } + param->url_query.next_url = group->cached[0].cache; param->url_query.start_range = group->cached[0].start_range; param->url_query.end_range = group->cached[0].end_range; @@ -755,47 +762,14 @@ GF_Err MPD_downloadWithRetry( GF_ClientService * service, GF_DownloadSession **s } } -static void MPD_SetGroupRepresentation(GF_MPD_Group *group, GF_MPD_Representation *rep) +static void MPD_GetSegmentDuration(GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set, GF_MPD_Period *period, GF_MPD *mpd, u32 *nb_segments, Double *seg_duration) { - u64 duration = 0; - u64 mediaDuration = 0; -#ifndef GPAC_DISABLE_LOG - u32 width=0, height=0, samplerate=0; - GF_MPD_Fractional *framerate=NULL; -#endif - u32 timescale = 1; - GF_MPD_AdaptationSet *set; - GF_MPD_Period *period; - u32 i = gf_list_find(group->adaptation_set->representations, rep); - assert((s32) i >= 0); - - group->active_rep_index = i; - group->active_bitrate = rep->bandwidth; - group->nb_segments_in_rep = 1; - - set = group->adaptation_set; - period = group->period; - -#ifndef GPAC_DISABLE_LOG - -#define GET_REP_ATTR(_a) _a = rep->_a; if (!_a) _a = set->_a; - - GET_REP_ATTR(width); - GET_REP_ATTR(height); - GET_REP_ATTR(samplerate); - GET_REP_ATTR(framerate); - - GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[MPDIn] Switched to representation bandwidth %d kbps\n", rep->bandwidth/1024)); - if (group->max_bitrate) GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\tmax download bandwidth: %d kbps\n", group->max_bitrate/1024)); - if (width&&height) { - GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\tWidth %d Height %d", width, height)); - if (framerate) GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("framerate %d/%d", framerate->num, framerate->den)); - GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\n")); - } else if (samplerate) { - GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\tsamplerate %d\n", samplerate)); - } -#endif - + Double mediaDuration; + u32 timescale; + u64 duration; + *nb_segments = timescale = 0; + duration = 0; + /*single segment*/ if (rep->segment_base || set->segment_base || period->segment_base) { return; @@ -818,11 +792,11 @@ static void MPD_SetGroupRepresentation(GF_MPD_Group *group, GF_MPD_Representatio if (rep->segment_list->segment_URLs) segments = rep->segment_list->segment_URLs; } if (segments) - group->nb_segments_in_rep = gf_list_count(segments); + *nb_segments = gf_list_count(segments); - if (!timescale) timescale=1; - group->segment_duration = (Double) duration; - group->segment_duration /= timescale; + if (! timescale) timescale=1; + *seg_duration = (Double) duration; + *seg_duration /= timescale; return; } @@ -839,22 +813,66 @@ static void MPD_SetGroupRepresentation(GF_MPD_Group *group, GF_MPD_Representatio if (rep->segment_template->timescale) timescale = rep->segment_template->timescale; } if (!timescale) timescale=1; - group->segment_duration = (Double) duration; - group->segment_duration /= timescale; + *seg_duration = (Double) duration; + *seg_duration /= timescale; mediaDuration = period->duration; - if (!mediaDuration) mediaDuration = group->mpd_in->mpd->media_presentation_duration; + if (!mediaDuration) mediaDuration = mpd->media_presentation_duration; if (mediaDuration && duration) { Double nb_seg = (Double) mediaDuration; /*duration is given in ms*/ nb_seg /= 1000; nb_seg *= timescale; nb_seg /= duration; - group->nb_segments_in_rep = (u32) ceil(nb_seg); - } else { - group->nb_segments_in_rep = 0; + *nb_segments = (u32) ceil(nb_seg); } } + +static void MPD_SetGroupRepresentation(GF_MPD_Group *group, GF_MPD_Representation *rep) +{ + u64 duration = 0; + u64 mediaDuration = 0; +#ifndef GPAC_DISABLE_LOG + u32 width=0, height=0, samplerate=0; + GF_MPD_Fractional *framerate=NULL; +#endif + u32 timescale = 1; + GF_MPD_AdaptationSet *set; + GF_MPD_Period *period; + u32 i = gf_list_find(group->adaptation_set->representations, rep); + assert((s32) i >= 0); + + group->active_rep_index = i; + group->active_bitrate = rep->bandwidth; + group->nb_segments_in_rep = 1; + + set = group->adaptation_set; + period = group->period; + +#ifndef GPAC_DISABLE_LOG + +#define GET_REP_ATTR(_a) _a = rep->_a; if (!_a) _a = set->_a; + + GET_REP_ATTR(width); + GET_REP_ATTR(height); + GET_REP_ATTR(samplerate); + GET_REP_ATTR(framerate); + + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[MPDIn] Switched to representation bandwidth %d kbps\n", rep->bandwidth/1024)); + if (group->max_bitrate) GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\tmax download bandwidth: %d kbps\n", group->max_bitrate/1024)); + if (width&&height) { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\tWidth %d Height %d", width, height)); + if (framerate) GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("framerate %d/%d", framerate->num, framerate->den)); + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\n")); + } else if (samplerate) { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("\tsamplerate %d\n", samplerate)); + } +#endif + + + MPD_GetSegmentDuration(rep, set, period, group->mpd_in->mpd, &group->nb_segments_in_rep, &group->segment_duration); +} + static void MPD_SwitchGroupRepresentation(GF_MPD_In *mpd, GF_MPD_Group *group) { u32 i, bandwidth, min_bandwidth; @@ -1440,6 +1458,7 @@ static u32 download_segments(void *par) gf_mx_v(mpdin->dl_mutex); restart_period: + mpdin->in_period_setup = 1; e = GF_OK; period = gf_list_get(mpdin->mpd->periods, mpdin->active_period_index); group_count = gf_list_count(mpdin->groups); @@ -1482,6 +1501,7 @@ restart_period: } gf_mx_p(mpdin->dl_mutex); + mpdin->in_period_setup = 0; mpdin->mpd_is_running = MPD_STATE_RUNNING; gf_mx_v(mpdin->dl_mutex); @@ -1807,15 +1827,16 @@ static void MPD_DownloadStop(GF_MPD_In *mpdin) { u32 i; assert( mpdin ); - if (mpdin->groups){ - for (i=0; igroups); i++) { - GF_MPD_Group *group = gf_list_get(mpdin->groups, i); - assert( group ); - if (group->selected && group->segment_dnload) { - gf_dm_sess_abort(group->segment_dnload); - group->done = 1; + if (mpdin->groups) { + for (i=0; igroups); i++) { + GF_MPD_Group *group = gf_list_get(mpdin->groups, i); + assert( group ); + if (! group->service_connected ) return; + if (group->selected && group->segment_dnload) { + gf_dm_sess_abort(group->segment_dnload); + group->done = 1; + } } - } } /* stop the download thread */ gf_mx_p(mpdin->dl_mutex); @@ -1844,6 +1865,8 @@ Bool MPD_SeekPeriods(GF_MPD_In *mpdin) u32 i, period_idx; gf_mx_p(mpdin->dl_mutex); + + mpdin->start_range_in_segment_at_next_period = 0; start_time = 0; period_idx = 0; for (i=0; i<=gf_list_count(mpdin->mpd->periods); i++) { @@ -1862,6 +1885,23 @@ Bool MPD_SeekPeriods(GF_MPD_In *mpdin) mpdin->playback_start_range -= start_time; mpdin->active_period_index = period_idx; mpdin->request_period_switch = 2; + + /*figure out default segment duration and substract from our start range request*/ + if (mpdin->playback_start_range) { + Double duration; + u32 nb_segs; + GF_MPD_Period *period = gf_list_get(mpdin->mpd->periods, period_idx); + GF_MPD_AdaptationSet *set = gf_list_get(period->adaptation_sets, 0); + GF_MPD_Representation *rep = gf_list_get(set->representations, 0); + + MPD_GetSegmentDuration(rep, set, period, mpdin->mpd, &nb_segs, &duration); + + if (duration) { + while (mpdin->playback_start_range - mpdin->start_range_in_segment_at_next_period >= duration) + mpdin->start_range_in_segment_at_next_period += duration; + } + + } } gf_mx_v(mpdin->dl_mutex); @@ -1874,6 +1914,7 @@ void MPD_SeekGroup(GF_MPD_In *mpdin, GF_MPD_Group *group) u32 first_downloaded, last_downloaded, segment_idx; group->force_segment_switch = 0; + if (!group->segment_duration) return; /*figure out where to seek*/ segment_idx = 0; @@ -1927,6 +1968,16 @@ void MPD_SeekGroupsDownloads(GF_MPD_In *mpdin) u32 i; gf_mx_p(mpdin->dl_mutex); + + if (mpdin->active_period_index) { + Double dur = 0; + u32 i; + for (i=0; iactive_period_index; i++) { + GF_MPD_Period *period = gf_list_get(mpdin->mpd->periods, mpdin->active_period_index-1); + dur += period->duration/1000.0; + } + mpdin->playback_start_range -= dur; + } for (i=0; igroups); i++) { GF_MPD_Group *group = gf_list_get(mpdin->groups, i); MPD_SeekGroup(mpdin, group); @@ -2486,7 +2537,7 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) case GF_NET_CHAN_PLAY: GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[MPD_IN] Received Play command from terminal on channel %p on Service (%p)\n", com->base.on_channel, mpdin->service)); - if (!com->play.dash_segment_switch && ! mpdin->in_seek) { + if (! mpdin->in_period_setup && !com->play.dash_segment_switch && ! mpdin->in_seek) { Bool skip_seek; mpdin->in_seek = 1; @@ -2511,6 +2562,10 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) else if (mpdin->in_seek && (com->play.start_range==0)) { // mpdin->in_seek = 0; } + else if (mpdin->in_period_setup && (com->play.start_range==0)) { + com->play.start_range = mpdin->playback_start_range; + } + group->done = 0; com->play.dash_segment_switch = group->force_segment_switch; /*don't forward commands, we are killing the service anyway ...*/ diff --git a/modules/osd/osd.c b/modules/osd/osd.c index 74913f8..f4c6f6c 100644 --- a/modules/osd/osd.c +++ b/modules/osd/osd.c @@ -256,7 +256,7 @@ GF_TermExt *osd_new() GF_OSD *osd; dr = (GF_TermExt*)gf_malloc(sizeof(GF_TermExt)); memset(dr, 0, sizeof(GF_TermExt)); - GF_REGISTER_MODULE_INTERFACE(dr, GF_TERM_EXT_INTERFACE, "GPAC OnSscreen Display", "gpac distribution"); + GF_REGISTER_MODULE_INTERFACE(dr, GF_TERM_EXT_INTERFACE, "GPAC OnScreen Display", "gpac distribution"); GF_SAFEALLOC(osd, GF_OSD); dr->process = osd_process; diff --git a/modules/oss_audio/Makefile b/modules/oss_audio/Makefile index 1582048..2deafcd 100644 --- a/modules/oss_audio/Makefile +++ b/modules/oss_audio/Makefile @@ -15,7 +15,7 @@ CFLAGS+=-pg LDFLAGS+=-pg endif -ifeq ($(OSS_INC_TYPE), SYS) +ifeq ($(OSS_INC_TYPE), yes) else CFLAGS+=-DOSS_FIX_INC endif diff --git a/modules/platinum/Makefile b/modules/platinum/Makefile index b6bc3d4..5c8a44b 100644 --- a/modules/platinum/Makefile +++ b/modules/platinum/Makefile @@ -14,7 +14,7 @@ CFLAGS+=-pg LDFLAGS+=-pg endif -LINKLIBS= -lgpac -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib +LINKLIBS= -lgpac -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread LOCAL_LIB=../../bin/gcc -L../../extra_lib/lib/gcc #common objects diff --git a/modules/widgetman/Makefile b/modules/widgetman/Makefile new file mode 100644 index 0000000..edb93f8 --- /dev/null +++ b/modules/widgetman/Makefile @@ -0,0 +1,75 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/modules/widgetman + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +LINKLIBS= -lgpac -lz +LOCAL_LIB=-L../../bin/gcc + +#common objects +OBJS=widgetman.o unzip.o widget.o wgt_load.o + +ifeq ($(CONFIG_ZLIB), local) +CFLAGS+=-I"$(LOCAL_INC_PATH)/zlib" +LOCAL_LIB+= -L../../extra_lib/lib/gcc +endif + +ifeq ($(CONFIG_JS),no) +else +CFLAGS+=$(JS_FLAGS) +ifeq ($(CONFIG_JS),local) +NEED_LOCAL_LIB="yes" +LOCAL_LIB+= -L../../extra_lib/lib/gcc +endif +LINKLIBS+= $(JS_LIBS) +endif + +SRCS := $(OBJS:.o=.c) + +LIB=gm_widgetman.$(DYN_LIB_SUFFIX) +ifeq ($(CONFIG_WIN32),yes) +#LDFLAGS+=-export-symbols widgetman.def +endif + + +all: $(LIB) + + +$(LIB): $(OBJS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) $(LOCAL_LIB) $(LINKLIBS) + + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + + +clean: + rm -f $(OBJS) ../../bin/gcc/$(LIB) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + + + +# include dependency files if they exist +# +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/modules/widgetman/unzip.c b/modules/widgetman/unzip.c new file mode 100644 index 0000000..df1430c --- /dev/null +++ b/modules/widgetman/unzip.c @@ -0,0 +1,1372 @@ +/* + miniunz.c + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + + +#include +#include +#include +#include + +#ifndef _WIN32_WCE +#include +#include + +#ifdef WIN32 +# include +# include +#else +# include +# include +# include +#endif + +#endif + +#include "unzip.h" +#include + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)gf_fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + fseek((FILE *)stream, offset, fseek_origin); + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +static int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + +static int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int err; + int i = 0; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +static int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int err; + int i = 0; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +static uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +static int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK){ + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + +int unzGetCurrentFileInfo(unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file, pfile_info, NULL, szFileName, fileNameBufferSize, extraField, extraFieldBufferSize, szComment, commentBufferSize); +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +int unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +int unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +int unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +int unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) + const char *path; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK){ + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +int unzOpenCurrentFile3 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + + if (password != NULL) + return UNZ_PARAMERROR; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + + return UNZ_OK; +} + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzClose (file) + unzFile file; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + if (s->pfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + +#ifndef _WIN32_WCE + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#if defined(WIN32) || defined(_WIN32_WCE) + return mkdir(dirname); +#else + return mkdir (dirname, 700); +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)gf_malloc(len+1); + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + gf_free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + gf_free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + gf_free(buffer); + return 1; +} +#else +int makedir (newdir) +{ + return 0; +} +#endif + + +int do_extract_currentfile(uf) + unzFile uf; +{ + char filename_inzip[256]; + char* filename_withoutpath; + char* p; + int err=UNZ_OK; + FILE *fout=NULL; + void* buf; + uInt size_buf; + + unz_file_info file_info; + err = unzlocal_GetCurrentFileInfoInternal(uf,&file_info,NULL,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0); + + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); + return err; + } + + size_buf = WRITEBUFFERSIZE; + buf = (void*)gf_malloc(size_buf); + if (buf==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + + p = filename_withoutpath = filename_inzip; + while ((*p) != '\0') + { + if (((*p)=='/') || ((*p)=='\\')) + filename_withoutpath = p+1; + p++; + } + + if ((*filename_withoutpath)=='\0') + { +#ifndef _WIN32_WCE + printf("creating directory: %s\n",filename_inzip); + mymkdir(filename_inzip); +#endif + } + else + { + const char* write_filename; + int skip=0; + + write_filename = filename_inzip; + + err = unzOpenCurrentFile3(uf, NULL, NULL, 0, NULL/*password*/); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err); + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen(write_filename,"wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (gf_fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + gf_free(buf); + return err; +} + + +int gf_unzip_archive(const char *zipfilename, const char *dirname) +{ + uLong i; + unz_global_info gi; + int err; + + unzFile uf=NULL; + + uf = unzOpen2(zipfilename, NULL); + if (uf==NULL) + { + printf("Cannot open %s\n", zipfilename); + return 1; + } +#ifndef _WIN32_WCE + if (chdir(dirname)) + { + printf("Error changing into %s, aborting\n", dirname); + exit(-1); + } +#endif + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i + +#ifndef OF +#define OF(x) x +#endif + +#define ZCALLBACK + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (gf_malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) gf_free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +#define WRITEBUFFERSIZE (8192) + + + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + + + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for gf_f64_seek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + +int gf_unzip_probe(const char *zipfilename); + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/modules/widgetman/wgt_load.c b/modules/widgetman/wgt_load.c new file mode 100644 index 0000000..7a87d28 --- /dev/null +++ b/modules/widgetman/wgt_load.c @@ -0,0 +1,302 @@ +//This software module was originally developed by TelecomParisTech in the +//course of the development of MPEG-U Widgets (ISO/IEC 23007-1) standard. +// +//This software module is an implementation of a part of one or +//more MPEG-U Widgets (ISO/IEC 23007-1) tools as specified by the MPEG-U Widgets +//(ISO/IEC 23007-1) standard. ISO/IEC gives users of the MPEG-U Widgets +//(ISO/IEC 23007-1) free license to this software module or modifications +//thereof for use in hardware or software products claiming conformance to +//the MPEG-U Widgets (ISO/IEC 23007-1). Those intending to use this software +//module in hardware or software products are advised that its use may +//infringe existing patents. +//The original developer of this software module and his/her company, the +//subsequent editors and their companies, and ISO/IEC have no liability +//for use of this software module or modifications thereof in an implementation. +//Copyright is not released for non MPEG-U Widgets (ISO/IEC 23007-1) conforming +//products. +//Telecom ParisTech retains full right to use the code for his/her own purpose, +//assign or donate the code to a third party and to inhibit third parties from +//using the code for non MPEG-U Widgets (ISO/IEC 23007-1) conforming products. +// +//This copyright notice must be included in all copies or derivative works. +// +//Copyright (c) 2009. +// +// Alternatively, this software module may be redistributed and/or modified +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////// +// +// Authors: +// Cyril Concolato, Telecom ParisTech +// Jean Le Feuvre, Telecom ParisTech +// +///////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include + +#ifdef GPAC_HAS_SPIDERMONKEY + +typedef struct +{ + GF_Scene *scene; + u8 oti; + char *file_name; + u32 file_size; + Bool loaded; +} WgtLoad; + +static GF_Err WGT_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 inBufferLength, + u16 ES_ID, u32 stream_time, u32 mmlevel) +{ + GF_Err e = GF_OK; + WgtLoad *wgtload = (WgtLoad *)plug->privateStack; + + if (stream_time==(u32)-1) { + gf_sg_reset(wgtload->scene->graph); + return GF_OK; + } + + switch (wgtload->oti) { + case GPAC_OTI_PRIVATE_SCENE_WGT: + if (wgtload->file_name && !wgtload->loaded) { + const char *path, *wmpath; + char *tmp; + GF_Node *n, *root; + GF_FieldInfo info; + FILE *jsfile; + GF_ChildNodeItem *last; + + wgtload->loaded = 1; + + gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/2000/svg", NULL); + gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/1999/xlink", "xlink"); + gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/2001/xml-events", "ev"); + gf_sg_set_scene_size_info(wgtload->scene->graph, 800, 600, 1); + + /* modify the scene with an Inline/Animation pointing to the widget start file URL */ + n = root = gf_node_new(wgtload->scene->graph, TAG_SVG_svg); + gf_node_register(root, NULL); + gf_sg_set_root_node(wgtload->scene->graph, root); + gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_viewBox, 1, 0, &info); + gf_svg_parse_attribute(n, &info, "0 0 320 240", 0); + gf_node_get_attribute_by_name(n, "xmlns", 0, 1, 0, &info); + gf_svg_parse_attribute(n, &info, "http://www.w3.org/2000/svg", 0); +/* + gf_sg_set_scene_size_info(wgtload->scene->graph, 800, 600, 1); + gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_width, 1, 0, &info); + gf_svg_parse_attribute(n, &info, "800", 0); + gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_height, 1, 0, &info); + gf_svg_parse_attribute(n, &info, "600", 0); +*/ + gf_node_init(n); + + n = gf_node_new(wgtload->scene->graph, TAG_SVG_animation); + gf_node_set_id(n, 1, "w_anim"); + gf_node_register(n, root); + gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); + gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_width, 1, 0, &info); + gf_svg_parse_attribute(n, &info, "320", 0); + gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_height, 1, 0, &info); + gf_svg_parse_attribute(n, &info, "240", 0); + gf_node_init(n); + + tmp = wgtload->file_name; + while ((tmp = strchr(tmp, '\\'))) { + tmp[0] = '/'; + tmp++; + } + + n = gf_node_new(wgtload->scene->graph, TAG_SVG_script); + gf_node_register(n, root); + gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); + path = gf_modules_get_option((GF_BaseInterface *)plug, "Widgets", "WidgetLoadScript"); + jsfile = path ? gf_f64_open(path, "rt") : NULL; + if (jsfile) { + fclose(jsfile); + gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, 1, 0, &info); + gf_svg_parse_attribute(n, &info, (char *) path, 0); + } else { + const char *load_fun = "function load_widget(wid_url) {\n" + " var wid = WidgetManager.load(wid_url);\n" + " var anim = document.getElementById('w_anim');\n" + " if (wid != null) {\n" + " wid.activate(anim);" + " anim.setAttributeNS('http://www.w3.org/1999/xlink', 'href', wid.main);\n" + " } else {\n" + " alert('Widget ' + wid_url + ' is not valid');\n" + " }\n" + "}\n"; + + gf_dom_add_text_node(n, gf_strdup(load_fun) ); + } + gf_node_init(n); + + + wmpath = gf_modules_get_option((GF_BaseInterface *)plug, "Widgets", "WidgetManagerScript"); + jsfile = wmpath ? gf_f64_open(wmpath, "rt") : NULL; + if (jsfile) { + fclose(jsfile); + n = gf_node_new(wgtload->scene->graph, TAG_SVG_script); + gf_node_register(n, root); + gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); + gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, 1, 0, &info); + gf_svg_parse_attribute(n, &info, (char *) wmpath, 0); + gf_node_init(n); + + n = gf_node_new(wgtload->scene->graph, TAG_SVG_script); + gf_node_register(n, root); + gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); + gf_dom_add_text_node(n, gf_strdup("widget_manager_init();") ); + gf_node_init(n); + } + + tmp = gf_malloc(sizeof(char) * (strlen(wgtload->file_name)+50) ); + sprintf(tmp, "load_widget(\"%s\");\n", wgtload->file_name); + + n = gf_node_new(wgtload->scene->graph, TAG_SVG_script); + gf_node_register(n, root); + gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); + gf_dom_add_text_node(n, gf_strdup(tmp) ); + gf_free(tmp); + + gf_node_init(n); + + if ((wgtload->scene->graph_attached!=1) && (gf_sg_get_root_node(wgtload->scene->graph)!=NULL) ) { + gf_scene_attach_to_compositor(wgtload->scene); + e = GF_EOS; + } + } + break; + + default: + return GF_BAD_PARAM; + } + return e; +} + +static GF_Err WGT_AttachScene(GF_SceneDecoder *plug, GF_Scene *scene, Bool is_scene_decoder) +{ + WgtLoad *wgtload = (WgtLoad *)plug->privateStack; + wgtload->scene = scene; + return GF_OK; +} + +static GF_Err WGT_ReleaseScene(GF_SceneDecoder *plug) +{ + WgtLoad *wgtload = (WgtLoad *)plug->privateStack; + wgtload->scene = NULL; + return GF_OK; +} + +static GF_Err WGT_AttachStream(GF_BaseDecoder *plug, GF_ESD *esd) +{ + GF_BitStream *bs; + WgtLoad *wgtload = (WgtLoad *)plug->privateStack; + if (esd->decoderConfig->upstream) return GF_NOT_SUPPORTED; + + /* decSpecInfo is not null only when reading from an WGT file (local or distant, cached or not) */ + switch (esd->decoderConfig->objectTypeIndication) { + case GPAC_OTI_PRIVATE_SCENE_WGT: + default: + if (!esd->decoderConfig->decoderSpecificInfo) return GF_NON_COMPLIANT_BITSTREAM; + bs = gf_bs_new(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ); + wgtload->file_size = gf_bs_read_u32(bs); + gf_bs_del(bs); + wgtload->file_name = (char *) gf_malloc(sizeof(char)*(1 + esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32)) ); + memcpy(wgtload->file_name, esd->decoderConfig->decoderSpecificInfo->data + sizeof(u32), esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32) ); + wgtload->file_name[esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32) ] = 0; + break; + } + wgtload->oti = esd->decoderConfig->objectTypeIndication; + return GF_OK; +} + +static GF_Err WGT_DetachStream(GF_BaseDecoder *plug, u16 ES_ID) +{ + WgtLoad *wgtload = (WgtLoad *)plug->privateStack; + if (wgtload->file_name) gf_free(wgtload->file_name); + wgtload->file_name = NULL; + return GF_OK; +} + +const char *WGT_GetName(struct _basedecoder *plug) +{ + return "GPAC W3C Widget Loader"; +} + +static u32 WGT_CanHandleStream(GF_BaseDecoder *ifce, u32 StreamType, GF_ESD *esd, u8 PL) +{ + /*don't reply to media type query*/ + if (!esd) return GF_CODEC_NOT_SUPPORTED; + + if (StreamType==GF_STREAM_PRIVATE_SCENE) { + if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_PRIVATE_SCENE_WGT) return GF_CODEC_SUPPORTED; + return GF_CODEC_NOT_SUPPORTED; + } + return GF_CODEC_NOT_SUPPORTED; +} + +static GF_Err WGT_GetCapabilities(GF_BaseDecoder *plug, GF_CodecCapability *cap) +{ + cap->cap.valueInt = 0; + if (cap->CapCode==GF_CODEC_PADDING_BYTES) { + /* Adding one byte of padding for \r\n problems*/ + cap->cap.valueInt = 1; + return GF_OK; + } + return GF_NOT_SUPPORTED; +} + +static GF_Err WGT_SetCapabilities(GF_BaseDecoder *plug, const GF_CodecCapability capability) +{ + return GF_OK; +} + +/*interface create*/ +GF_BaseInterface *LoadWidgetReader() +{ + WgtLoad *wgtload; + GF_SceneDecoder *sdec; + + GF_SAFEALLOC(sdec, GF_SceneDecoder) + GF_REGISTER_MODULE_INTERFACE(sdec, GF_SCENE_DECODER_INTERFACE, "GPAC W3C Widget Loader", "gpac distribution"); + + GF_SAFEALLOC(wgtload, WgtLoad); + sdec->privateStack = wgtload; + sdec->AttachStream = WGT_AttachStream; + sdec->CanHandleStream = WGT_CanHandleStream; + sdec->DetachStream = WGT_DetachStream; + sdec->AttachScene = WGT_AttachScene; + sdec->ReleaseScene = WGT_ReleaseScene; + sdec->ProcessData = WGT_ProcessData; + sdec->GetName = WGT_GetName; + sdec->SetCapabilities = WGT_SetCapabilities; + sdec->GetCapabilities = WGT_GetCapabilities; + return (GF_BaseInterface *)sdec; +} + + +/*interface destroy*/ +void ShutdownWidgetReader(GF_BaseInterface *ifce) +{ + GF_SceneDecoder *sdec = (GF_SceneDecoder *)ifce; + WgtLoad *wgtload; + if (!ifce) + return; + wgtload = (WgtLoad *) sdec->privateStack; + if (wgtload) + gf_free(wgtload); + sdec->privateStack = NULL; + gf_free(sdec); +} + +#endif /*GPAC_HAS_SPIDERMONKEY*/ diff --git a/modules/widgetman/wgt_load_base.js b/modules/widgetman/wgt_load_base.js new file mode 100644 index 0000000..bdaadbd --- /dev/null +++ b/modules/widgetman/wgt_load_base.js @@ -0,0 +1,84 @@ +var wid = null; +var xmlns_xlink = 'http://www.w3.org/1999/xlink'; + +function debug(s) { + alert('[Widget Loader] '+s); +} + +function add_text_span(parent, string) { + var span = document.createElement('tspan'); + span.textContent = string; + parent.appendChild(span); + parent.appendChild(document.createElement('tbreak')); +} + +function load_widget(wid_url) { + debug('Loading Widget: '+wid_url); + wid = WidgetManager.load(wid_url); + var anim = document.getElementById('w_anim'); + width = 320; + height = 240; + anim.setAttribute('height', height/3); + + var info = document.createElement('textArea'); + document.documentElement.appendChild(info); + info.setAttribute('y', height/3); + info.setAttribute('width', width); + + info.setAttribute('font-size', '7'); + info.setAttribute('font-family', 'Arial Unicode MS'); + if (wid != null) { + debug('Loading scene: '+wid.main); + anim.setAttributeNS(xmlns_xlink, 'href', wid.main); + add_text_span(info, 'Widget Metadata'); + add_text_span(info, 'UA Locale: \'' + gpac.getOption('Systems', 'Language2CC') + '\''); + add_text_span(info, 'widget src (abs.): \'' + wid.url + '\''); + add_text_span(info, 'config src (abs.): \'' + wid.manifest + '\''); + add_text_span(info, 'content src (rel.&loc./abs.): \''+wid.main+'\' / \''+wid.localizedSrc+'\' ('+wid.mainMimeType+';'+wid.mainEncoding+')'); + add_text_span(info, 'id: \'' + wid.identifier + '\''); + add_text_span(info, 'shortname/name: \''+wid.shortName+ '\' / \''+wid.name+'\''); + add_text_span(info, 'version: \''+wid.version+'\''); + add_text_span(info, 'license/href: \''+wid.license+'\' / \''+wid.licenseHref+'\''); + add_text_span(info, 'description: \''+wid.description+'\''); + add_text_span(info, 'author (name/email/href): \''+wid.authorName+ '\' / \''+wid.authorEmail +'\' / \''+wid.authorHref+'\''); + var s = 'icons src (rel.&loc./abs.): '; + for (var i=0; iwidget->wm->term, &evt); + SMJS_FREE(c, (char *)evt.navigate.to_url); + + return JS_TRUE; +} + +JSBool SMJS_FUNCTION(widget_get_attention) +{ + jsval fval; + SMJS_OBJ + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_TRUE; + + if ((JS_LookupProperty(c, wid->widget->wm->obj, "getAttention", &fval)==JS_TRUE) && JSVAL_IS_OBJECT(fval)) { + jsval args[1]; + args[0] = OBJECT_TO_JSVAL(wid->obj); + JS_CallFunctionValue(c, wid->widget->wm->obj, fval, 1, args, SMJS_GET_RVAL); + } + return JS_TRUE; +} + +JSBool SMJS_FUNCTION(widget_show_notification) +{ + jsval fval; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_TRUE; + + if ((JS_LookupProperty(c, wid->widget->wm->obj, "showNotification", &fval)==JS_TRUE) && JSVAL_IS_OBJECT(fval)) { + jsval *vars; + u32 i; + vars = gf_malloc(sizeof(jsval)*(argc+1)); + vars[0] = OBJECT_TO_JSVAL(wid->obj); + for (i=0; iwidget->wm->obj, fval, argc+1, vars, SMJS_GET_RVAL); + } + return JS_TRUE; +} + + +static JSBool SMJS_FUNCTION(widget_call_message_reply_callback) +{ + JSObject *list; + jsval *vals, fval; + u32 i, count; + SMJS_OBJ + SMJS_ARGS + GF_WidgetMessage *msg = JS_GetPrivate(c, obj); + if (!msg || !argc || !JSVAL_IS_OBJECT(argv[0]) ) return JS_FALSE; + + if ((JS_LookupProperty(c, obj, "replyCallback", &fval)==JS_TRUE) && JSVAL_IS_OBJECT(fval)) { + list = JSVAL_TO_OBJECT(argv[0]); + JS_GetArrayLength(c, list, (jsuint*) &count); + vals = gf_malloc(sizeof(jsval)*(count+1)); + vals[0] = OBJECT_TO_JSVAL(obj); + for (i=0; iifce->messages); + for (i=0; iifce->messages, i); + if (!strcmp(msg->name, msg_name)) { + JSObject *an_obj = JS_NewObject(c, &bifce->wid->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, an_obj, msg); + JS_DefineProperty(c, an_obj, "msgName", STRING_TO_JSVAL( JS_NewStringCopyZ(c, msg->name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, an_obj, "interfaceHandler", OBJECT_TO_JSVAL( obj ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineFunction(c, an_obj, "onInvokeReply", widget_call_message_reply_callback, 1, 0); + + if ((argc==2) && JSVAL_IS_OBJECT(argv[1]) && !JSVAL_IS_NULL(argv[1])) + JS_DefineProperty(c, an_obj, "replyCallback", argv[1], 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + + SMJS_SET_RVAL( OBJECT_TO_JSVAL(an_obj) ); + } + } + SMJS_FREE(c, msg_name); + return JS_TRUE; +} +static JSBool SMJS_FUNCTION(widget_invoke_message) +{ + jsval oval; + GF_WidgetMessage *msg = NULL; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInterfaceInstance *bifce = (GF_WidgetInterfaceInstance *)JS_GetPrivate(c, obj); + if (!bifce) return JS_FALSE; + + SMJS_SET_RVAL( JSVAL_NULL ); + + if (!JSVAL_IS_OBJECT(argv[0])) return JS_FALSE; + if (JSVAL_IS_NULL(argv[0])) return JS_FALSE; + msg = (GF_WidgetMessage *)JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!msg) return JS_FALSE; + + /*look for JS Callback "invoke" in the widget manager script*/ + if (JS_LookupProperty(c, bifce->ifce->obj, "invoke", &oval)==JS_TRUE) { + if (JSVAL_IS_OBJECT(oval)) { + JS_CallFunctionValue(bifce->wid->widget->wm->ctx, bifce->ifce->obj, oval, argc, argv, SMJS_GET_RVAL ); + } + } + + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(widget_invoke_message_reply) +{ + jsval oval; + SMJS_OBJ + SMJS_ARGS + GF_WidgetMessage *msg = NULL; + GF_WidgetInterfaceInstance *bifce = (GF_WidgetInterfaceInstance *)JS_GetPrivate(c, obj); + if (!bifce) return JS_FALSE; + + SMJS_SET_RVAL( JSVAL_NULL ); + + if (!JSVAL_IS_OBJECT(argv[0])) return JS_FALSE; + if (JSVAL_IS_NULL(argv[0])) return JS_FALSE; + msg = (GF_WidgetMessage *)JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!msg) return JS_FALSE; + + /*look for JS Callback "invokeReply" in the widget manager script*/ + if (JS_LookupProperty(c, bifce->ifce->obj, "invokeReply", &oval)==JS_TRUE) { + if (JSVAL_IS_OBJECT(oval)) { + JS_CallFunctionValue(bifce->wid->widget->wm->ctx, bifce->ifce->obj, oval, argc, argv, SMJS_GET_RVAL); + } + } + return JS_TRUE; +} + +static void widget_interface_js_bind(JSContext *c, GF_WidgetInterfaceInstance *ifce) +{ + if (!ifce->obj) { + ifce->obj = JS_NewObject(c, &ifce->wid->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, ifce->obj, ifce); + gf_js_add_root(c, &ifce->obj, GF_JSGC_OBJECT); + JS_DefineProperty(c, ifce->obj, "type", STRING_TO_JSVAL( JS_NewStringCopyZ(c, ifce->ifce->type) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, ifce->obj, "bound", STRING_TO_JSVAL( JS_NewStringCopyZ(c, ifce->hostname) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineFunction(c, ifce->obj, "invoke", widget_invoke_message, 1, 0); + JS_DefineFunction(c, ifce->obj, "msgHandlerFactory", widget_message_handler_factory, 1, 0); + JS_DefineFunction(c, ifce->obj, "invokeReply", widget_invoke_message_reply, 1, 0); + } +} + +static JSBool SMJS_FUNCTION(widget_get_interfaces) +{ + u32 i, count; + char *ifce_name; + JSObject *list; + jsuint idx; + jsval v; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + + if (!argc || !JSVAL_IS_STRING(argv[0])) return JS_TRUE; + ifce_name = SMJS_CHARS(c, argv[0]); + + list = JS_NewArrayObject(c, 0, 0); + + count = gf_list_count(wid->bound_ifces); + for (i=0; ibound_ifces, i); + if (strcmp(ifce->ifce->type, ifce_name)) continue; + + widget_interface_js_bind(c, ifce); + + JS_GetArrayLength(c, list, &idx); + v = OBJECT_TO_JSVAL(ifce->obj); + JS_SetElement(c, list, idx, &v); + } + SMJS_SET_RVAL( OBJECT_TO_JSVAL(list) ); + SMJS_FREE(c, ifce_name); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION_EXT(widget_activate_component, Bool is_deactivate) +{ + u32 i, count; + char *comp_id; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + + if (!argc || !JSVAL_IS_STRING(argv[0])) return JS_TRUE; + comp_id = SMJS_CHARS(c, argv[0]); + + count = gf_list_count(wid->widget->main->components); + for (i=0; iwidget->main->components, i); + if (!comp->id || strcmp(comp->id, comp_id)) continue; + + if (is_deactivate) { + wm_deactivate_component(c, wid, comp, NULL); + } else { + wm_activate_component(c, wid, comp, 0); + } + break; + } + SMJS_FREE(c, comp_id); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(widget_activate_widget) +{ + return widget_activate_component(SMJS_CALL_ARGS, 0); +} + +static JSBool SMJS_FUNCTION(widget_deactivate_widget) +{ + return widget_activate_component(SMJS_CALL_ARGS, 1); +} + +void widget_on_interface_bind(GF_WidgetInterfaceInstance *ifce, Bool unbind) +{ + jsval funval, rval, argv[1]; + + const char *fun_name = unbind ? "onInterfaceUnbind" : "onInterfaceBind"; + if (!ifce || !ifce->wid || !ifce->wid->scene_context) return; + + /*look for JS Callback "invoke" in the widget manager script*/ + if (JS_LookupProperty(ifce->wid->scene_context, ifce->wid->scene_obj, fun_name, &funval)!=JS_TRUE) + return; + if (!JSVAL_IS_OBJECT(funval)) return; + + widget_interface_js_bind(ifce->wid->widget->wm->ctx, ifce); + argv[0] = OBJECT_TO_JSVAL(ifce->obj); + JS_CallFunctionValue(ifce->wid->widget->wm->ctx, ifce->ifce->obj, funval, 1, argv, &rval); + +} + +JSBool widget_getProperty(JSContext *c, JSObject *obj, SMJS_PROP_GETTER, jsval *rval) +{ + const char *opt; + char *prop_name; + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + + if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; + prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); + if (!prop_name) return JS_FALSE; + + if (!strcmp(prop_name, "viewMode")) { + *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, "floating") ); + } + else if (!strcmp(prop_name, "locale")) { + opt = gf_cfg_get_key(wid->widget->wm->term->user->config, "Systems", "Language2CC"); + if (!opt) opt = "und"; + *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, opt) ); + } + else if (!strcmp(prop_name, "identifier")) { + if (wid->widget->identifier) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->identifier) ); + } + else if (!strcmp(prop_name, "authorName")) { + if (wid->widget->authorName) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->authorName) ); + } + else if (!strcmp(prop_name, "authorEmail")) { + if (wid->widget->authorEmail) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->authorEmail) ); + } + else if (!strcmp(prop_name, "authorHref")) { + if (wid->widget->authorHref) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->authorHref) ); + } + else if (!strcmp(prop_name, "name")) { + if (wid->widget->name) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->name) ); + } + else if (!strcmp(prop_name, "version")) { + if (wid->widget->version) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->version) ); + } + else if (!strcmp(prop_name, "description")) { + if (wid->widget->description) *rval = STRING_TO_JSVAL( JS_NewStringCopyZ(c, wid->widget->description) ); + } + else if (!strcmp(prop_name, "width")) { + opt = gf_cfg_get_key(wid->widget->wm->term->user->config, wid->secname, "width"); + *rval = INT_TO_JSVAL( (opt ? atoi(opt) : 0) ); + } + else if (!strcmp(prop_name, "height")) { + opt = gf_cfg_get_key(wid->widget->wm->term->user->config, wid->secname, "height"); + *rval = INT_TO_JSVAL( (opt ? atoi(opt) : 0) ); + } + else if (!strcmp(prop_name, "preferences")) { + } + SMJS_FREE(c, prop_name); + return JS_TRUE; +} + +JSBool widget_setProperty(JSContext *c, JSObject *obj, SMJS_PROP_SETTER, jsval *vp) +{ + return JS_TRUE; +} + +void widget_load(GF_WidgetManager *wm, GF_SceneGraph *scene, JSContext *c, JSObject *global, Bool unload) +{ + u32 i, count; + GF_WidgetInstance *wi; + + /*Is this scenegraph a widget or not ? To find out, browse all widget instances*/ + i=0; + while ((wi = gf_list_enum(wm->widget_instances, &i))) { + if (!wi->scene || (wi->scene != scene)) continue; + break; + } + if (!wi) return; + + /*OK we found our widget*/ + + if (unload) { + /*detach all bound interfaces from this script*/ + count = gf_list_count(wi->bound_ifces); + for (i=0; ibound_ifces, i); + if (ifce->obj) { + JS_SetPrivate(c, ifce->obj, NULL); + gf_js_remove_root(c, &ifce->obj, GF_JSGC_OBJECT); + ifce->obj = NULL; + } + } + return; + } else { + + JSPropertySpec widgetClassProps[] = { + {0, 0, 0, 0, 0} + }; + JSFunctionSpec widgetClassFuncs[] = { + /*W3C*/ + SMJS_FUNCTION_SPEC("has_feature", widget_has_feature, 1), + SMJS_FUNCTION_SPEC("openURL", widget_open_url, 1), + SMJS_FUNCTION_SPEC("getAttention", widget_get_attention, 0), + SMJS_FUNCTION_SPEC("showNotification", widget_show_notification, 0), + /*MPEG*/ + SMJS_FUNCTION_SPEC("getInterfaceHandlersByType", widget_get_interfaces, 1), + SMJS_FUNCTION_SPEC("activateComponentWidget", widget_activate_widget, 1), + SMJS_FUNCTION_SPEC("deactivateComponentWidget", widget_deactivate_widget, 1), + SMJS_FUNCTION_SPEC(0, 0, 0) + }; + + JS_InitClass(c, global, 0, &wm->widgetClass, 0, 0,widgetClassProps, widgetClassFuncs, 0, 0); + + + wi->scene_obj = JS_DefineObject(c, global, "widget", &wm->widgetClass, 0, 0); + //JS_AliasProperty(c, global, "widget", "MPEGWidget"); + JS_SetPrivate(c, wi->scene_obj, wi); + /*and remember the script*/ + wi->scene_context = c; + wi->scene_global = global; + } +} + +#endif diff --git a/modules/widgetman/widgetman.c b/modules/widgetman/widgetman.c new file mode 100644 index 0000000..75e3df3 --- /dev/null +++ b/modules/widgetman/widgetman.c @@ -0,0 +1,3648 @@ +//This software module was originally developed by TelecomParisTech in the +//course of the development of MPEG-U Widgets (ISO/IEC 23007-1) standard. +// +//This software module is an implementation of a part of one or +//more MPEG-U Widgets (ISO/IEC 23007-1) tools as specified by the MPEG-U Widgets +//(ISO/IEC 23007-1) standard. ISO/IEC gives users of the MPEG-U Widgets +//(ISO/IEC 23007-1) free license to this software module or modifications +//thereof for use in hardware or software products claiming conformance to +//the MPEG-U Widgets (ISO/IEC 23007-1). Those intending to use this software +//module in hardware or software products are advised that its use may +//infringe existing patents. +//The original developer of this software module and his/her company, the +//subsequent editors and their companies, and ISO/IEC have no liability +//for use of this software module or modifications thereof in an implementation. +//Copyright is not released for non MPEG-U Widgets (ISO/IEC 23007-1) conforming +//products. +//Telecom ParisTech retains full right to use the code for his/her own purpose, +//assign or donate the code to a third party and to inhibit third parties from +//using the code for non MPEG-U Widgets (ISO/IEC 23007-1) conforming products. +// +//This copyright notice must be included in all copies or derivative works. +// +//Copyright (c) 2009. +// +// Alternatively, this software module may be redistributed and/or modified +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////////// +// +// Authors: +// Jean Le Feuvre, Telecom ParisTech +// Cyril Concolato, Telecom ParisTech +// +///////////////////////////////////////////////////////////////////////////////// + +#include "widgetman.h" + +#ifdef GPAC_HAS_SPIDERMONKEY + +#if !defined(__GNUC__) +# pragma comment(lib, "js32") +#endif + + +JSBool gf_sg_js_event_add_listener(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, GF_Node *vrml_node); +JSBool gf_sg_js_event_remove_listener(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, GF_Node *vrml_node); + + + +static Bool is_same_path(const char *p1, const char *p2, u32 len) +{ + char c1, c2; + u32 i=0; + do { + if (len && (i==len)) + break; + c1 = p1[i]; + c2 = p2[i]; + if (p1[i] != p2[i]) { + if ((c1=='/') && (c2=='\\')) {} + else if ((c1=='\\') && (c2=='/')) {} + else return 0; + } + i++; + } while (c1); + return 1; +} + +static void widget_package_extract_file(GF_WidgetPackage *wpack, GF_WidgetPackageResource *res) +{ + u32 i, count; + + if (wpack->is_zip) { + unz_global_info gi; + unzFile uf = unzOpen2(wpack->package_path, NULL); + if (!uf) return; + + unzGetGlobalInfo(uf, &gi); + for (i=0; iinner_path, filename_inzip)) { + if ((i+1)extracted_path, "wb"); + if (!fout) break; + do { + err = unzReadCurrentFile(uf,buf,8192); + if (err<0) break; + if (err>0) + if (gf_fwrite(buf,err,1,fout)!=1) { + err=UNZ_ERRNO; + break; + } + } while (err>0); + if (fout) fclose(fout); + + res->extracted = 1; + break; + } + unzClose(uf); + } else { + GF_ISOFile *isom = gf_isom_open(wpack->package_path, GF_ISOM_OPEN_READ, 0); + if (!isom ) return; + + count = gf_isom_get_meta_item_count(isom, 1, 0); + for (i=0; iinner_path, item_name)) continue; + + gf_isom_extract_meta_item(isom, 1, 0, ID, res->extracted_path); + res->extracted = 1; + break; + } + gf_isom_close(isom); + } + +} + +static Bool package_find_res(GF_WidgetPackage *wpack, char *res_path, char *relocated_path, char *localized_rel_path) +{ + u32 count, i; + count = gf_list_count(wpack->resources); + for (i=0;iresources, i); + if (is_same_path(res_path, pack_res->inner_path, 0)) { + strcpy(localized_rel_path, res_path); + strcpy(relocated_path, pack_res->extracted_path); + if (!pack_res->extracted) widget_package_extract_file(wpack, pack_res); + return 1; + } + } + return 0; +} + +/* Checks if a resource in the package has the given rel_path, potentially in a localized sub-folder */ +static Bool widget_package_relocate_uri(void *__self, const char *parent_uri, const char *rel_path, char *relocated_path, char *localized_rel_path) +{ + char path[GF_MAX_PATH]; + const char *opt; + GF_WidgetPackage *wpack = (GF_WidgetPackage *)__self; + + assert(parent_uri); + /*resource belongs to our archive*/ + if (strstr(rel_path, wpack->archive_id)) { + rel_path = strstr(rel_path, wpack->archive_id) + strlen(wpack->archive_id); + } + /*parent resource belongs to our archive*/ + else if (strstr(parent_uri, wpack->archive_id)) { + } + /*resource doesn't belong to our archive*/ + else { + return 0; + } + + /* First try to locate the resource in the locales folder */ + opt = gf_cfg_get_key(wpack->wm->term->user->config, "Systems", "Language2CC"); + if (opt) { + if (!strcmp(opt, "*") || !strcmp(opt, "un") ) + opt = NULL; + } + + while (opt) { + char lan[100]; + char *sep; + char *sep_lang = strchr(opt, ';'); + if (sep_lang) sep_lang[0] = 0; + + while (strchr(" \t", opt[0])) + opt++; + strcpy(lan, opt); + + if (sep_lang) { + sep_lang[0] = ';'; + opt = sep_lang+1; + } else { + opt = NULL; + } + + while (1) { + sep = strstr(lan, "-*"); + if (!sep) break; + strncpy(sep, sep+2, strlen(sep)-2); + } + + sprintf(path, "locales/%s/%s", lan, rel_path); + if (package_find_res(wpack, path, relocated_path, localized_rel_path)) + return 1; + + /*recursively remove region (sub)tags*/ + while (1) { + sep = strrchr(lan, '-'); + if (!sep) break; + sep[0] = 0; + sprintf(path, "locales/%s/%s", lan, rel_path); + if (package_find_res(wpack, path, relocated_path, localized_rel_path)) + return 1; + } + } + + /*no locale*/ + if (package_find_res(wpack, (char*)rel_path, relocated_path, localized_rel_path)) + return 1; + + strcpy(localized_rel_path, ""); + strcpy(relocated_path, ""); + return 0; +} + +static GF_WidgetPackage *widget_isom_new(GF_WidgetManager *wm, const char *path) +{ + GF_WidgetPackageResource *pack_res; + char szPath[GF_MAX_PATH]; + const char *dir; + GF_WidgetPackage *wzip; + u32 brand = 0; + u32 i, count; + GF_ISOFile *isom = gf_isom_open(path, GF_ISOM_OPEN_READ, 0); + if (!isom ) return NULL; + + brand = gf_isom_get_meta_type(isom, 1, 0); + if ((brand!=GF_4CC('m','w','g','t') ) || !gf_isom_has_meta_xml(isom, 1, 0) ) { + gf_isom_close(isom); + return NULL; + } + + GF_SAFEALLOC(wzip, GF_WidgetPackage); + + wzip->wm = wm; + wzip->relocate_uri = widget_package_relocate_uri; + wzip->resources = gf_list_new(); + dir = gf_cfg_get_key(wm->term->user->config, "General", "CacheDirectory"); + /* create the extracted path for the package root using: + the cache dir + a CRC of the file path and the instance*/ + sprintf(wzip->root_extracted_path, "%s%08X", path, (unsigned int)((unsigned long) wzip)); + i = gf_crc_32((char *)wzip->root_extracted_path, strlen(wzip->root_extracted_path)); + sprintf(wzip->archive_id, "GWM_%08X_", i); + sprintf(wzip->root_extracted_path, "%s/%s", dir, wzip->archive_id); + + + strcpy(szPath, wzip->root_extracted_path); + strcat(szPath, "config.xml"); + if (gf_isom_extract_meta_xml(isom, 1, 0, szPath, NULL) != GF_OK) { + gf_list_del(wzip->resources); + gf_free(wzip); + gf_isom_close(isom); + return NULL; + } + + wzip->package_path = gf_strdup(path); + + GF_SAFEALLOC(pack_res, GF_WidgetPackageResource); + pack_res->extracted_path = gf_strdup(szPath); + pack_res->inner_path = gf_strdup("config.xml"); + pack_res->extracted = 1; + gf_list_add(wzip->resources, pack_res); + + + count = gf_isom_get_meta_item_count(isom, 1, 0); + for (i=0; iroot_extracted_path, gf_crc_32((char*)item_name, strlen(item_name)), sep+1); + sep[0] = '/'; + } else { + strcpy(szPath, wzip->root_extracted_path); + strcat(szPath, item_name); + } + GF_SAFEALLOC(pack_res, GF_WidgetPackageResource); + pack_res->extracted_path = gf_strdup(szPath); + pack_res->inner_path = gf_strdup(item_name); + pack_res->extracted = 0; + gf_list_add(wzip->resources, pack_res); + } + gf_isom_close(isom); + + + /* register this widget package as a relocator to enable localization of resources inside this package */ + gf_mx_p(wm->term->net_mx); + gf_list_add(wm->term->uri_relocators, wzip); + gf_mx_v(wm->term->net_mx); + return wzip; +} + +static GF_WidgetPackage *widget_zip_new(GF_WidgetManager *wm, const char *path) +{ + unz_global_info gi; + const char *dir; + u32 i; + GF_WidgetPackage *wzip; + unzFile uf = unzOpen2(path, NULL); + if (!uf) return NULL; + + GF_SAFEALLOC(wzip, GF_WidgetPackage); + + wzip->wm = wm; + wzip->is_zip = 1; + wzip->relocate_uri = widget_package_relocate_uri; + wzip->resources = gf_list_new(); + wzip->package_path = gf_strdup(path); + dir = gf_cfg_get_key(wm->term->user->config, "General", "CacheDirectory"); + /* create the extracted path for the package root using: + the cache dir + a CRC of the file path and the instance*/ + sprintf(wzip->root_extracted_path, "%s%08X", path, (unsigned int)((unsigned long) wzip)); + i = gf_crc_32((char *)wzip->root_extracted_path, strlen(wzip->root_extracted_path)); + sprintf(wzip->archive_id, "GWM_%08X_", i); + sprintf(wzip->root_extracted_path, "%s/%s", dir, wzip->archive_id); + + unzGetGlobalInfo(uf, &gi); + for (i=0; iroot_extracted_path, gf_crc_32(filename_inzip, strlen(filename_inzip)), sep+1); + sep[0] = '/'; + } else { + strcpy(szPath, wzip->root_extracted_path); + strcat(szPath, filename_inzip); + } + + + if (!strcmp(filename_inzip, "config.xml")) { + int err; + char buf[8192]; + FILE *fout; + unzOpenCurrentFile3(uf, NULL, NULL, 0, NULL/*password*/); + + fout=gf_f64_open(szPath,"wb"); + if (!fout) return NULL; + + do { + err = unzReadCurrentFile(uf,buf,8192); + if (err<0) break; + + if (err>0) + if (gf_fwrite(buf,err,1,fout)!=1) { + err=UNZ_ERRNO; + break; + } + } while (err>0); + if (fout) fclose(fout); + if (err==0) { + GF_SAFEALLOC(pack_res, GF_WidgetPackageResource); + pack_res->extracted_path = gf_strdup(szPath); + pack_res->inner_path = gf_strdup(filename_inzip); + pack_res->extracted = 1; + gf_list_add(wzip->resources, pack_res); + } + } else { + GF_SAFEALLOC(pack_res, GF_WidgetPackageResource); + pack_res->extracted_path = gf_strdup(szPath); + pack_res->inner_path = gf_strdup(filename_inzip); + pack_res->extracted = 0; + gf_list_add(wzip->resources, pack_res); + } + + if ((i+1)term->net_mx); + gf_list_add(wm->term->uri_relocators, wzip); + gf_mx_v(wm->term->net_mx); + return wzip; +} + +GF_WidgetPackage *widget_package_new(GF_WidgetManager *wm, const char *path) +{ + if (gf_unzip_probe(path)) { + return widget_zip_new(wm, path); + } + /*ISOFF-based packaged widget */ + else if (gf_isom_probe_file(path)) { + return widget_isom_new(wm, path); + } + return NULL; +} + +static void widget_package_del(GF_WidgetManager *wm, GF_WidgetPackage *wpackage) +{ + gf_mx_p(wm->term->net_mx); + gf_list_del_item(wm->term->uri_relocators, wpackage); + gf_mx_v(wm->term->net_mx); + + while (gf_list_count(wpackage->resources)) { + GF_WidgetPackageResource *wu = gf_list_get(wpackage->resources, 0); + gf_list_rem(wpackage->resources, 0); + gf_delete_file(wu->extracted_path); + gf_free(wu->extracted_path); + gf_free(wu->inner_path); + gf_free(wu); + } + gf_list_del(wpackage->resources); + if (wpackage->sess) gf_dm_sess_del(wpackage->sess); + gf_free(wpackage->package_path); + gf_free(wpackage); +} + + + +static void wm_delete_message_param(GF_WidgetPin *mp) +{ + if (!mp) return; + if (mp->node) gf_free(mp->node); + if (mp->attribute) gf_free(mp->attribute); + if (mp->default_value) gf_free(mp->default_value); + if (mp->name) gf_free(mp->name); + gf_free(mp); +} + +static void wm_delete_widget_content(GF_WidgetContent *content) +{ + if (!content) return; + + while (gf_list_count(content->interfaces)) { + GF_WidgetInterface*ifce = gf_list_last(content->interfaces); + gf_list_rem_last(content->interfaces); + + while (gf_list_count(ifce->messages)) { + GF_WidgetMessage *msg = gf_list_last(ifce->messages); + gf_list_rem_last(ifce->messages); + + while (gf_list_count(msg->params)) { + GF_WidgetPin *par = gf_list_last(msg->params); + gf_list_rem_last(msg->params); + wm_delete_message_param(par); + } + gf_list_del(msg->params); + + wm_delete_message_param(msg->input_action); + wm_delete_message_param(msg->output_trigger); + gf_free(msg->name); + gf_free(msg); + } + gf_list_del(ifce->messages); + wm_delete_message_param(ifce->bind_action); + wm_delete_message_param(ifce->unbind_action); + if (ifce->obj) gf_js_remove_root(ifce->content->widget->wm->ctx, &ifce->obj, GF_JSGC_OBJECT); + + if (ifce->connectTo) gf_free(ifce->connectTo); + gf_free(ifce->type); + gf_free(ifce); + } + gf_list_del(content->interfaces); + + while (gf_list_count(content->components)) { + GF_WidgetComponent *comp = gf_list_last(content->components); + gf_list_rem_last(content->components); + + wm_delete_message_param(comp->activateTrigger); + wm_delete_message_param(comp->deactivateTrigger); + + while (gf_list_count(comp->required_interfaces)) { + char *type = gf_list_last(comp->required_interfaces); + gf_list_rem_last(comp->required_interfaces); + if (type) gf_free(type); + } + gf_list_del(comp->required_interfaces); + if (comp->id) gf_free(comp->id); + if (comp->src) gf_free(comp->src); + gf_free(comp); + } + gf_list_del(content->components); + + while (gf_list_count(content->preferences)) { + GF_WidgetPreference *pref = gf_list_last(content->preferences); + gf_list_rem_last(content->preferences); + + wm_delete_message_param(pref->connectTo); + if (pref->value) gf_free(pref->value); + gf_free(pref->name); + gf_free(pref); + } + gf_list_del(content->preferences); + + wm_delete_message_param(content->saveTrigger); + wm_delete_message_param(content->restoreTrigger); + wm_delete_message_param(content->savedAction); + wm_delete_message_param(content->restoredAction); + + gf_free(content->src); + gf_free(content->relocated_src); + gf_free(content->mimetype); + gf_free(content->encoding); + gf_free(content); +} + +static void wm_delete_widget(GF_WidgetManager *wm, GF_Widget *wid) +{ + gf_list_del_item(wm->widgets, wid); + + if (wid->url) gf_free(wid->url); + if (wid->manifest_path) gf_free(wid->manifest_path); + wm_delete_widget_content(wid->main); + if (wid->local_path) gf_free(wid->local_path); + if (wid->name) gf_free(wid->name); + if (wid->shortname) gf_free(wid->shortname); + if (wid->identifier) gf_free(wid->identifier); + if (wid->authorName) gf_free(wid->authorName); + if (wid->authorEmail) gf_free(wid->authorEmail); + if (wid->authorHref) gf_free(wid->authorHref); + if (wid->description) gf_free(wid->description); + if (wid->license) gf_free(wid->license); + if (wid->licenseHref) gf_free(wid->licenseHref); + if (wid->viewmodes) gf_free(wid->viewmodes); + if (wid->version) gf_free(wid->version); + if (wid->uuid) gf_free(wid->uuid); + + + while (gf_list_count(wid->icons)) { + GF_WidgetContent *icon = gf_list_get(wid->icons, 0); + gf_list_rem(wid->icons, 0); + wm_delete_widget_content(icon); + } + gf_list_del(wid->icons); + + while (gf_list_count(wid->features)) { + GF_WidgetFeature *f = gf_list_get(wid->features, 0); + gf_list_rem(wid->features, 0); + if (f->name) gf_free(f->name); + while (gf_list_count(f->params)) { + GF_WidgetFeatureParam *p = gf_list_get(f->params, 0); + gf_list_rem(f->params, 0); + if (p->name) gf_free(p->name); + if (p->value) gf_free(p->value); + gf_free(p); + } + gf_free(f); + } + gf_list_del(wid->features); + + if (wid->wpack) widget_package_del(wm, wid->wpack); + gf_free(wid); +} + +static void wm_delete_interface_instance(GF_WidgetManager *wm, GF_WidgetInterfaceInstance *bifce) +{ + if (bifce->hostname) gf_free(bifce->hostname); + if (bifce->obj) { + JS_SetPrivate(wm->ctx, bifce->obj, NULL); + gf_js_remove_root(wm->ctx, &bifce->obj, GF_JSGC_OBJECT); + } + gf_free(bifce); +} + +static void wm_delete_widget_instance(GF_WidgetManager *wm, GF_WidgetInstance *widg) +{ + + while (gf_list_count(widg->components)) { + GF_WidgetComponentInstance *comp = gf_list_get(widg->components, 0); + gf_list_rem(widg->components, 0); + if (comp->wid) wm_delete_widget_instance(wm, comp->wid); + gf_free(comp); + } + gf_list_del(widg->components); + + while (gf_list_count(widg->bound_ifces)) { + GF_WidgetInterfaceInstance *bifce = gf_list_get(widg->bound_ifces, 0); + gf_list_rem(widg->bound_ifces, 0); + wm_delete_interface_instance(wm, bifce); + } + gf_list_del(widg->bound_ifces); + + gf_list_del(widg->output_triggers); + + if (widg->obj) { + JS_SetPrivate(wm->ctx, widg->obj, NULL); + gf_js_remove_root(wm->ctx, &widg->obj, GF_JSGC_OBJECT); + } + gf_list_del_item(wm->widget_instances, widg); + widg->widget->nb_instances--; + if (!widg->widget->nb_instances) wm_delete_widget(wm, widg->widget); + + if (!widg->permanent) { + gf_cfg_del_section(wm->term->user->config, widg->secname); + gf_cfg_set_key(wm->term->user->config, "Widgets", widg->secname, NULL); + } + if (widg->mpegu_context) gf_xml_dom_del(widg->mpegu_context); + + gf_free(widg); +} + + + +static JSBool wm_widget_call_script(GF_WidgetInstance *wid, GF_WidgetPin *pin, uintN argc, jsval *argv, jsval *rval) +{ + jsval fval; + if (!wid->scene_context || !wid->scene_global) return JS_FALSE; + + /*if on_load property is assigned to this widget, add an event listener on the root.*/ + JS_LookupProperty(wid->scene_context, wid->scene_global, pin->node, &fval); + if (JSVAL_IS_OBJECT(fval)) { + JS_CallFunctionValue(wid->scene_context, wid->scene_global, fval, argc, argv, rval); + } + return JS_TRUE; +} + +static JSBool wm_widget_set_scene_input_value(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, u32 type, GF_WidgetInstance *wid, GF_WidgetPin *param, const char *value) +{ + char *str_val; + GF_Node *n; + GF_FieldInfo info; + GF_WidgetMessage *msg; + GF_WidgetInterface *ifce; + + if (!wid && obj) wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + if (!wid->scene) return JS_TRUE; + + if (!param) { + if (!JSVAL_IS_OBJECT(argv[0])) return JS_TRUE; + + switch (type) { + /*set_input*/ + case 0: + if (argc!=2) return JS_FALSE; + param = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + break; + /*call_input_action*/ + case 1: + msg = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + param = msg ? msg->input_action : NULL; + break; + /*bind_interface*/ + case 2: + ifce = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + param = ifce ? ifce->bind_action : NULL; + break; + /*unbind_interface*/ + case 3: + ifce = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + param = ifce ? ifce->unbind_action : NULL; + break; + } + } + + if (!param || !param->node) return JS_TRUE; + /*this is a script call*/ + if (!param->attribute) { + return wm_widget_call_script(wid, param, 0, NULL, rval); + } + + n = gf_sg_find_node_by_name(wid->scene, param->node); + if (!n) return JS_TRUE; + + if (param->in_action) return JS_TRUE; + + param->in_action = 1; + +#ifndef GPAC_DISABLE_SVG + if (n->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) { + u32 evt_type; + if (!type) { + char *_str_val = NULL; + if (value) { + str_val = (char *)value; + } else { + if (!JSVAL_IS_STRING(argv[1])) goto exit; + str_val = _str_val = SMJS_CHARS(c, argv[1]); + } + + /* first check if the set_input refers to an attribute name or to an event name */ + evt_type = gf_dom_event_type_by_name(param->attribute); + + /*events are not allowed for and */ + if (evt_type == GF_EVENT_UNKNOWN) { + /* modify an attribute */ + if (!strcmp(param->attribute, "textContent")) { + gf_dom_set_textContent(n, (char *)str_val); + gf_node_changed(n, NULL); + } + else { + if (gf_node_get_attribute_by_name(n, param->attribute, 0, 1, 0, &info)==GF_OK) { + gf_svg_parse_attribute(n, &info, (char *)str_val, 0); + if (info.fieldType==XMLRI_datatype) gf_node_dirty_set(n, GF_SG_SVG_XLINK_HREF_DIRTY, 0); + gf_node_changed(n, &info); + } + } + } + SMJS_FREE(c, _str_val); + + } else { + GF_DOM_Event evt; + memset(&evt, 0, sizeof(GF_DOM_Event)); + /* first check if the set_input refers to an attribute name or to an event name */ + evt_type = gf_dom_event_type_by_name(param->attribute); + /* launch an event */ + if (evt_type != GF_EVENT_UNKNOWN) { + evt.type = evt_type; + gf_dom_event_fire(n, &evt); + } else { + /*should we fire a DOMAttrModified event ? to clarify in the spec*/ + + if (gf_node_get_attribute_by_name(n, param->attribute, 0, 1, 0, &info)==GF_OK) { + evt.bubbles = 1; + evt.type = GF_EVENT_ATTR_MODIFIED; + evt.attr = &info; + gf_dom_event_fire(n, &evt); + } + } + } + } else +#endif + + +#ifndef GPAC_DISABLE_VRML + { + if (gf_node_get_field_by_name(n, param->attribute, &info) != GF_OK) return JS_TRUE; + + if (!type) { + char *_str_val = NULL; + jsdouble val; + + switch (info.fieldType) { + case GF_SG_VRML_SFSTRING: + if (value) { + str_val = (char *)value; + } else { + if (!JSVAL_IS_STRING(argv[1]))goto exit; + str_val = SMJS_CHARS(c, argv[1]); + } + if ( ((SFString*)info.far_ptr)->buffer) gf_free(((SFString*)info.far_ptr)->buffer); + ((SFString*)info.far_ptr)->buffer = str_val ? gf_strdup(str_val) : NULL; + break; + case GF_SG_VRML_SFBOOL: + if (value) *((SFBool*)info.far_ptr) = (!strcmp(value, "true")) ? 1 : 0; + else if (JSVAL_IS_BOOLEAN(argv[1])) *((SFBool*)info.far_ptr) = JSVAL_TO_BOOLEAN(argv[1]); + else if (JSVAL_IS_INT(argv[1])) *((SFBool*)info.far_ptr) = JSVAL_TO_INT(argv[1]); + else if (JSVAL_IS_STRING(argv[1])) { + str_val = SMJS_CHARS(c, argv[1]); + *((SFBool*)info.far_ptr) = (str_val && !strcmp(str_val, "true")) ? 1 : 0; + SMJS_FREE(c, str_val); + } else + goto exit; + break; + case GF_SG_VRML_SFINT32: + if (value) *((SFInt32*)info.far_ptr) = (s32) atof(value); + else if (JSVAL_IS_INT(argv[1])) *((SFInt32*)info.far_ptr) = JSVAL_TO_INT(argv[1]); + else if (JSVAL_IS_NUMBER(argv[1])) { + JS_ValueToNumber(c, argv[1], &val); + *((SFInt32*)info.far_ptr) = (s32) val; + } else if (JSVAL_IS_STRING(argv[1])) { + Double a_val; + str_val = SMJS_CHARS(c, argv[1]); + a_val = str_val ? atof(str_val) : 0; + *((SFInt32*)info.far_ptr) = (s32) a_val; + SMJS_FREE(c, str_val); + } else + goto exit; + break; + case GF_SG_VRML_SFFLOAT: + if (value) *((SFFloat*)info.far_ptr) = FLT2FIX(atof(value)); + else if (JSVAL_IS_INT(argv[1])) *((SFFloat *)info.far_ptr) = INT2FIX( JSVAL_TO_INT(argv[1]) ); + else if (JSVAL_IS_NUMBER(argv[1])) { + JS_ValueToNumber(c, argv[1], &val); + *((SFFloat *)info.far_ptr) = FLT2FIX( val ); + } else if (JSVAL_IS_STRING(argv[1])) { + Double a_val; + str_val = SMJS_CHARS(c, argv[1]); + a_val = str_val ? atof(str_val) : 0; + *((SFFloat*)info.far_ptr) = FLT2FIX(a_val); + SMJS_FREE(c, str_val); + } else + goto exit; + break; + case GF_SG_VRML_SFTIME: + if (value) *((SFTime*)info.far_ptr) = atof(value); + else if (JSVAL_IS_INT(argv[1])) *((SFTime *)info.far_ptr) = JSVAL_TO_INT(argv[1]); + else if (JSVAL_IS_NUMBER(argv[1])) { + JS_ValueToNumber(c, argv[1], &val); + *((SFTime *)info.far_ptr) = val; + } else if (JSVAL_IS_STRING(argv[1])) { + Double a_val; + str_val = SMJS_CHARS(c, argv[1]); + a_val = str_val ? atof(str_val) : 0; + *((SFTime *)info.far_ptr) = a_val; + SMJS_FREE(c, str_val); + } else + goto exit; + break; + case GF_SG_VRML_MFSTRING: + if (value) { + str_val = (char *)value; + } else { + if (!JSVAL_IS_STRING(argv[1])) goto exit; + str_val = _str_val = SMJS_CHARS(c, argv[1]); + } + if ( ((GenMFField *)info.far_ptr)->count != 1) { + gf_sg_vrml_mf_reset(info.far_ptr, GF_SG_VRML_MFSTRING); + gf_sg_vrml_mf_alloc(info.far_ptr, GF_SG_VRML_MFSTRING, 1); + } + if ( ((MFString*)info.far_ptr)->vals[0]) gf_free( ((MFString*)info.far_ptr)->vals[0] ); + ((MFString*)info.far_ptr)->vals[0] = str_val ? gf_strdup(str_val) : NULL; + + SMJS_FREE(c, _str_val); + break; + } + } + + //if this is a script eventIn call directly script + if ((n->sgprivate->tag==TAG_MPEG4_Script) +#ifndef GPAC_DISABLE_X3D + || (n->sgprivate->tag==TAG_X3D_Script) +#endif + ) + gf_sg_script_event_in(n, &info); + + gf_node_changed(n, &info); + + /*if this is an exposedField, route it*/ + if (info.eventType==GF_SG_EVENT_EXPOSED_FIELD) { + gf_node_event_out(n, info.fieldIndex); + } + } +#endif /*GPAC_DISABLE_VRML*/ + +exit: + param->in_action = 0; + return JS_TRUE; +} + + +static JSBool SMJS_FUNCTION(wm_widget_set_input) +{ + SMJS_OBJ + SMJS_ARGS + SMJS_DECL_RVAL + return wm_widget_set_scene_input_value(c, obj, argc, argv, rval, 0, NULL, NULL, NULL); +} +static JSBool SMJS_FUNCTION(wm_widget_call_input_action) +{ + SMJS_OBJ + SMJS_ARGS + SMJS_DECL_RVAL + return wm_widget_set_scene_input_value(c, obj, 1, argv, rval, 1, NULL, NULL, NULL); +} + + +static JSBool SMJS_FUNCTION(wm_widget_call_input_script) +{ + GF_WidgetMessage *msg; + GF_WidgetPin *param; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || (argc!=2) ) return JS_FALSE; + if (!wid->scene) return JS_TRUE; + + if (!JSVAL_IS_OBJECT(argv[0])) return JS_TRUE; + msg = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + param = msg ? msg->input_action : NULL; + if (!param || !param->node || param->attribute) return JS_FALSE; + + if (JSVAL_IS_OBJECT(argv[1])) { + jsval *args; + JSObject *list = JSVAL_TO_OBJECT(argv[1]); + u32 i, count; + JS_GetArrayLength(c, list, (jsuint*) &count); + args = gf_malloc(sizeof(jsval)*count); + for (i=0; ijs_fun_val) { + gf_js_remove_root(handler->js_context, &handler->js_fun_val, GF_JSGC_VAL); + handler->js_fun_val=0; + } + } +} + +static SVG_handlerElement *wm_create_scene_listener(GF_WidgetInstance *wid, GF_WidgetPin *param) +{ + /*FIXME - we need to split SVG and base DOM !!*/ +#ifdef GPAC_DISABLE_SVG + return NULL; +#else + u32 evt_type, att_name; + GF_Node *listener; + GF_FieldInfo info; + GF_Node *n = NULL; + SVG_handlerElement *handler; + + evt_type = GF_EVENT_ATTR_MODIFIED; + n = gf_sg_find_node_by_name(wid->scene, param->node); + if (!n) + return NULL; + + att_name = 0; + +#ifndef GPAC_DISABLE_SVG + if (n->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) { + /* first check if the set_input refers to an attribute name or to an event name */ + evt_type = gf_dom_event_type_by_name(param->attribute); + if (evt_type == GF_EVENT_UNKNOWN) { + evt_type = GF_EVENT_ATTR_MODIFIED; + + /* modify textContent */ + if (!strcmp(param->attribute, "textContent")) { + att_name = (u32) -1; + } + /* modify an attribute */ + else if (gf_node_get_attribute_by_name(n, param->attribute, 0, 1, 0, &info)==GF_OK) { + att_name = info.fieldIndex; + } + else { + return NULL; + } + } + } else +#endif + { + if (gf_node_get_field_by_name(n, param->attribute, &info) != GF_OK) + return NULL; + att_name = info.fieldIndex; + } + + listener = gf_node_new(wid->scene, TAG_SVG_listener); + + handler = (SVG_handlerElement *) gf_node_new(wid->scene, TAG_SVG_handler); + /*we register the handler with the listener node to avoid modifying the DOM*/ + gf_node_register((GF_Node *)handler, listener); + gf_node_list_add_child(& ((GF_ParentNode *)listener)->children, (GF_Node*)handler); + handler->sgprivate->UserCallback = wm_handler_destroy; + + /*create attributes if needed*/ + gf_node_get_attribute_by_tag(listener, TAG_XMLEV_ATT_event, 1, 0, &info); + ((XMLEV_Event*)info.far_ptr)->type = evt_type; + ((XMLEV_Event*)info.far_ptr)->parameter = att_name; + gf_node_get_attribute_by_tag(listener, TAG_XMLEV_ATT_handler, 1, 0, &info); + ((XMLRI*)info.far_ptr)->target = (GF_Node*)handler; + gf_node_get_attribute_by_tag(listener, TAG_XMLEV_ATT_target, 1, 0, &info); + ((XMLRI*)info.far_ptr)->target = n; + + gf_node_get_attribute_by_tag((GF_Node*)handler, TAG_XMLEV_ATT_event, 1, 0, &info); + ((XMLEV_Event*)info.far_ptr)->type = evt_type; + ((XMLEV_Event*)info.far_ptr)->parameter = att_name; + + gf_node_dom_listener_add((GF_Node *) n, listener); + + return handler; +#endif +} + +static void wm_component_activation_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *observer, Bool unload) +{ + JSObject *obj; + JSContext *c; + GF_WidgetInstance *wid; + GF_WidgetComponent *comp; + SVG_handlerElement *handler = (SVG_handlerElement *)hdl; + + c = handler->js_context; + obj = handler->evt_listen_obj; + if (!c || !obj) return; + wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return; + + comp = (GF_WidgetComponent *)handler->js_fun; + if (unload) { + wm_deactivate_component(c, wid, comp, NULL); + } else { + wm_activate_component(c, wid, comp, 0); + } +} +static void wm_component_activate_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *observer) +{ + wm_component_activation_event(hdl, evt, observer, 0); +} +static void wm_component_deactivate_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *observer) +{ + wm_component_activation_event(hdl, evt, observer, 1); +} + +static void wm_widget_set_pref_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *observer) +{ + char *att; + SVG_handlerElement *handler = (SVG_handlerElement *)hdl; + GF_WidgetInstance *wid = (GF_WidgetInstance *) handler->evt_listen_obj; + GF_WidgetPreference *pref = (GF_WidgetPreference *) handler->js_fun; + + if (evt->type != GF_EVENT_ATTR_MODIFIED) return; + + if (evt->detail == (u32) -1) { + att = gf_dom_flatten_textContent(evt->target); + } else { + att = gf_node_dump_attribute(evt->target, evt->attr); + if (!att) return; + } + gf_cfg_set_key(wid->widget->wm->term->user->config, wid->secname, pref->name, att); + gf_free(att); +} + +static void on_widget_activated(JSContext *c, JSObject *obj) +{ + jsval funval, rval; + u32 i, count; + GF_XMLNode *context = NULL; + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || wid->activated) return; + + /*widget is now activated*/ + wid->activated = 1; + + /*for all components, setup bindings on activateTrigger & deactivateTrigger*/ + count = gf_list_count(wid->widget->main->components); + for (i=0; iwidget->main->components, i); + /*setup listener*/ + if (comp->activateTrigger && comp->activateTrigger->attribute) { + SVG_handlerElement *a_hdl = wm_create_scene_listener(wid, comp->activateTrigger); + if (!a_hdl) return; + a_hdl->evt_listen_obj = obj; + a_hdl->js_context = c; + a_hdl->js_fun = comp; + a_hdl->handle_event = wm_component_activate_event; + } + /*setup listener*/ + if (comp->deactivateTrigger && comp->deactivateTrigger->attribute) { + SVG_handlerElement *a_hdl = wm_create_scene_listener(wid, comp->deactivateTrigger); + if (!a_hdl) continue; + a_hdl->evt_listen_obj = obj; + a_hdl->js_context = c; + a_hdl->js_fun = comp; + a_hdl->handle_event = wm_component_deactivate_event; + } + } + + if (wid->mpegu_context) + context = gf_xml_dom_get_root(wid->mpegu_context); + + /*load preferences*/ + count = gf_list_count(wid->widget->main->preferences); + for (i=0; iwidget->main->preferences, i); + + + /*get stored value for this preference*/ + value = gf_cfg_get_key(wid->widget->wm->term->user->config, wid->secname, pref->name); + /*if none found, use preference*/ + if (!value) value = pref->value; + + /*and overload with migrated context*/ + if (context) { + GF_XMLNode *pref_node; + u32 j=0; + while ((pref_node = gf_list_enum(context->content, &j))) { + const char *att; + if (pref_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(pref_node->name, "preference")) continue; + att = wm_xml_get_attr(pref_node, "name"); + if (!att) continue; + if (strcmp(att, pref->name)) continue; + + att = wm_xml_get_attr(pref_node, "value"); + if (att) value = att; + break; + } + } + + if (pref->connectTo) { + SVG_handlerElement *hdl; + + if (value) + wm_widget_set_scene_input_value(NULL, NULL, 0, 0, 0, 0, wid, pref->connectTo, value); + + /*preference is read only, do not setup listener*/ + if (pref->flags & GF_WM_PREF_READONLY) continue; + /*preference is migratable only, do not setup listener*/ + if (!(pref->flags & GF_WM_PREF_SAVE)) continue; + + /*create the listener*/ + hdl = wm_create_scene_listener(wid, pref->connectTo); + if (!hdl) continue; + + hdl->evt_listen_obj = wid; + hdl->js_fun = pref; + hdl->handle_event = wm_widget_set_pref_event; + + } + } + if (count && wid->widget->main->restoredAction) { + wm_widget_set_scene_input_value(wid->widget->wm->ctx, wid->obj, 0, NULL, &rval, 0, wid, wid->widget->main->restoredAction, NULL); + } + + if (wid->mpegu_context) { + gf_xml_dom_del(wid->mpegu_context); + wid->mpegu_context = NULL; + } + + gf_sg_lock_javascript(wid->widget->wm->ctx, 1); + /*refresh all interface bindings*/ + JS_LookupProperty(wid->widget->wm->ctx, wid->widget->wm->obj, "check_bindings", &funval); + if (JSVAL_IS_OBJECT(funval)) { + JS_CallFunctionValue(wid->widget->wm->ctx, wid->widget->wm->obj, funval, 0, 0, &rval); + } + + /*if on_load property is assigned to this widget, call it.*/ + JS_LookupProperty(c, obj, "on_load", &funval); + if (JSVAL_IS_OBJECT(funval)) { + JS_CallFunctionValue(wid->widget->wm->ctx, wid->obj, funval, 0, 0, &rval); + } + gf_sg_lock_javascript(wid->widget->wm->ctx, 0); +} + + +static void wm_widget_load_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *observer) +{ + JSObject *obj; + JSContext *c; + SVG_handlerElement *handler = (SVG_handlerElement *)hdl; + + c = handler->js_context; + obj = handler->evt_listen_obj; + if (!c || !obj) return; + + on_widget_activated(c, obj); +} + + +static JSBool SMJS_FUNCTION(wm_widget_activate) +{ + SVG_handlerElement *handler; + GF_MediaObject *mo; + Bool direct_trigger = 0; + MFURL url; + SFURL _url; + GF_Node *inl; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || !argc) return JS_FALSE; + + if (!JSVAL_IS_OBJECT(argv[0])) return JS_FALSE; + + inl = gf_sg_js_get_node(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!inl) return JS_FALSE; + + _url.OD_ID = 0; + _url.url = gf_url_concatenate(wid->widget->url, wid->widget->main->relocated_src); + url.count = 1; + url.vals = &_url; + mo = gf_mo_register(inl, &url, 0, 1); + if (mo) { + wid->scene = gf_mo_get_scenegraph(mo); + if (wid->scene && gf_sg_get_root_node(wid->scene)) direct_trigger = 1; + } + if (_url.url) gf_free(_url.url); + + wid->anchor = inl; + + if (direct_trigger) { + on_widget_activated(c, obj); + } else { +#ifndef GPAC_DISABLE_SVG + handler = gf_dom_listener_build(inl, GF_EVENT_SCENE_ATTACHED, 0); + handler->handle_event = wm_widget_load_event; + handler->js_context = c; + handler->evt_listen_obj = obj; +#endif + } + + return JS_TRUE; +} + + +static void wm_handle_dom_event(GF_Node *hdl, GF_DOM_Event *event, GF_Node *observer) +{ + GF_FieldInfo info; + GF_Node *n; + jsval argv[1], rval, jsfun; + SVG_handlerElement *handler = (SVG_handlerElement *) hdl; + GF_WidgetPin *param = handler->js_fun; + GF_WidgetInstance *wid = (GF_WidgetInstance *)handler->evt_listen_obj; + + if (!wid->scene) + return; + + n = gf_sg_find_node_by_name(wid->scene, param->node); + if (!n) return; + + /*this is a regular event output*/ + if (event->type != GF_EVENT_ATTR_MODIFIED) { + jsfun = (jsval) handler->js_fun_val; + if (JSVAL_IS_OBJECT(jsfun)) + JS_CallFunctionValue(handler->js_context, wid->obj, (jsval) handler->js_fun_val, 0, 0, &rval); + return; + } + + /*otherwise this is a node.attr output through DOMAttributeModified*/ + argv[0] = JSVAL_NULL; + +#ifndef GPAC_DISABLE_SVG + if (n->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) { + if (!strcmp(param->attribute, "textContent")) { + char *txt = gf_dom_flatten_textContent(n); + argv[0] = STRING_TO_JSVAL( JS_NewStringCopyZ(handler->js_context, txt ? txt : "") ); + if (txt) gf_free(txt); + } else if (gf_node_get_attribute_by_name(n, param->attribute, 0, 1, 0, &info)==GF_OK) { + char *attValue; + if (event->attr->fieldIndex != info.fieldIndex) return; + + attValue = gf_node_dump_attribute(n, &info); + argv[0] = STRING_TO_JSVAL( JS_NewStringCopyZ(handler->js_context, attValue) ); + if (attValue) gf_free(attValue); + } else { + return; + } + } else +#endif + { + if (gf_node_get_field_by_name(n, param->attribute, &info) != GF_OK) return; + if (event->attr->fieldIndex != info.fieldIndex) return; + + switch (info.fieldType) { + case GF_SG_VRML_SFSTRING: + argv[0] = STRING_TO_JSVAL( JS_NewStringCopyZ(handler->js_context, ((SFString*)info.far_ptr)->buffer ) ); + break; + case GF_SG_VRML_SFINT32: + argv[0] = INT_TO_JSVAL( *((SFInt32*)info.far_ptr) ); + break; + case GF_SG_VRML_SFBOOL: + argv[0] = BOOLEAN_TO_JSVAL( *((SFBool*)info.far_ptr) ); + break; + case GF_SG_VRML_SFFLOAT: + argv[0] = DOUBLE_TO_JSVAL( JS_NewDouble(handler->js_context, FIX2FLT( *((SFFloat*)info.far_ptr) ) ) ); + break; + case GF_SG_VRML_SFTIME: + argv[0] = DOUBLE_TO_JSVAL( JS_NewDouble(handler->js_context, *((SFTime *)info.far_ptr) ) ); + break; + } + } + + jsfun = (jsval) handler->js_fun_val; + if (JSVAL_IS_OBJECT(jsfun)) + JS_CallFunctionValue(handler->js_context, wid->obj, (jsval) handler->js_fun_val, 1, argv, &rval); +} + +static JSBool SMJS_FUNCTION(wm_widget_get_param_value) +{ + GF_Node *n; + GF_FieldInfo info; + GF_WidgetPin *param; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || !wid->scene || !argc || !JSVAL_IS_OBJECT(argv[0]) ) return JS_FALSE; + + param = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!param) return JS_FALSE; + + if (!param->node) { + if (param->default_value) { + SMJS_SET_RVAL( STRING_TO_JSVAL( JS_NewStringCopyZ(c, param->default_value) ) ); + return JS_TRUE; + } + return JS_FALSE; + } + + n = gf_sg_find_node_by_name(wid->scene, param->node); + if (!n) return JS_FALSE; + +#ifndef GPAC_DISABLE_SVG + if (n->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) { + if (!strcmp(param->attribute, "textContent")) { + char *txt = gf_dom_flatten_textContent(n); + SMJS_SET_RVAL( STRING_TO_JSVAL( JS_NewStringCopyZ(c, txt ? txt : "") )); + if (txt) gf_free(txt); + } else if (gf_node_get_attribute_by_name(n, param->attribute, 0, 1, 0, &info)==GF_OK) { + char *attValue = gf_node_dump_attribute(n, &info); + SMJS_SET_RVAL( STRING_TO_JSVAL( JS_NewStringCopyZ(c, attValue) )); + if (attValue) gf_free(attValue); + } else { + return JS_FALSE; + } + } else +#endif + { + if (gf_node_get_field_by_name(n, param->attribute, &info) != GF_OK) return JS_FALSE; + + switch (info.fieldType) { + case GF_SG_VRML_SFSTRING: + SMJS_SET_RVAL( STRING_TO_JSVAL( JS_NewStringCopyZ(c, ((SFString*)info.far_ptr)->buffer ) ) ); + break; + case GF_SG_VRML_SFINT32: + SMJS_SET_RVAL( INT_TO_JSVAL( *((SFInt32*)info.far_ptr) )); + break; + case GF_SG_VRML_SFBOOL: + SMJS_SET_RVAL(BOOLEAN_TO_JSVAL( *((SFBool*)info.far_ptr) )); + break; + case GF_SG_VRML_SFFLOAT: + SMJS_SET_RVAL( DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT( *((SFFloat*)info.far_ptr) ) ) )); + break; + case GF_SG_VRML_SFTIME: + SMJS_SET_RVAL( DOUBLE_TO_JSVAL( JS_NewDouble(c, *((SFTime *)info.far_ptr) ) )); + break; + } + } + + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_get_message_param) +{ + GF_WidgetPin *par = NULL; + SMJS_OBJ + SMJS_ARGS + GF_WidgetMessage *msg = (GF_WidgetMessage *)JS_GetPrivate(c, obj); + if (!msg || !argc ) return JS_FALSE; + + if (JSVAL_IS_INT(argv[0])) { + u32 idx = JSVAL_TO_INT(argv[0]); + par = gf_list_get(msg->params, idx); + } else if (JSVAL_IS_STRING(argv[0])) { + u32 i, count = gf_list_count(msg->params); + char *name = SMJS_CHARS(c, argv[0]); + for (i=0; iparams, i); + if (!strcmp(par->name, name)) break; + par = NULL; + } + SMJS_FREE(c, name); + } + + if (par) { + JSObject *obj = JS_NewObject(c, &msg->ifce->content->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, obj, par); + JS_DefineProperty(c, obj, "name", STRING_TO_JSVAL( JS_NewStringCopyZ(c, par->name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, obj, "is_input", BOOLEAN_TO_JSVAL( (par->type == GF_WM_PARAM_OUTPUT) ? JS_FALSE : JS_TRUE), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + switch (par->script_type) { + case GF_WM_PARAM_SCRIPT_BOOL: + JS_DefineProperty(c, obj, "script_type", STRING_TO_JSVAL( JS_NewStringCopyZ(c, "boolean") ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + break; + case GF_WM_PARAM_SCRIPT_NUMBER: + JS_DefineProperty(c, obj, "script_type", STRING_TO_JSVAL( JS_NewStringCopyZ(c, "number") ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + break; + case GF_WM_PARAM_SCRIPT_STRING: + default: + JS_DefineProperty(c, obj, "script_type", STRING_TO_JSVAL( JS_NewStringCopyZ(c, "string") ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + break; + } + SMJS_SET_RVAL( OBJECT_TO_JSVAL(obj) ); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_get_message) +{ + GF_WidgetMessage *msg; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInterface *ifce = (GF_WidgetInterface*)JS_GetPrivate(c, obj); + if (!ifce || !argc) return JS_FALSE; + msg = NULL; + + if (JSVAL_IS_INT(argv[0])) { + u32 idx; + idx = JSVAL_TO_INT(argv[0]); + msg = gf_list_get(ifce->messages, idx); + } else if (JSVAL_IS_STRING(argv[0])) { + u32 i, count = gf_list_count(ifce->messages); + char *name = SMJS_CHARS(c, argv[0]); + for (i=0; imessages, i); + if (!strcmp(msg->name, name)) break; + msg = NULL; + } + SMJS_FREE(c, name); + } + if (msg) { + JSObject *obj = JS_NewObject(c, &ifce->content->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, obj, msg); + JS_DefineProperty(c, obj, "num_params", INT_TO_JSVAL( gf_list_count(msg->params) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, obj, "name", STRING_TO_JSVAL( JS_NewStringCopyZ(c, msg->name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, obj, "is_input", BOOLEAN_TO_JSVAL( msg->is_output ? JS_FALSE : JS_TRUE ) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, obj, "has_output_trigger", BOOLEAN_TO_JSVAL( msg->output_trigger ? JS_TRUE : JS_FALSE) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, obj, "has_input_action", BOOLEAN_TO_JSVAL( (msg->input_action && msg->input_action->attribute) ? JS_TRUE : JS_FALSE) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, obj, "has_script_input", BOOLEAN_TO_JSVAL( (msg->input_action && !msg->input_action->attribute) ? JS_TRUE : JS_FALSE) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineFunction(c, obj, "get_param", wm_widget_get_message_param, 1, 0); + + SMJS_SET_RVAL( OBJECT_TO_JSVAL(obj) ); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_get_component) +{ + char *comp_id; + u32 i, count; + GF_WidgetComponentInstance *comp_inst; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || !argc || !JSVAL_IS_STRING(argv[0]) ) return JS_FALSE; + + comp_id = SMJS_CHARS(c, argv[0]); + count = gf_list_count(wid->components); + for (i=0; icomponents, i); + if (comp_inst->comp->id && !strcmp(comp_inst->comp->id, comp_id)) { + SMJS_SET_RVAL( OBJECT_TO_JSVAL(comp_inst->wid->obj) ); + SMJS_FREE(c, comp_id); + return JS_TRUE; + } + } + /*if requested load the component*/ + if ((argc==2) && JSVAL_IS_BOOLEAN(argv[1]) && (JSVAL_TO_BOOLEAN(argv[1])==JS_TRUE) ) { + count = gf_list_count(wid->widget->main->components); + for (i=0; iwidget->main->components, i); + if (!comp->id || strcmp(comp->id, comp_id)) continue; + + comp_inst = wm_activate_component(c, wid, comp, 1); + if (comp_inst) { + SMJS_SET_RVAL( OBJECT_TO_JSVAL(comp_inst->wid->obj) ); + SMJS_FREE(c, comp_id); + return JS_TRUE; + } + SMJS_FREE(c, comp_id); + return JS_TRUE; + } + } + + SMJS_FREE(c, comp_id); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_get_interface) +{ + u32 idx; + GF_WidgetInterface *ifce; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || !argc || !JSVAL_IS_INT(argv[0]) ) return JS_FALSE; + + idx = JSVAL_TO_INT(argv[0]); + ifce = gf_list_get(wid->widget->main->interfaces, idx); + + if (ifce) { + if (!ifce->obj) { + ifce->obj = JS_NewObject(c, &wid->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, ifce->obj, ifce); + JS_DefineProperty(c, ifce->obj, "num_messages", INT_TO_JSVAL( gf_list_count(ifce->messages) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, ifce->obj, "type", STRING_TO_JSVAL( JS_NewStringCopyZ(c, ifce->type) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, ifce->obj, "serviceProvider", BOOLEAN_TO_JSVAL( ifce->provider ? JS_TRUE : JS_FALSE ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, ifce->obj, "multipleBinding", BOOLEAN_TO_JSVAL( ifce->multiple_binding ? JS_TRUE : JS_FALSE ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineFunction(c, ifce->obj, "get_message", wm_widget_get_message, 1, 0); + gf_js_add_root(c, &ifce->obj, GF_JSGC_OBJECT); + } + SMJS_SET_RVAL( OBJECT_TO_JSVAL(ifce->obj) ); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_bind_output_trigger) +{ + GF_WidgetMessage *msg; + GF_WidgetPin *param; + SVG_handlerElement *handler; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + + SMJS_SET_RVAL( BOOLEAN_TO_JSVAL(JS_FALSE) ); + if (!wid || !wid->scene || (argc!=3)) return JS_TRUE; + + if (!JSVAL_IS_OBJECT(argv[0])) return JS_TRUE; + if (!JSVAL_IS_OBJECT(argv[1])) return JS_TRUE; + if (!JSVAL_IS_OBJECT(argv[2])) return JS_TRUE; + + msg = (GF_WidgetMessage *)JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0])); + if (!msg) return JS_TRUE; + param = msg->output_trigger; + if (!param) return JS_TRUE; + + + handler = wm_create_scene_listener(wid, param); + if (!handler) return JS_TRUE; + handler->js_fun_val = * (u64 *) & argv[1]; + gf_js_add_root(c, &handler->js_fun_val, GF_JSGC_VAL); + handler->evt_listen_obj = wid; + handler->js_fun = param; + handler->js_context = c; + handler->handle_event = wm_handle_dom_event; + handler->sgprivate->UserPrivate = JSVAL_TO_OBJECT(argv[2]); + + gf_list_add(wid->output_triggers, handler); + SMJS_SET_RVAL( BOOLEAN_TO_JSVAL(JS_TRUE) ); + + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_get_context) +{ + GF_BitStream *bs; + u32 i, count; + const char *str; + char *att; + SMJS_OBJ + //SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + if (!wid->scene) { + SMJS_SET_RVAL(JSVAL_NULL); + return JS_TRUE; + } + + bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); + str = "\n\n"; + gf_bs_write_data(bs, (u8 *) str, strlen(str) ); + + count = gf_list_count(wid->widget->main->preferences); + for (i=0; iwidget->main->preferences, i); + + /*preference is read only, do not include in context*/ + if (pref->flags & GF_WM_PREF_READONLY) continue; + /*preference is not migratable, do not include in context*/ + if (!(pref->flags & GF_WM_PREF_MIGRATE)) continue; + + str = " name, strlen(pref->name) ); + + str = "\" value=\""; + gf_bs_write_data(bs, (u8 *) str, strlen(str) ); + + /*read from node*/ + if (pref->connectTo && pref->connectTo->attribute) { + GF_FieldInfo info; + GF_Node *n = gf_sg_find_node_by_name(wid->scene, pref->connectTo->node); + if (n) { + +#ifndef GPAC_DISABLE_SVG + if ((n->sgprivate->tag >= GF_NODE_FIRST_DOM_NODE_TAG) && !strcmp(pref->connectTo->attribute, "textContent")) { + char *txt = gf_dom_flatten_textContent(n); + gf_bs_write_data(bs, (u8 *) txt, strlen(txt) ); + } else +#endif + if (gf_node_get_field_by_name(n, pref->connectTo->attribute, &info)==GF_OK) { + att = gf_node_dump_attribute(n, &info); + if (att) { + gf_bs_write_data(bs, (u8 *) att, strlen(att) ); + gf_free(att); + } + } + } + } + /*read from config*/ + else { + att = (char *)gf_cfg_get_key(wid->widget->wm->term->user->config, wid->secname, pref->name); + if (!att) att = pref->value; + + if (att) gf_bs_write_data(bs, (u8 *) att, strlen(att) ); + } + + str = "\"/>\n"; + gf_bs_write_data(bs, (u8 *) str, strlen(str) ); + } + str = "\n"; + gf_bs_write_data(bs, (u8 *) str, strlen(str) ); + + gf_bs_write_u8(bs, 0); + att = NULL; + gf_bs_get_content(bs, &att, &count); + gf_bs_del(bs); + + SMJS_SET_RVAL( STRING_TO_JSVAL( JS_NewStringCopyZ(c, att) ) ); + gf_free(att); + + return JS_TRUE; +} + + +static JSBool wm_widget_getProperty(JSContext *c, JSObject *obj, SMJS_PROP_GETTER, jsval *vp) +{ + JSString *s; + char *prop_name; + const char *opt; + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + + if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; + prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); + if (!prop_name) return JS_FALSE; + + /* + Manifest properties + */ + if (!strcmp(prop_name, "manifest")) { + s = JS_NewStringCopyZ(c, wid->widget->manifest_path); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "url")) { + s = JS_NewStringCopyZ(c, wid->widget->local_path ? wid->widget->local_path : wid->widget->url); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "main")) { + s = JS_NewStringCopyZ(c, wid->widget->main->relocated_src); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "localizedSrc")) { + s = JS_NewStringCopyZ(c, wid->widget->main->src); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "mainEncoding")) { + s = JS_NewStringCopyZ(c, wid->widget->main->encoding); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "mainMimeType")) { + s = JS_NewStringCopyZ(c, wid->widget->main->mimetype); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "defaultWidth")) { + *vp = INT_TO_JSVAL(wid->widget->width); + } + else if (!strcmp(prop_name, "defaultHeight")) { + *vp = INT_TO_JSVAL(wid->widget->height); + } + else if (!strcmp(prop_name, "icons")) { + u32 i, count; + JSObject *arr; + count = gf_list_count(wid->widget->icons); + arr = JS_NewArrayObject(c, count, NULL); + for (i = 0; iwidget->icons, i); + if (icon) { + char *abs_reloc_url; + jsval icon_obj_val; + JSObject *icon_obj = JS_NewObject(c, &wid->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, icon_obj, icon); + JS_DefineProperty(c, icon_obj, "src", STRING_TO_JSVAL( JS_NewStringCopyZ(c, icon->src) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + if (strlen(icon->relocated_src)) abs_reloc_url = gf_url_concatenate(wid->widget->url, icon->relocated_src); + else abs_reloc_url = gf_strdup(""); + JS_DefineProperty(c, icon_obj, "relocated_src", STRING_TO_JSVAL( JS_NewStringCopyZ(c, abs_reloc_url) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, icon_obj, "width", INT_TO_JSVAL( icon->width ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, icon_obj, "height", INT_TO_JSVAL( icon->height ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + icon_obj_val = OBJECT_TO_JSVAL(icon_obj); + JS_SetElement(c, arr, i, &icon_obj_val); + gf_free(abs_reloc_url); + } + } + *vp = OBJECT_TO_JSVAL(arr); + } + else if (!strcmp(prop_name, "preferences")) { + u32 i, count; + JSObject *arr; + count = gf_list_count(wid->widget->main->preferences); + arr = JS_NewArrayObject(c, count, NULL); + for (i = 0; iwidget->main->preferences, i); + if (pref) { + jsval pref_obj_val; + JSObject *pref_obj = JS_NewObject(c, &wid->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, pref_obj, pref); + JS_DefineProperty(c, pref_obj, "name", STRING_TO_JSVAL( JS_NewStringCopyZ(c, pref->name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, pref_obj, "value", STRING_TO_JSVAL( JS_NewStringCopyZ(c, pref->value) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, pref_obj, "readonly", STRING_TO_JSVAL( JS_NewStringCopyZ(c, ((pref->flags & GF_WM_PREF_READONLY)?"true":"false")) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + pref_obj_val = OBJECT_TO_JSVAL(pref_obj); + JS_SetElement(c, arr, i, &pref_obj_val); + } + } + *vp = OBJECT_TO_JSVAL(arr); + } + else if (!strcmp(prop_name, "features")) { + u32 i, count; + JSObject *arr; + count = gf_list_count(wid->widget->features); + arr = JS_NewArrayObject(c, count, NULL); + for (i = 0; iwidget->features, i); + if (feat) { + jsval feat_obj_val; + JSObject *feat_obj = JS_NewObject(c, &wid->widget->wm->widgetAnyClass, 0, 0); + JS_SetPrivate(c, feat_obj, feat); + JS_DefineProperty(c, feat_obj, "name", STRING_TO_JSVAL( JS_NewStringCopyZ(c, feat->name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, feat_obj, "required", BOOLEAN_TO_JSVAL( (feat->required? JS_TRUE : JS_FALSE) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + { + u32 j, pcount; + JSObject *params_arr; + pcount = gf_list_count(feat->params); + params_arr = JS_NewArrayObject(c, pcount, NULL); + for (j=0; j < pcount; j++) { + GF_WidgetFeatureParam *param = gf_list_get(feat->params, j); + JSObject *param_obj = JS_NewObject(c, &wid->widget->wm->widgetAnyClass, 0, 0); + jsval param_obj_val; + JS_SetPrivate(c, param_obj, param); + JS_DefineProperty(c, param_obj, "name", STRING_TO_JSVAL( JS_NewStringCopyZ(c, param->name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, param_obj, "value", STRING_TO_JSVAL( JS_NewStringCopyZ(c, param->value) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + param_obj_val = OBJECT_TO_JSVAL(param_obj); + JS_SetElement(c, params_arr, j, ¶m_obj_val); + } + JS_DefineProperty(c, feat_obj, "params", OBJECT_TO_JSVAL(params_arr), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + } + feat_obj_val = OBJECT_TO_JSVAL(feat_obj); + JS_SetElement(c, arr, i, &feat_obj_val); + } + } + *vp = OBJECT_TO_JSVAL(arr); + } + + else if (!strcmp(prop_name, "components")) { + u32 i, count; + jsval val; + JSObject *arr; + count = gf_list_count(wid->components); + arr = JS_NewArrayObject(c, count, NULL); + for (i = 0; icomponents, i); + val = OBJECT_TO_JSVAL(comp->wid->obj); + JS_SetElement(c, arr, i, &val); + } + *vp = OBJECT_TO_JSVAL(arr); + } + else if (!strcmp(prop_name, "identifier")) { + s = JS_NewStringCopyZ(c, wid->widget->identifier); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "name")) { + s = JS_NewStringCopyZ(c, wid->widget->name); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "shortName")) { + s = JS_NewStringCopyZ(c, wid->widget->shortname); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "authorName")) { + s = JS_NewStringCopyZ(c, wid->widget->authorName); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "authorEmail")) { + s = JS_NewStringCopyZ(c, wid->widget->authorEmail); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "authorHref")) { + s = JS_NewStringCopyZ(c, wid->widget->authorHref); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "description")) { + s = JS_NewStringCopyZ(c, wid->widget->description); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "viewmodes")) { + if (wid->widget->viewmodes) s = JS_NewStringCopyZ(c, wid->widget->viewmodes); + else s = JS_NewStringCopyZ(c, ""); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "license")) { + s = JS_NewStringCopyZ(c, wid->widget->license); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "licenseHref")) { + s = JS_NewStringCopyZ(c, wid->widget->licenseHref); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "version")) { + s = JS_NewStringCopyZ(c, wid->widget->version); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "uuid")) { + s = JS_NewStringCopyZ(c, wid->widget->uuid); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "discardable")) { + *vp = BOOLEAN_TO_JSVAL( wid->widget->discardable ? JS_TRUE : JS_FALSE); + } + else if (!strcmp(prop_name, "multipleInstances")) { + *vp = BOOLEAN_TO_JSVAL( wid->widget->multipleInstance ? JS_TRUE : JS_FALSE); + } + + /* + Widget Manager special properties (common to all implementations) + */ + else if (!strcmp(prop_name, "permanent")) { + *vp = BOOLEAN_TO_JSVAL( wid->permanent ? JS_TRUE : JS_FALSE); + } + else if (!strcmp(prop_name, "is_component")) { + *vp = BOOLEAN_TO_JSVAL( wid->parent ? JS_TRUE : JS_FALSE); + } + else if (!strcmp(prop_name, "parent")) { + *vp = wid->parent ? OBJECT_TO_JSVAL(wid->parent->obj) : JSVAL_NULL; + } + else if (!strcmp(prop_name, "activated")) { + *vp = BOOLEAN_TO_JSVAL( wid->activated ? JS_TRUE : JS_FALSE); + } + else if (!strcmp(prop_name, "section")) { + s = JS_NewStringCopyZ(c, wid->secname); + *vp = STRING_TO_JSVAL(s); + } + else if (!strcmp(prop_name, "num_instances")) { + *vp = INT_TO_JSVAL( wid->widget->nb_instances); + } + else if (!strcmp(prop_name, "num_interfaces")) { + *vp = INT_TO_JSVAL( gf_list_count(wid->widget->main->interfaces)); + } + else if (!strcmp(prop_name, "num_components")) { + *vp = INT_TO_JSVAL( gf_list_count(wid->components)); + } + else if (!strcmp(prop_name, "num_bound_interfaces")) { + *vp = INT_TO_JSVAL( gf_list_count(wid->bound_ifces)); + } + /*all variables used by the WidgetManager script but not stored*/ + else if (!strcmp(prop_name, "originating_device_ip") + || !strcmp(prop_name, "originating_device") + || !strcmp(prop_name, "device") + ) { + } + /* + Widget properties, common to each implementation + */ + else { + char szName[1024]; + sprintf(szName, "WM:%s", prop_name); + opt = gf_cfg_get_key(wid->widget->wm->term->user->config, wid->secname, szName); + if (opt) { + Double val=0; + if (!strcmp(opt, "true")) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); + else if (!strcmp(opt, "false")) *vp = BOOLEAN_TO_JSVAL(JS_FALSE); + else if (sscanf(opt, "%lf", &val)==1) { + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, val) ); + } else { + s = JS_NewStringCopyZ(c, opt); + *vp = STRING_TO_JSVAL(s); + } + } + } + SMJS_FREE(c, prop_name); + return JS_TRUE; +} +static JSBool wm_widget_setProperty(JSContext *c, JSObject *obj, SMJS_PROP_SETTER, jsval *vp) +{ + char szVal[32]; + jsdouble val; + char *prop_name; + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + + if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; + prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); + + /*internal to WidgetManager, never stored*/ + if (!strcmp(prop_name, "permanent")) { + wid->permanent = (JSVAL_TO_BOOLEAN(*vp)==JS_TRUE) ? 1 : 0; + } + + /*any widget properties*/ + else { + char szName[1024], *value, *_val = NULL; + + if (JSVAL_IS_STRING(*vp)) { + value = _val = SMJS_CHARS(c, *vp); + if (!value) value = ""; + } + else if (JSVAL_IS_BOOLEAN(*vp)) { + strcpy(szVal, (JSVAL_TO_BOOLEAN(*vp)==JS_TRUE) ? "true" : "false"); + value = szVal; + } + else if (JSVAL_IS_NUMBER(*vp)) { + JS_ValueToNumber(c, *vp, &val); + sprintf(szVal, "%f", val); + value = szVal; + } else { + SMJS_FREE(c, prop_name); + return JS_TRUE; + } + + sprintf(szName, "WM:%s", prop_name); + gf_cfg_set_key(wid->widget->wm->term->user->config, wid->secname, szName, value); + SMJS_FREE(c, _val); + } + + SMJS_FREE(c, prop_name); + return JS_TRUE; +} + + + +static JSBool wm_widget_bind_interface_ex(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, Bool is_unbind) +{ + u32 i, count; + GF_WidgetInterfaceInstance *bifce; + GF_WidgetInterface *ifce; + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || !wid->scene) return JS_FALSE; + + ifce = NULL; + if (argc) { + if (!JSVAL_IS_OBJECT(argv[0])) return JS_FALSE; + ifce = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!ifce) return JS_FALSE; + } + + if (!is_unbind) { + char *hostname; + JSObject *cookie; + if ((argc<3) || !JSVAL_IS_OBJECT(argv[1]) || !JSVAL_IS_STRING(argv[2])) return JS_FALSE; + + cookie = JSVAL_TO_OBJECT(argv[1]); + hostname = SMJS_CHARS(c, argv[2]); + count = gf_list_count(wid->bound_ifces); + for (i=0; ibound_ifces, i); + if (!strcmp(bifce->ifce->type, ifce->type) && (bifce->cookie==cookie) ) { + SMJS_FREE(c, hostname); + return JS_TRUE; + } + } + GF_SAFEALLOC(bifce, GF_WidgetInterfaceInstance); + bifce->wid = wid; + bifce->ifce = ifce; + bifce->cookie = cookie; + bifce->hostname = gf_strdup(hostname); + SMJS_FREE(c, hostname); + gf_list_add(wid->bound_ifces, bifce); + + if (ifce->bind_action) { + return wm_widget_set_scene_input_value(c, obj, 1, argv, rval, 2, NULL, NULL, NULL); + } else { + widget_on_interface_bind(bifce, 0); + } + } else { + JSObject *cookie = NULL; + if ((argc==2) && JSVAL_IS_OBJECT(argv[1])) cookie = JSVAL_TO_OBJECT(argv[1]); + + count = gf_list_count(wid->bound_ifces); + for (i=0; ibound_ifces, i); + if (!ifce || ( !strcmp(bifce->ifce->type, ifce->type) && (bifce->cookie==cookie)) ) { + gf_list_rem(wid->bound_ifces, i); + if (bifce->ifce->unbind_action) { + wm_widget_set_scene_input_value(c, NULL, 0, NULL, rval, 3, wid, bifce->ifce->unbind_action, NULL); + } else { + widget_on_interface_bind(bifce, 1); + } + if (ifce) { + /*unregister our message handlers*/ + count = gf_list_count(wid->output_triggers); + for (i=0; ioutput_triggers, i); + GF_WidgetPin *param = handler->js_fun; + + if (handler->sgprivate->UserPrivate != cookie) continue; + found = 0; + c2 = gf_list_count(bifce->ifce->messages); + for (j=0; jifce->messages, j); + if (msg->output_trigger == param) { + found = 1; + break; + } + } + if (found) { + GF_Node *listener = handler->sgprivate->parents->node; + gf_dom_listener_del(listener, listener->sgprivate->UserPrivate); + gf_list_rem(wid->output_triggers, i); + i--; + count--; + } + } + } + wm_delete_interface_instance(wid->widget->wm, bifce); + if (ifce) return JS_TRUE; + i--; + count--; + } + } + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_widget_bind_interface) +{ + SMJS_OBJ + SMJS_ARGS + SMJS_DECL_RVAL + return wm_widget_bind_interface_ex(c, obj, argc, argv, rval, 0); +} +static JSBool SMJS_FUNCTION(wm_widget_unbind_interface) +{ + SMJS_OBJ + SMJS_ARGS + SMJS_DECL_RVAL + return wm_widget_bind_interface_ex(c, obj, argc, argv, rval, 1); +} + + +static JSBool SMJS_FUNCTION(wm_widget_deactivate) +{ + u32 i, count; + jsval funval; + SMJS_OBJ + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid) return JS_FALSE; + + /*widget is a component of another widget, unregister*/ + if (wid->parent) { + GF_WidgetInstance *par_wid = wid->parent; + count = gf_list_count(par_wid->components); + for (i=0; icomponents, i); + if (comp->wid == wid) { + gf_list_rem(par_wid->components, i); + gf_free(comp); + break; + } + } + wid->parent = NULL; + } + + /*remove all components*/ + while (gf_list_count(wid->components)) { + GF_WidgetComponentInstance *comp = gf_list_get(wid->components, 0); + wm_deactivate_component(c, wid, NULL, comp); + gf_list_rem(wid->components, 0); + } + + /*mark the widget as deactivated, so it is no longer valid when checking all widgets bindings*/ + wid->activated = 0; + + /*unbind existing widgets*/ + JS_LookupProperty(wid->widget->wm->ctx, wid->widget->wm->obj, "unbind_widget", &funval); + if (JSVAL_IS_OBJECT(funval)) { + jsval an_argv[1]; + an_argv[0] = OBJECT_TO_JSVAL(obj); + JS_CallFunctionValue(wid->widget->wm->ctx, wid->widget->wm->obj, funval, 1, an_argv, SMJS_GET_RVAL ); + } + + /*unbind all interfaces of this widget*/ + wm_widget_bind_interface_ex(c, obj, 0, NULL, SMJS_GET_RVAL, 1); + + /*detach scene now that all unbind events have been sent*/ + wid->scene = NULL; + return JS_TRUE; +} + + +static void wm_widget_jsbind(GF_WidgetManager *wm, GF_WidgetInstance *wid) +{ + if (wid->obj) + return; + wid->obj = JS_NewObject(wm->ctx, &wm->wmWidgetClass, 0, 0); + JS_SetPrivate(wm->ctx, wid->obj, wid); + /*protect from GC*/ + gf_js_add_root(wm->ctx, &wid->obj, GF_JSGC_OBJECT); +} + +void wm_deactivate_component(JSContext *c, GF_WidgetInstance *wid, GF_WidgetComponent *comp, GF_WidgetComponentInstance *comp_inst) +{ + jsval fval, rval; + + if (!comp_inst) { + u32 i=0; + while ((comp_inst = gf_list_enum(wid->components, &i))) { + if (comp_inst->comp == comp) break; + comp_inst = NULL; + } + } + if (!comp_inst) return; + + if ((JS_LookupProperty(c, wid->widget->wm->obj, "on_widget_remove", &fval)==JS_TRUE) && JSVAL_IS_OBJECT(fval)) { + jsval argv[1]; + argv[0] = OBJECT_TO_JSVAL(comp_inst->wid->obj); + JS_CallFunctionValue(wid->widget->wm->ctx, wid->obj, fval, 1, argv, &rval); + } +} + +GF_WidgetComponentInstance *wm_activate_component(JSContext *c, GF_WidgetInstance *wid, GF_WidgetComponent *comp, Bool skip_wm_notification) +{ + u32 i, count; + const char *fun_name = NULL; + jsval fval, rval; + GF_WidgetComponentInstance *comp_inst; + GF_WidgetInstance *comp_wid; + + comp_wid = NULL; + if (comp->src) { + char *url = gf_url_concatenate(wid->widget->url, comp->src); + + count = gf_list_count(wid->widget->wm->widget_instances); + for (i=0; iwidget->wm->widget_instances, i); + if (!strcmp(comp_wid->widget->url, url) && !comp_wid->parent) break; + comp_wid = NULL; + } + if (!comp_wid) { + comp_wid = wm_load_widget(wid->widget->wm, url, 0, 0); + if (comp_wid) comp_wid->permanent = 0; + } + gf_free(url); + } + if (!comp_wid) return NULL; + + if (!comp_wid->activated) + fun_name = "on_widget_add"; + + GF_SAFEALLOC(comp_inst, GF_WidgetComponentInstance); + comp_inst->comp = comp; + comp_inst->wid = comp_wid; + comp_wid->parent = wid; + + gf_list_add(wid->components, comp_inst); + + if (!comp_inst->wid->obj) wm_widget_jsbind(wid->widget->wm, comp_inst->wid); + + if (!skip_wm_notification && fun_name && (JS_LookupProperty(c, wid->widget->wm->obj, fun_name, &fval)==JS_TRUE) && JSVAL_IS_OBJECT(fval)) { + jsval argv[1]; + argv[0] = OBJECT_TO_JSVAL(comp_inst->wid->obj); + JS_CallFunctionValue(wid->widget->wm->ctx, wid->obj, fval, 1, argv, &rval); + } + if (comp_inst) return comp_inst; + return NULL; +} + +static JSBool SMJS_FUNCTION(wm_widget_is_interface_bound) +{ + u32 i, count; + JSObject *cookie; + GF_WidgetInterface *ifce; + SMJS_OBJ + SMJS_ARGS + GF_WidgetInstance *wid = (GF_WidgetInstance *)JS_GetPrivate(c, obj); + if (!wid || !wid->scene || (argc<1) || !JSVAL_IS_OBJECT(argv[0]) ) return JS_FALSE; + + ifce = JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!ifce) return JS_FALSE; + cookie = NULL; + if ((argc==2) && JSVAL_IS_OBJECT(argv[1]) ) + cookie = JSVAL_TO_OBJECT(argv[1]); + + SMJS_SET_RVAL(BOOLEAN_TO_JSVAL(JS_FALSE)); + count = gf_list_count(wid->bound_ifces); + for (i=0; ibound_ifces, i); + if (!strcmp(bifce->ifce->type, ifce->type) && (!cookie || (bifce->cookie==cookie))) { + SMJS_SET_RVAL( BOOLEAN_TO_JSVAL(JS_TRUE) ); + break; + } + } + return JS_TRUE; +} + + +static JSBool SMJS_FUNCTION(wm_load) +{ + u32 i, count; + char *manifest, *url, *widget_ctx; + GF_WidgetInstance *wid; + SMJS_OBJ + SMJS_ARGS + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + if (!argc || !JSVAL_IS_STRING(argv[0])) return JS_TRUE; + + manifest = SMJS_CHARS(c, argv[0]); + + url = NULL; + if ((argc==2) && ! JSVAL_IS_NULL(argv[1]) && JSVAL_IS_OBJECT(argv[1])) { + GF_WidgetInstance *parent_widget; + if (!JS_InstanceOf(c, JSVAL_TO_OBJECT(argv[1]), &wm->wmWidgetClass, NULL) ) return JS_FALSE; + parent_widget = (GF_WidgetInstance *)JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[1]) ); + + if (parent_widget->widget->url) url = gf_url_concatenate(parent_widget->widget->url, manifest); + } + + widget_ctx = NULL; + if ((argc==3) && !JSVAL_IS_NULL(argv[2]) && JSVAL_IS_STRING(argv[2])) { + widget_ctx = SMJS_CHARS(c, argv[2]); + } + + if (!url) { + url = gf_strdup(manifest); + } + + wid=NULL; + count = gf_list_count(wm->widget_instances); + for (i=0; iwidget_instances, i); + if (!strcmp(wid->widget->url, url) && !wid->activated) break; + wid = NULL; + } + if (!wid) { + wid = wm_load_widget(wm, url, 0, 1); + } + if (url) gf_free(url); + + /*parse context if any*/ + if (wid && wid->mpegu_context) { + gf_xml_dom_del(wid->mpegu_context); + wid->mpegu_context = NULL; + } + if (wid && widget_ctx && strlen(widget_ctx)) { + GF_Err e; + GF_XMLNode *context = NULL; + wid->mpegu_context = gf_xml_dom_new(); + e = gf_xml_dom_parse_string(wid->mpegu_context, widget_ctx); + if (!e) { + context = gf_xml_dom_get_root(wid->mpegu_context); + if (strcmp(context->name, "contextInformation")) context = NULL; + } else { + } + + if (!context && wid->mpegu_context) { + gf_xml_dom_del(wid->mpegu_context); + wid->mpegu_context = NULL; + } + } + + if (wid) { + wm_widget_jsbind(wm, wid); + SMJS_SET_RVAL(OBJECT_TO_JSVAL(wid->obj)); + } + SMJS_FREE(c, manifest); + SMJS_FREE(c, widget_ctx); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_unload) +{ + GF_WidgetInstance *wid; + SMJS_OBJ + SMJS_ARGS + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + if (!argc || !JSVAL_IS_OBJECT(argv[0])) return JS_TRUE; + + if (!JS_InstanceOf(c, JSVAL_TO_OBJECT(argv[0]), &wm->wmWidgetClass, NULL) ) return JS_FALSE; + wid = (GF_WidgetInstance *)JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0]) ); + if (!wid) return JS_TRUE; + + /*unless explecetely requested, remove the section*/ + if ((argc!=2) || !JSVAL_IS_BOOLEAN(argv[1]) || (JSVAL_TO_BOOLEAN(argv[1])==JS_TRUE) ) { + /*create section*/ + gf_cfg_del_section(wm->term->user->config, wid->secname); + gf_cfg_set_key(wm->term->user->config, "Widgets", wid->secname, NULL); + } + wm_delete_widget_instance(wm, wid); + return JS_TRUE; +} + + + +static JSBool wm_getProperty(JSContext *c, JSObject *obj, SMJS_PROP_GETTER, jsval *vp) +{ + char *prop_name; + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + if (!wm) return JS_FALSE; + + if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; + prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); + if (!prop_name) return JS_FALSE; + + if (!strcmp(prop_name, "num_widgets")) { + *vp = INT_TO_JSVAL(gf_list_count(wm->widget_instances)); + } + else if (!strcmp(prop_name, "last_widget_dir")) { + const char *opt = gf_cfg_get_key(wm->term->user->config, "Widgets", "last_widget_dir"); + if (!opt) opt = "/"; + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, opt)); + } + SMJS_FREE(c, prop_name); + return JS_TRUE; +} +static JSBool wm_setProperty(JSContext *c, JSObject *obj, SMJS_PROP_SETTER, jsval *vp) +{ + char *prop_name; + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + if (!wm) return JS_FALSE; + + if (!JSVAL_IS_STRING(*vp)) return JS_TRUE; + if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; + prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); + + if (!strcmp(prop_name, "last_widget_dir")) { + char *v = SMJS_CHARS(c, *vp); + gf_cfg_set_key(wm->term->user->config, "Widgets", "last_widget_dir", v); + SMJS_FREE(c, v); + } + SMJS_FREE(c, prop_name); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_get) +{ + u32 i; + GF_WidgetInstance *wid; + SMJS_OBJ + SMJS_ARGS + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + if (!argc || !JSVAL_IS_INT(argv[0])) return JS_TRUE; + + i = JSVAL_TO_INT(argv[0]); + wid = gf_list_get(wm->widget_instances, i); + if (wid) SMJS_SET_RVAL( OBJECT_TO_JSVAL(wid->obj) ); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(wm_find_interface) +{ + char *ifce_name; + u32 i; + GF_WidgetInstance *wid; + SMJS_OBJ + SMJS_ARGS + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + if (!argc || !JSVAL_IS_STRING(argv[0])) return JS_TRUE; + + ifce_name = SMJS_CHARS(c, argv[0]); + i=0; + while ( (wid = gf_list_enum(wm->widget_instances, &i) )) { + u32 j=0; + GF_WidgetInterface *wid_ifce; + while ((wid_ifce = gf_list_enum(wid->widget->main->interfaces, &j))) { + if (!strcmp(wid_ifce->type, ifce_name)) { + SMJS_SET_RVAL( OBJECT_TO_JSVAL(wid->obj) ); + SMJS_FREE(c, ifce_name); + return JS_TRUE; + } + } + } + SMJS_FREE(c, ifce_name); + return JS_TRUE; +} + + +const char *wm_xml_get_attr(GF_XMLNode *root, const char *name) +{ + + u32 i, count; + count = gf_list_count(root->attributes); + for (i=0; iattributes, i); + if (!att->name) continue; + if (!strcmp(att->name, name)) return att->value; + sep = strchr(att->name, ':'); + if (sep && !strcmp(sep+1, name)) return att->value; + } + return NULL; +} + +/* TODO Implement real language check according to BCP 47*/ +static Bool wm_check_language(const char *xml_lang_value, const char *user_locale) +{ + Bool ret = 0; + char *sep, *val; + val = (char*)xml_lang_value; + while (!ret) { + sep = strchr(val, ';'); + if (sep) sep[0] = 0; + if (strstr(user_locale, val)) ret = 1; + if (sep) { + sep[0] = ';'; + val = sep+1; + } else { + break; + } + } + return ret; +} + +static GF_XMLNode *wm_xml_find(GF_XMLNode *root, const char *ns_prefix, const char *name, const char *user_locale) +{ + GF_XMLNode *localized = NULL; + GF_XMLNode *non_localized = NULL; + u32 i, count; + + if (!root) return NULL; + + count = gf_list_count(root->content); + for (i=0; icontent, i); + if (n->type==GF_XML_NODE_TYPE && n->name && !strcmp(n->name, name) && ((!ns_prefix && !n->ns) || (ns_prefix && n->ns && !strcmp(ns_prefix, n->ns)))) { + const char *lang = wm_xml_get_attr(n, "xml:lang"); + if (!lang) { + if (!non_localized) non_localized = n; + } else { + if (user_locale && wm_check_language(lang, user_locale) && !localized) localized = n; + } + } + } + if (localized) return localized; + else return non_localized; +} + +static GF_WidgetPin *wm_parse_pin(const char *value, u16 type, const char *pin_name, const char *scriptType, const char *default_value) +{ + GF_WidgetPin *pin; + char *sep; + + if (!value && !scriptType && !default_value) return NULL; + + GF_SAFEALLOC(pin, GF_WidgetPin); + pin->type = type; + if (pin_name) pin->name = gf_strdup(pin_name); + + if (value) { + sep = strrchr(value, '.'); + if (!sep && (type==GF_WM_PREF_CONNECT)) { + gf_free(pin); + return NULL; + } + + /*node.event || node.attribute*/ + if (sep) { + sep[0] = 0; + pin->node = gf_strdup(value); + pin->attribute = gf_strdup(sep+1); + sep[0] = '.'; + } + /*script function*/ + else { + pin->node = gf_strdup(value); + } + } + + if (scriptType) { + if (!strcmp(scriptType, "boolean")) pin->script_type = GF_WM_PARAM_SCRIPT_BOOL; + else if (!strcmp(scriptType, "number")) pin->script_type = GF_WM_PARAM_SCRIPT_NUMBER; + } else if (default_value) { + pin->default_value = gf_strdup(default_value); + } + return pin; +} + +static void wm_parse_mpegu_content_element(GF_WidgetContent *content, GF_XMLNode *root, const char *ns_prefix, GF_List *global_prefs) +{ + GF_XMLNode *ifces, *context, *pref_node; + GF_WidgetMessage *msg; + GF_WidgetInterface *ifce; + GF_XMLNode *ifce_node; + GF_WidgetPreference *pref; + const char *att; + u32 i = 0; + + ifces = wm_xml_find(root, ns_prefix, "interfaces", NULL); + if (ifces) { + + /*get all interface element*/ + while ((ifce_node = gf_list_enum(ifces->content, &i))) { + GF_XMLNode *msg_node; + u32 j; + const char *ifce_type, *act; + if (ifce_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(ifce_node->name, "interface")) continue; + ifce_type = wm_xml_get_attr(ifce_node, "type"); + if (!ifce_type) continue; + + GF_SAFEALLOC(ifce, GF_WidgetInterface); + ifce->type = gf_strdup(ifce_type); + ifce->messages = gf_list_new(); + ifce->content = content; + gf_list_add(content->interfaces, ifce); + + act = wm_xml_get_attr(ifce_node, "serviceProvider"); + if (act && !strcmp(act, "true")) ifce->provider = 1; + + act = wm_xml_get_attr(ifce_node, "multipleBindings"); + if (act && !strcmp(act, "true")) ifce->multiple_binding = 1; + + act = wm_xml_get_attr(ifce_node, "required"); + if (act && !strcmp(act, "true")) ifce->required = 1; + + act = wm_xml_get_attr(ifce_node, "connectTo"); + if (act) ifce->connectTo = gf_strdup(act); + + act = wm_xml_get_attr(ifce_node, "bindAction"); + if (act) { + ifce->bind_action = wm_parse_pin(act, GF_WM_BIND_ACTION, NULL, NULL, NULL); + } + act = wm_xml_get_attr(ifce_node, "unbindAction"); + if (act) { + ifce->unbind_action = wm_parse_pin(act, GF_WM_UNBIND_ACTION, NULL, NULL, NULL); + } + + j=0; + while ((msg_node = gf_list_enum(ifce_node->content, &j))) { + u32 k; + GF_XMLNode *par_node; + const char *msg_name, *action; + if (msg_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(msg_node->name, "messageIn") && strcmp(msg_node->name, "messageOut")) continue; + + msg_name = wm_xml_get_attr(msg_node, "name"); + if (!msg_name) continue; + GF_SAFEALLOC(msg, GF_WidgetMessage); + msg->name = gf_strdup(msg_name); + msg->params = gf_list_new(); + msg->ifce = ifce; + if (!strcmp(msg_node->name, "messageOut")) msg->is_output = 1; + + gf_list_add(ifce->messages, msg); + + /*get inputAction*/ + action = wm_xml_get_attr(msg_node, "inputAction"); + if (action) { + msg->input_action = wm_parse_pin(action, GF_WM_INPUT_ACTION, NULL, NULL, NULL); + } + + /*get outputTrigger*/ + action = wm_xml_get_attr(msg_node, "outputTrigger"); + if (action) { + msg->output_trigger = wm_parse_pin(action, GF_WM_OUTPUT_TRIGGER, NULL, NULL, NULL); + } + + /*get params*/ + k=0; + while ((par_node=gf_list_enum(msg_node->content, &k))) { + GF_WidgetPin *wpin; + u16 type; + const char *par_name, *att_name; + if (par_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(par_node->name, "input") && strcmp(par_node->name, "output")) continue; + + + par_name = wm_xml_get_attr(par_node, "name"); + /*invalid param, discard message*/ + if (!par_name) { + gf_list_del_item(ifce->messages, msg); + gf_list_del(msg->params); + gf_free(msg->name); + gf_free(msg); + break; + } + + if (!strcmp(par_node->name, "output")) { + type = GF_WM_PARAM_OUTPUT; + att_name = wm_xml_get_attr(par_node, "attributeModified"); + } else { + type = GF_WM_PARAM_INPUT; + att_name = wm_xml_get_attr(par_node, "setAttribute"); + } + wpin = wm_parse_pin(att_name, type, par_name, wm_xml_get_attr(par_node, "scriptParamType"), wm_xml_get_attr(par_node, "default")); + if (!wpin) continue; + wpin->msg = msg; + + gf_list_add(msg->params, wpin); + } + } + } + } + + /*get all component elements*/ + i=0; + while (root && (ifce_node = gf_list_enum(root->content, &i))) { + GF_XMLNode *req_node; + u32 j; + const char *src, *id, *act; + GF_WidgetComponent *comp; + if (ifce_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(ifce_node->name, "component")) continue; + src = wm_xml_get_attr(ifce_node, "src"); + id = wm_xml_get_attr(ifce_node, "id"); + + GF_SAFEALLOC(comp, GF_WidgetComponent); + comp->required_interfaces = gf_list_new(); + comp->content = content; + if (id) comp->id = gf_strdup(id); + if (src) comp->src = gf_strdup(src); + j=0; + while ((req_node=gf_list_enum(ifce_node->content, &j))) { + const char *ifce_type; + if (req_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(req_node->name, "requiredInterface")) continue; + ifce_type = wm_xml_get_attr(req_node, "type"); + if (!ifce_type) continue; + gf_list_add(comp->required_interfaces, gf_strdup(ifce_type)); + } + + act = wm_xml_get_attr(ifce_node, "activateTrigger"); + if (act) comp->activateTrigger = wm_parse_pin(act, GF_WM_ACTIVATE_TRIGGER, NULL, NULL, NULL); + act = wm_xml_get_attr(ifce_node, "deactivateTrigger"); + if (act) comp->deactivateTrigger = wm_parse_pin(act, GF_WM_DEACTIVATE_TRIGGER, NULL, NULL, NULL); + + gf_list_add(content->components, comp); + } + + /*clone global prefs for this content*/ + i=0; + while ((pref = gf_list_enum(global_prefs, &i))) { + GF_WidgetPreference *apref; + GF_SAFEALLOC(apref, GF_WidgetPreference); + apref->name = gf_strdup(pref->name); + if (pref->value) apref->value = gf_strdup(pref->value); + apref->flags = pref->flags; + gf_list_add(content->preferences, apref); + } + + context = wm_xml_find(root, ns_prefix, "contextConfiguration", NULL); + if (context) { + u32 j; + /*get all preference elements*/ + i=0; + while ((pref_node = gf_list_enum(context->content, &i))) { + const char *att; + if (pref_node->type != GF_XML_NODE_TYPE) continue; + if (strcmp(pref_node->name, "preferenceConnect")) continue; + att = wm_xml_get_attr(pref_node, "name"); + if (!att) continue; + + j=0; + while ((pref = gf_list_enum(content->preferences, &j))) { + if (!strcmp(pref->name, att) && !pref->connectTo) break; + } + + if (!pref) { + GF_SAFEALLOC(pref, GF_WidgetPreference); + pref->name = gf_strdup(att); + gf_list_add(content->preferences, pref); + } + att = wm_xml_get_attr(pref_node, "value"); + if (att) { + if (pref->value) gf_free(pref->value); + pref->value = gf_strdup(att); + } + att = wm_xml_get_attr(pref_node, "readOnly"); + if (att && !strcmp(att, "true")) pref->flags |= GF_WM_PREF_READONLY; + att = wm_xml_get_attr(pref_node, "migratable"); + if (att && !strcmp(att, "saveOnly")) pref->flags |= GF_WM_PREF_SAVE; + else if (att && !strcmp(att, "migrateOnly")) pref->flags |= GF_WM_PREF_MIGRATE; + else pref->flags |= GF_WM_PREF_SAVE | GF_WM_PREF_MIGRATE; + + att = wm_xml_get_attr(pref_node, "connectTo"); + if (att) pref->connectTo = wm_parse_pin(att, GF_WM_PREF_CONNECT, NULL, NULL, NULL); + } + + att = wm_xml_get_attr(context, "savedAction"); + if (att) content->savedAction = wm_parse_pin(att, GF_WM_PREF_SAVEDACTION, NULL, NULL, NULL); + att = wm_xml_get_attr(context, "restoredAction"); + if (att) content->restoredAction = wm_parse_pin(att, GF_WM_PREF_RESTOREDACTION, NULL, NULL, NULL); + att = wm_xml_get_attr(context, "saveTrigger"); + if (att) content->saveTrigger = wm_parse_pin(att, GF_WM_PREF_SAVETRIGGER, NULL, NULL, NULL); + att = wm_xml_get_attr(context, "restoreTrigger"); + if (att) content->restoreTrigger = wm_parse_pin(att, GF_WM_PREF_RESTORETRIGGER, NULL, NULL, NULL); + } +} + +/* Implements the W3C P&C rule for getting a single attribute value + see http://www.w3.org/TR/widgets/#rule-for-getting-a-single-attribute-valu0 + should be different from getting normalized text but for now it's ok + */ +static char *wm_get_single_attribute(const char *input) { + u32 i, j, len; + char *output; + Bool first_space_copied; + + if (!input) return gf_strdup(""); + + len = strlen(input); + output = gf_malloc(len+1); + + first_space_copied = 1; + j = 0; + for (i = 0; itype == GF_XML_TEXT_TYPE) { + if (node->name) return gf_strdup(node->name); + else return gf_strdup(""); + } else { + char *xml_lang = (char *)wm_xml_get_attr(node, "xml:lang"); + if (!xml_lang) xml_lang = inherited_locale; + /* + if (xml_lang && user_locale && wm_check_language(xml_lang, user_locale)) + */ + { + u32 i, count; + char *text_content; + u32 text_content_len = 0; + text_content = gf_strdup(""); + count = gf_list_count(node->content); + for (i=0; icontent, i); + char *child_content = wm_get_text_content(child, xml_lang, user_locale); + u32 child_content_len = strlen(child_content); + text_content = gf_realloc(text_content, text_content_len+child_content_len+1); + memcpy(text_content+text_content_len, child_content, child_content_len); + text_content[text_content_len+child_content_len] = 0; + text_content_len+=child_content_len; + gf_free(child_content); + } + return text_content; + } + /* + } else { + return gf_strdup(""); + */ + } +} + +static char *wm_get_normalized_text_content(GF_XMLNode *node, char *inherited_locale, const char *user_locale) { + char *text_content, *result; + /* first aggregate text content */ + text_content = wm_get_text_content(node, inherited_locale, user_locale); + /* calling normalization of text content */ + result = wm_get_single_attribute(text_content); + gf_free(text_content); + return result; +} + +/* When relocating resources over HTTP, we check if the resources for a given locale exists + on the server by sending a HEAD message with an Accept-Language header. */ +void wm_relocate_proc(void *usr_cbk, GF_NETIO_Parameter *parameter) +{ + switch (parameter->msg_type) { + case GF_NETIO_GET_METHOD: + parameter->name = "HEAD"; + break; + } +} + +/* relocate the given resource name (res_name) using registered relocators (e.g. locales, package folder) + The result is the path of the file, possibly uncompressed, possibly localized. + The parameter widget_path provides the path for converting relative resource paths into absolute paths.*/ +static Bool wm_relocate_url(GF_WidgetManager *wm, const char *widget_path, const char *res_name, char *relocated_name, char *localized_res_name) +{ + Bool ok = 0; + char *res_url; + Bool result = gf_term_relocate_url(wm->term, res_name, widget_path, relocated_name, localized_res_name); + if (result) return result; + + res_url = gf_url_concatenate(widget_path, res_name); + + /*try with HTTP HEAD */ + if (!strnicmp(widget_path, "http", 4)) { + GF_Err e; + /*fetch the remote widget manifest synchronously and load it */ + GF_DownloadSession *sess = gf_dm_sess_new(wm->term->downloader, (char *)res_url, GF_NETIO_SESSION_NOT_THREADED, wm_relocate_proc, NULL, &e); + if (sess) { + e = gf_dm_sess_process(sess); + gf_dm_sess_del(sess); + if (e==GF_OK) { + const char *opt = gf_cfg_get_key(wm->term->user->config, "Systems", "Language2CC"); + strcpy(relocated_name, res_url); + if (opt) + sprintf(localized_res_name, "%s/%s", opt, res_name); + else + strcpy(localized_res_name, res_name); + ok = 1; + } + } + } + gf_free(res_url); + return ok; +} + +/* function that checks if the default start file exists in the widget (package or folder) + according to the default start files table from the W3C P&C spec. + The widget path attribute is used to get the associated relocator from the registered relocators */ +static void wm_set_default_start_file(GF_WidgetManager *wm, GF_WidgetContent *content, const char *widget_path) { + Bool result; + char localized_path[GF_MAX_PATH], relocated_path[GF_MAX_PATH]; + char *mimetype = "text/html"; + result = wm_relocate_url(wm, widget_path, "index.htm", relocated_path, localized_path); + if (result) { + mimetype = "text/html"; + } else { + result = wm_relocate_url(wm, widget_path, "index.html", relocated_path, localized_path); + if (result) { + mimetype = "text/html"; + } else { + result = wm_relocate_url(wm, widget_path, "index.svg", relocated_path, localized_path); + if (result) { + mimetype = "image/svg+xml"; + } else { + result = wm_relocate_url(wm, widget_path, "index.xhtml", relocated_path, localized_path); + if (result) { + mimetype = "application/xhtml+xml"; + } else { + result = wm_relocate_url(wm, widget_path, "index.xht", relocated_path, localized_path); + if (result) mimetype = "application/xhtml+xml"; + } + } + } + } + if (content->src) gf_free(content->src); + content->src = gf_strdup(localized_path); + if (content->relocated_src) gf_free(content->relocated_src); + content->relocated_src = gf_strdup(relocated_path); + if (content->mimetype) gf_free(content->mimetype); + content->mimetype = gf_strdup(mimetype); + if (content->encoding) gf_free(content->encoding); + content->encoding = gf_strdup("utf-8"); +} + +static GF_WidgetContent *wm_add_icon(GF_Widget *widget, const char *icon_relocated_path, const char *icon_localized_path, const char *uri_fragment) +{ + GF_WidgetContent *icon; + u32 i, count; + Bool already_in = 0; + + count = gf_list_count(widget->icons); + for (i =0; iicons, i); + if (!strcmp(icon_localized_path, in_icon->src)) { + already_in = 1; + break; + } + } + if (already_in) return NULL; + + GF_SAFEALLOC(icon, GF_WidgetContent); + if (uri_fragment) { + icon->src = gf_malloc(strlen(icon_localized_path) + strlen(uri_fragment) + 1); + strcpy(icon->src, icon_localized_path); + strcat(icon->src, uri_fragment); + + icon->relocated_src = gf_malloc(strlen(icon_relocated_path) + strlen(uri_fragment) + 1); + strcpy(icon->relocated_src, icon_relocated_path); + strcat(icon->relocated_src, uri_fragment); + } else { + icon->src = gf_strdup(icon_localized_path); + icon->relocated_src = gf_strdup(icon_relocated_path); + } + icon->interfaces = gf_list_new(); + icon->components = gf_list_new(); + icon->preferences = gf_list_new(); + icon->widget = widget; + gf_list_add(widget->icons, icon); + return icon; +} + +/* Scans the W3C default icons table and add each icon */ +static void wm_set_default_icon_files(GF_WidgetManager *wm, const char *widget_path, GF_Widget *widget) { + char relocated_path[GF_MAX_PATH], localized_path[GF_MAX_PATH]; + Bool result; + + result = wm_relocate_url(wm, widget_path, "icon.svg", relocated_path, localized_path); + if (result) wm_add_icon(widget, relocated_path, localized_path, NULL); + + result = wm_relocate_url(wm, widget_path, "icon.ico", relocated_path, localized_path); + if (result) wm_add_icon(widget, relocated_path, localized_path, NULL); + + result = wm_relocate_url(wm, widget_path, "icon.png", relocated_path, localized_path); + if (result) wm_add_icon(widget, relocated_path, localized_path, NULL); + + result = wm_relocate_url(wm, widget_path, "icon.gif", relocated_path, localized_path); + if (result) wm_add_icon(widget, relocated_path, localized_path, NULL); + + result = wm_relocate_url(wm, widget_path, "icon.jpg", relocated_path, localized_path); + if (result) wm_add_icon(widget, relocated_path, localized_path, NULL); +} + +GF_WidgetInstance *wm_load_widget(GF_WidgetManager *wm, const char *path, u32 InstanceID, Bool skip_context) +{ + char szName[GF_MAX_PATH]; + u32 i, count; + GF_Widget *widget = NULL; + GF_WidgetInstance *wi = NULL; + GF_XMLNode *root, *icon, *nmain, *name, *xml_node; + GF_Err e; + GF_DOMParser *dom = NULL; + GF_WidgetPackage *wpackage = NULL; + + GF_DownloadSession *sess = NULL; + const char *widget_ns_prefix = NULL; + const char *mpegu_ns_prefix = NULL; + const char *user_locale = gf_cfg_get_key(wm->term->user->config, "Systems", "Language2CC"); + + /* Try to see if this widget is already loaded */ + e = GF_OK; + count = gf_list_count(wm->widgets); + for (i=0; iwidgets, i); + if (!strcmp(widget->url, path)) break; + widget = NULL; + } + + /*not found, retrieve the widget (if http), check the package if needed and parse the configuration document/widget manifest*/ + if (!widget) { + Bool isDownloadedPackage = 0; + + /* path used to locate the widget (config.xml if unpackaged or zip/isoff package), potentially after download */ + const char *szLocalPath = path; + /* used to locate the config document/widget manifest potentially after unzipping */ + const char *szManifestPath = path; + /* */ + const char *szWidgetPath = path; + const char *desc; + GF_WidgetPreference *pref; + GF_List *global_prefs; + GF_WidgetContent *content; + Bool correct_ns = 0; + + if (strstr(path, "http://")) { + /*fetch the remote widget manifest synchronously and load it */ + sess = gf_dm_sess_new(wm->term->downloader, (char *)path, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e); + if (sess) { + e = gf_dm_sess_process(sess); + if (e==GF_OK) { + szLocalPath = gf_dm_sess_get_cache_name(sess); + + if (gf_unzip_probe(szLocalPath)) { + isDownloadedPackage = 1; + } else { + /* TODO ISOFF-based packaged widget */ + } + } + } + if (!sess || (e!=GF_OK) || !szLocalPath) goto exit; + } + + /* Check if the widget package is a valid package and if it contains a config.xml file */ + szManifestPath = szLocalPath; + + wpackage = widget_package_new(wm, szLocalPath); + if (wpackage) { + count = gf_list_count(wpackage->resources); + for (i=0; iresources, i); + /* According to W3C WPC, the config.xml file (lower case) shall only be located + at the root of the package + see http://www.w3.org/TR/widgets/#ta-dxzVDWpaWg */ + if (!strcmp(wu->inner_path, "config.xml")) { + szManifestPath = wu->extracted_path; + break; + } + } + szWidgetPath = szManifestPath; + } + + + /* Parse the Widget Config Document as a DOM */ + dom = gf_xml_dom_new(); + e = gf_xml_dom_parse(dom, szManifestPath, NULL, NULL); + if (e) goto exit; + + root = gf_xml_dom_get_root(dom); + if (!root) goto exit; + + correct_ns = 0; + count = gf_list_count(root->attributes); + for (i=0; iattributes, i); + if (att->name) { + if (!strcmp(att->name, "xmlns")) { + if (!strcmp(att->value, "http://www.w3.org/ns/widgets")) { + correct_ns = 1; + } + } else if (!strnicmp(att->name, "xmlns:", 6)) { + if (!strcmp(att->value, "http://www.w3.org/ns/widgets")) { + widget_ns_prefix = att->name+6; + correct_ns = 1; + } else if (!strcmp(att->value, "urn:mpeg:mpegu:schema:widgets:manifest:2010")) { + mpegu_ns_prefix = att->name+6; + } + } + } + } + /* According to the spec, wrong or no namespace means invalid widget + see http://www.w3.org/TR/widgets/#ta-ACCJfDGwDQ */ + if (!correct_ns) goto exit; + + /* see http://www.w3.org/TR/widgets/#ta-ACCJfDGwDQ */ + if ((root->ns && (!widget_ns_prefix || strcmp(root->ns, widget_ns_prefix) || strcmp(root->name, "widget"))) || + (!root->ns && (widget_ns_prefix || strcmp(root->name, "widget")))) + goto exit; + + + /*pre-parse the root-level preference for use when parsing MPEG-U elements */ + global_prefs = gf_list_new(); + i=0; + while ((nmain = gf_list_enum(root->content, &i))) { + const char *pname, *pvalue; + /* 'normalized' preference name and readonly*/ + char *npname, *npro; + u32 i, count; + Bool pref_exists = 0; + Bool readOnly = 0; + if (nmain->type != GF_XML_NODE_TYPE) continue; + if (strcmp(nmain->name, "preference")) continue; + pname = wm_xml_get_attr(nmain, "name"); + npname = wm_get_single_attribute(pname); + if (!npname || !strlen(npname)) continue; + + count = gf_list_count(global_prefs); + for (i = 0; i < count; i++) { + GF_WidgetPreference *tmp_pref = gf_list_get(global_prefs, i); + if (!strcmp(tmp_pref->name, npname)) { + pref_exists = 1; + break; + } + } + if (pref_exists) continue; + + pvalue = wm_xml_get_attr(nmain, "readonly"); + npro = wm_get_single_attribute(pvalue); + if (npro && strlen(npro) && !strcmp(npro, "true")) readOnly=1; + if (npro) gf_free(npro); + + pvalue = wm_xml_get_attr(nmain, "value"); + + GF_SAFEALLOC(pref, GF_WidgetPreference); + pref->name = npname; + if (pvalue) pref->value = wm_get_single_attribute(pvalue); + /*global preferences are save and migratable*/ + pref->flags = GF_WM_PREF_SAVE | GF_WM_PREF_MIGRATE; + if (readOnly) pref->flags |= GF_WM_PREF_READONLY; + gf_list_add(global_prefs, pref); + } + + /* get the content element from the XML Config document */ + GF_SAFEALLOC(content, GF_WidgetContent); + content->interfaces = gf_list_new(); + content->components = gf_list_new(); + content->preferences = gf_list_new(); + nmain = wm_xml_find(root, widget_ns_prefix, "content", NULL); + if (!nmain) { + /* if not found, use the default table of start files */ + wm_set_default_start_file(wm, content, szWidgetPath); + } else { + const char *src, *encoding, *mimetype; + src = wm_xml_get_attr(nmain, "src"); + + /*check the resource exists*/ + if (src) { + Bool result; + char relocated_path[GF_MAX_PATH], localized_path[GF_MAX_PATH]; + /*remove any existing fragment*/ + char *sep = strchr(src, '#'); + if (sep) sep[0] = 0; + result = wm_relocate_url(wm, szWidgetPath, src, relocated_path, localized_path); + if (sep) sep[0] = '#'; + if (result) { + content->relocated_src = gf_strdup(relocated_path); + content->src = gf_strdup(localized_path); + } + } + + encoding = wm_xml_get_attr(nmain, "encoding"); + if (encoding && strlen(encoding)) content->encoding = wm_get_single_attribute(encoding); + else content->encoding = gf_strdup("utf-8"); + + mimetype = wm_xml_get_attr(nmain, "type"); + if (mimetype && strlen(mimetype)) { + char *sep = strchr(mimetype, ';'); + if (sep) sep[0] = 0; + content->mimetype = wm_get_single_attribute(mimetype); + if (sep) sep[0] = ';'; + } + else content->mimetype = gf_strdup("text/html"); + + if (!content->relocated_src) wm_set_default_start_file(wm, content, szWidgetPath); + } + if (strlen(content->relocated_src) == 0) { + gf_list_del(content->interfaces); + gf_list_del(content->components); + gf_list_del(content->preferences); + gf_free(content); + content = NULL; + goto exit; + } + /* We need to call the parse of the MPEG-U elements to clone the global preferences into widget preferences, + this should probably be changed to extract the clone from that function */ + wm_parse_mpegu_content_element(content, nmain, mpegu_ns_prefix, global_prefs); + + GF_SAFEALLOC(widget, GF_Widget); + widget->url = gf_strdup(path); + widget->manifest_path = gf_strdup(szManifestPath); + if (isDownloadedPackage) widget->local_path = gf_strdup(szLocalPath); + widget->wm = wm; + widget->main = content; + content->widget = widget; + widget->icons = gf_list_new(); + widget->features = gf_list_new(); + if (wpackage) { + widget->wpack = wpackage; + wpackage->widget = widget; + /*attach downloader to our package to avoid destroying the cache file*/ + wpackage->sess = sess; + sess = NULL; + } + + /*check for icon - can be optional*/ + i=0; + while ((icon = gf_list_enum(root->content, &i))) { + if (icon->type==GF_XML_NODE_TYPE && + icon->name && !strcmp(icon->name, "icon") && + ((!widget_ns_prefix && !icon->ns) || !strcmp(widget_ns_prefix, icon->ns))) { + char *sep; + char relocated[GF_MAX_PATH], localized_path[GF_MAX_PATH]; + char *icon_width, *icon_height; + GF_WidgetContent *iconic; + Bool result; + + char *pname = (char *)wm_xml_get_attr(icon, "src"); + if (!pname || !strlen(pname)) continue; + + /*remove any existing fragment*/ + sep = strchr(pname, '#'); + if (sep) sep[0] = 0; + result = wm_relocate_url(wm, szWidgetPath, pname, relocated, localized_path); + if (sep) sep[0] = '#'; + if (!result) continue; + + iconic = wm_add_icon(widget, relocated, localized_path, sep); + if (iconic) { + wm_parse_mpegu_content_element(iconic, icon, mpegu_ns_prefix, global_prefs); + icon_width = (char *)wm_xml_get_attr(icon, "width"); + if (icon_width) iconic->width = wm_parse_non_neg(icon_width); + icon_height = (char *)wm_xml_get_attr(icon, "height"); + if (icon_height) iconic->height = wm_parse_non_neg(icon_height); + } + } + } + /* after processing the icon elements (wether there are valid icons or not), we use the default icon table + see http://dev.w3.org/2006/waf/widgets/test-suite/test-cases/ta-FAFYMEGELU/004/ */ + wm_set_default_icon_files(wm, szWidgetPath, widget); + + /*delete the root-level preference*/ + i=0; + while ((pref = gf_list_enum(global_prefs , &i))) { + if (pref->value) gf_free(pref->value); + gf_free(pref->name); + gf_free(pref); + } + gf_list_del(global_prefs); + + /*check for optionnal meta data*/ + name = wm_xml_find(root, widget_ns_prefix, "name", user_locale); + if (name) { + const char *shortname = wm_xml_get_attr(name, "short"); + widget->shortname = wm_get_single_attribute(shortname); + + widget->name = wm_get_normalized_text_content(name, NULL, user_locale); + } + + desc = wm_xml_get_attr(root, "id"); + if (desc) { + /* TODO check if this is a valid IRI, for the moment, just hack to pass the test, check for ':' + see http://dev.w3.org/2006/waf/widgets/test-suite/test-cases/ta-RawAIWHoMs/ */ + if (strchr(desc, ':')) + widget->identifier = wm_get_single_attribute(desc); + } + + desc = wm_xml_get_attr(root, "width"); + if (desc) { + widget->width = wm_parse_non_neg(desc); + } + desc = wm_xml_get_attr(root, "height"); + if (desc) { + widget->height = wm_parse_non_neg(desc); + } + + name = wm_xml_find(root, widget_ns_prefix, "description", user_locale); + if (name) { + widget->description = wm_get_normalized_text_content(name, NULL, user_locale); + } + + name = wm_xml_find(root, widget_ns_prefix, "license", user_locale); + if (name) { + const char *href = wm_xml_get_attr(name, "href"); + widget->licenseHref = wm_get_single_attribute(href); + + /* Warning the license text content should not be normalized */ + widget->license = wm_get_text_content(name, NULL, user_locale); + } + + desc = wm_xml_get_attr(root, "version"); + if (desc) widget->version = wm_get_single_attribute(desc); + + desc = wm_xml_get_attr(root, "uuid"); + if (desc) widget->uuid = gf_strdup(desc); + + desc = wm_xml_get_attr(root, "discardable"); + if (desc) widget->discardable = !strcmp(desc, "true") ? 1 : 0; + + desc = wm_xml_get_attr(root, "multipleInstances"); + if (desc) widget->multipleInstance = !strcmp(desc, "true") ? 1 : 0; + + name = wm_xml_find(root, widget_ns_prefix, "author", NULL); + if (name) { + desc = wm_xml_get_attr(name, "href"); + if (desc && strchr(desc, ':')) widget->authorHref = wm_get_single_attribute(desc); + + desc = wm_xml_get_attr(name, "email"); + widget->authorEmail = wm_get_single_attribute(desc); + + widget->authorName = wm_get_normalized_text_content(name, NULL, user_locale); + } + + i=0; + while ((xml_node = gf_list_enum(root->content, &i))) { + if (xml_node->type==GF_XML_NODE_TYPE && + xml_node->name && !strcmp(xml_node->name, "feature") && + ((!widget_ns_prefix && !xml_node->ns) || !strcmp(widget_ns_prefix, xml_node->ns))) { + + u32 i, count; + Bool already_in = 0; + GF_WidgetFeature *feat; + const char *feature_name, *req_att; + char *nfname; + Bool required = 1; + u32 j; + GF_XMLNode *param_node; + + feature_name = (char *)wm_xml_get_attr(xml_node, "name"); + if (!feature_name || !strlen(feature_name) || !strchr(feature_name, ':')) continue; + nfname = wm_get_single_attribute(feature_name); + + req_att = (char *)wm_xml_get_attr(xml_node, "required"); + if (req_att && !strcmp(req_att, "false")) required = 0; + + count = gf_list_count(widget->features); + for (i = 0; ifeatures, i); + if (!strcmp(nfname, tmp->name)) { + already_in = 1; + break; + } + } + if (already_in) continue; + + GF_SAFEALLOC(feat, GF_WidgetFeature); + feat->name = nfname; + feat->required = required; + feat->params = gf_list_new(); + gf_list_add(widget->features, feat); + + j = 0; + while ((param_node = gf_list_enum(xml_node->content, &j))) { + if (param_node->type==GF_XML_NODE_TYPE && + param_node->name && !strcmp(param_node->name, "param") && + ((!widget_ns_prefix && !param_node->ns) || !strcmp(widget_ns_prefix, param_node->ns))) { + GF_WidgetFeatureParam *wfp; + const char *param_name, *param_value; + char *npname, *npvalue; + + param_name = (char *)wm_xml_get_attr(param_node, "name"); + npname = wm_get_single_attribute(param_name); + if (!strlen(npname)) continue; + + param_value = (char *)wm_xml_get_attr(param_node, "value"); + npvalue = wm_get_single_attribute(param_value); + if (!strlen(npvalue)) { + gf_free(npname); + continue; + } + + GF_SAFEALLOC(wfp, GF_WidgetFeatureParam); + wfp->name = npname; + wfp->value = npvalue; + gf_list_add(feat->params, wfp); + + } + } + + } + } + + gf_list_add(wm->widgets, widget); + } + + GF_SAFEALLOC(wi, GF_WidgetInstance); + wi->widget = widget; + wi->bound_ifces = gf_list_new(); + wi->output_triggers = gf_list_new(); + wi->components = gf_list_new(); + widget->nb_instances++; + wi->instance_id = InstanceID; + wi->permanent = 1; + + if (!InstanceID) { + char szInst[20]; + + count = gf_list_count(wm->widget_instances); + for (i=0; iwidget_instances, i); + if (awi->widget == wi->widget) + wi->instance_id = awi->instance_id; + } + wi->instance_id ++; + + sprintf(szName, "%s#%s#Instance%d", path, wi->widget->name, wi->instance_id); + sprintf(wi->secname, "Widget#%08X", gf_crc_32(szName, strlen(szName))); + + /*create section*/ + gf_cfg_set_key(wm->term->user->config, "Widgets", wi->secname, " "); + gf_cfg_set_key(wm->term->user->config, wi->secname, "WM:Manifest", wi->widget->url); + sprintf(szInst, "%d", wi->instance_id); + gf_cfg_set_key(wm->term->user->config, wi->secname, "WM:InstanceID", szInst); + } + gf_list_add(wm->widget_instances, wi); + + + if (!skip_context && strstr(path, "http://")) { + GF_XMLNode *context; + GF_DownloadSession *ctx_sess = NULL; + char *ctxPath; + context = NULL; + + /*fetch the remote widget context synchronously and load it */ + ctxPath = gf_malloc(sizeof(char) * (strlen(path) + 1 + 15/*?mpeg-u-context*/)); + strcpy(ctxPath, path); + if ((strchr(path, '?') == NULL) && (strstr(path, "%3f")==NULL) && (strstr(path, "%3F")==NULL) ) { + strcat(ctxPath, "?mpeg-u-context"); + } else { + strcat(ctxPath, "&mpeg-u-context"); + } + + /*try to fetch the associated context*/ + ctx_sess = gf_dm_sess_new(wm->term->downloader, (char *)ctxPath, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e); + if (ctx_sess) { + e = gf_dm_sess_process(ctx_sess); + if (e==GF_OK) { + wi->mpegu_context = gf_xml_dom_new(); + e = gf_xml_dom_parse(wi->mpegu_context , gf_dm_sess_get_cache_name(ctx_sess), NULL, NULL); + if (!e) { + context = gf_xml_dom_get_root(wi->mpegu_context); + if (strcmp(context->name, "contextInformation")) context = NULL; + } + } + gf_dm_sess_del(ctx_sess); + e = GF_OK; + } + gf_free(ctxPath); + ctxPath = NULL; + + if (!context && wi->mpegu_context) { + gf_xml_dom_del(wi->mpegu_context); + wi->mpegu_context = NULL; + } + + } + +exit: + if (dom) gf_xml_dom_del(dom); + if (sess) gf_dm_sess_del(sess); + if (e || !wi) { + if (wi) wm_delete_widget_instance(wm, wi); + else { + if (wpackage) widget_package_del(wm, wpackage); + } + return NULL; + } + return wi; +} + + +static Bool wm_enum_widget(void *cbk, char *file_name, char *file_path) +{ + GF_WidgetInstance *wid; + GF_WidgetManager *wm = (GF_WidgetManager *)cbk; + wid = wm_load_widget(wm, file_path, 0, 0); + if (wid) { + wm_widget_jsbind(wm, wid); + /*remove section info*/ + gf_cfg_del_section(wm->term->user->config, wid->secname); + gf_cfg_set_key(wm->term->user->config, "Widgets", wid->secname, NULL); + } + return 0; +} + +static Bool wm_enum_dir(void *cbk, char *file_name, char *file_path) +{ + return gf_enum_directory(file_path, 0, wm_enum_widget, cbk, "mgt"); +} + + +static JSBool SMJS_FUNCTION(wm_initialize) +{ + u32 i, count; + const char*opt; + SMJS_OBJ + //SMJS_ARGS + GF_WidgetManager *wm = (GF_WidgetManager *)JS_GetPrivate(c, obj); + + count = gf_cfg_get_key_count(wm->term->user->config, "Widgets"); + for (i=0; iterm->user->config, "Widgets", i); + /*this is a previously loaded widgets - reload it*/ + if (!strnicmp(name, "Widget#", 7)) { + const char *manifest = gf_cfg_get_key(wm->term->user->config, name, "WM:Manifest"); + if (manifest) { + const char *ID = gf_cfg_get_key(wm->term->user->config, name, "WM:InstanceID"); + u32 instID = ID ? atoi(ID) : 0; + GF_WidgetInstance *wi = wm_load_widget(wm, manifest, instID, 0); + if (wi) { + strcpy(wi->secname, name); + wm_widget_jsbind(wm, wi); + } + } + } + } + + opt = gf_cfg_get_key(wm->term->user->config, "Widgets", "WidgetStore"); + if (opt) gf_enum_directory(opt, 1, wm_enum_dir, wm, NULL); + + return JS_TRUE; +} + +static void widgetmanager_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext *c, JSObject *global, Bool unload) +{ + GF_WidgetManager *wm; + + GF_JSAPIParam par; + JSPropertySpec wmClassProps[] = { + {0, 0, 0, 0, 0} + }; + JSFunctionSpec wmClassFuncs[] = { + SMJS_FUNCTION_SPEC("initialize", wm_initialize, 0), + SMJS_FUNCTION_SPEC("load", wm_load, 2), + SMJS_FUNCTION_SPEC("unload", wm_unload, 1), + SMJS_FUNCTION_SPEC("get", wm_get, 1), + SMJS_FUNCTION_SPEC("findByInterface", wm_find_interface, 1), + SMJS_FUNCTION_SPEC(0, 0, 0) + }; + + wm = jsext->udta; + /*widget manager is only loaded once*/ + if (wm->ctx && (wm->ctx != c)) { + /*load the 'Widget' object in the global scope*/ + widget_load(wm, scene, c, global, unload); + return; + } + + /*unload widgets*/ + if (unload) { + if (wm->obj) { + gf_js_remove_root(wm->ctx, &wm->obj, GF_JSGC_OBJECT); + wm->obj = NULL; + } + + while (gf_list_count(wm->widget_instances)) { + GF_WidgetInstance *widg = gf_list_get(wm->widget_instances, 0); + wm_delete_widget_instance(wm, widg); + } + wm->ctx = NULL; + return; + } + wm->ctx = c; + + if (!scene) return; + + /*setup JS bindings*/ + JS_SETUP_CLASS(wm->widmanClass, "WIDGETMANAGER", JSCLASS_HAS_PRIVATE, wm_getProperty, wm_setProperty, JS_FinalizeStub); + + JS_InitClass(c, global, 0, &wm->widmanClass, 0, 0, wmClassProps, wmClassFuncs, 0, 0); + wm->obj = JS_DefineObject(c, global, "WidgetManager", &wm->widmanClass, 0, 0); + JS_SetPrivate(c, wm->obj, wm); + gf_js_add_root(c, &wm->obj, GF_JSGC_OBJECT); + + + { + JSPropertySpec wmWidgetClassProps[] = { + {0, 0, 0, 0, 0} + }; + JSFunctionSpec wmWidgetClassFuncs[] = { + SMJS_FUNCTION_SPEC("activate", wm_widget_activate, 1), + SMJS_FUNCTION_SPEC("deactivate", wm_widget_deactivate, 0), + SMJS_FUNCTION_SPEC("get_interface", wm_widget_get_interface, 1), + SMJS_FUNCTION_SPEC("bind_output_trigger", wm_widget_bind_output_trigger, 2), + SMJS_FUNCTION_SPEC("set_input", wm_widget_set_input, 2), + SMJS_FUNCTION_SPEC("bind_interface", wm_widget_bind_interface, 2), + SMJS_FUNCTION_SPEC("unbind_interface", wm_widget_unbind_interface, 1), + SMJS_FUNCTION_SPEC("call_input_action", wm_widget_call_input_action, 1), + SMJS_FUNCTION_SPEC("call_input_script", wm_widget_call_input_script, 2), + SMJS_FUNCTION_SPEC("is_interface_bound", wm_widget_is_interface_bound, 1), + SMJS_FUNCTION_SPEC("get_param_value", wm_widget_get_param_value, 1), + SMJS_FUNCTION_SPEC("get_context", wm_widget_get_context, 0), + SMJS_FUNCTION_SPEC("get_component", wm_widget_get_component, 2), + + SMJS_FUNCTION_SPEC(0, 0, 0) + }; + /*setup JS bindings*/ + JS_SETUP_CLASS(wm->wmWidgetClass, "WMWIDGET", JSCLASS_HAS_PRIVATE, wm_widget_getProperty, wm_widget_setProperty, JS_FinalizeStub); + JS_InitClass(c, global, 0, &wm->wmWidgetClass, 0, 0, wmWidgetClassProps, wmWidgetClassFuncs, 0, 0); + + JS_SETUP_CLASS(wm->widgetAnyClass, "WIDGETANY", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub_forSetter, JS_FinalizeStub); + JS_InitClass(c, global, 0, &wm->widgetAnyClass, 0, 0, 0, 0, 0, 0); + } + + JS_SETUP_CLASS(wm->widgetClass, "MPEGWidget", JSCLASS_HAS_PRIVATE, widget_getProperty, widget_setProperty, JS_FinalizeStub); + + if (scene->script_action) { + if (!scene->script_action(scene->script_action_cbck, GF_JSAPI_OP_GET_TERM, scene->RootNode, &par)) + return; + wm->term = par.term; + } + +} + + +static GF_JSUserExtension *gwm_new() +{ + GF_JSUserExtension *dr; + GF_WidgetManager *wm; + dr = gf_malloc(sizeof(GF_JSUserExtension)); + memset(dr, 0, sizeof(GF_JSUserExtension)); + GF_REGISTER_MODULE_INTERFACE(dr, GF_JS_USER_EXT_INTERFACE, "WidgetManager JavaScript Bindings", "gpac distribution"); + + GF_SAFEALLOC(wm, GF_WidgetManager); + wm->widget_instances = gf_list_new(); + wm->widgets = gf_list_new(); + dr->load = widgetmanager_load; + dr->udta = wm; + return dr; +} + + +static void gwm_delete(GF_BaseInterface *ifce) +{ + GF_WidgetManager *wm; + GF_JSUserExtension *dr = (GF_JSUserExtension *) ifce; + if (!dr) + return; + wm = dr->udta; + if (!wm) + return; + if (wm->widget_instances) + gf_list_del(wm->widget_instances); + wm->widget_instances = NULL; + if (wm->widgets) + gf_list_del(wm->widgets); + wm->widgets = NULL; + gf_free(wm); + dr->udta = NULL; + gf_free(dr); +} +#endif + + +GF_EXPORT +const u32 *QueryInterfaces() +{ + static u32 si [] = { +#ifdef GPAC_HAS_SPIDERMONKEY + GF_JS_USER_EXT_INTERFACE, + GF_SCENE_DECODER_INTERFACE, +#endif + 0 + }; + return si; +} + +GF_EXPORT +GF_BaseInterface *LoadInterface(u32 InterfaceType) +{ +#ifdef GPAC_HAS_SPIDERMONKEY + if (InterfaceType == GF_JS_USER_EXT_INTERFACE) return (GF_BaseInterface *)gwm_new(); + else if (InterfaceType == GF_SCENE_DECODER_INTERFACE) return (GF_BaseInterface *)LoadWidgetReader(); +#endif + return NULL; +} + +GF_EXPORT +void ShutdownInterface(GF_BaseInterface *ifce) +{ + switch (ifce->InterfaceType) { +#ifdef GPAC_HAS_SPIDERMONKEY + case GF_JS_USER_EXT_INTERFACE: + gwm_delete(ifce); + break; + case GF_SCENE_DECODER_INTERFACE: + ShutdownWidgetReader(ifce); + break; +#endif + } +} + diff --git a/modules/widgetman/widgetman.h b/modules/widgetman/widgetman.h new file mode 100644 index 0000000..879cf8b --- /dev/null +++ b/modules/widgetman/widgetman.h @@ -0,0 +1,360 @@ +//This software module was originally developed by TelecomParisTech in the +//course of the development of MPEG-U Widgets (ISO/IEC 23007-1) standard. +// +//This software module is an implementation of a part of one or +//more MPEG-U Widgets (ISO/IEC 23007-1) tools as specified by the MPEG-U Widgets +//(ISO/IEC 23007-1) standard. ISO/IEC gives users of the MPEG-U Widgets +//(ISO/IEC 23007-1) free license to this software module or modifications +//thereof for use in hardware or software products claiming conformance to +//the MPEG-U Widgets (ISO/IEC 23007-1). Those intending to use this software +//module in hardware or software products are advised that its use may +//infringe existing patents. +//The original developer of this software module and his/her company, the +//subsequent editors and their companies, and ISO/IEC have no liability +//for use of this software module or modifications thereof in an implementation. +//Copyright is not released for non MPEG-U Widgets (ISO/IEC 23007-1) conforming +//products. +//Telecom ParisTech retains full right to use the code for his/her own purpose, +//assign or donate the code to a third party and to inhibit third parties from +//using the code for non MPEG-U Widgets (ISO/IEC 23007-1) conforming products. +// +//This copyright notice must be included in all copies or derivative works. +// +//Copyright (c) 2009. +// +// Alternatively, this software module may be redistributed and/or modified +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////////// +// +// Authors: +// Jean Le Feuvre, Telecom ParisTech +// Cyril Concolato, Telecom ParisTech +// +///////////////////////////////////////////////////////////////////////////////// + +#ifndef _WIDGETMAN_H_ +#define _WIDGETMAN_H_ + +#include "unzip.h" + +/*base SVG type*/ +#include + +#ifdef GPAC_HAS_SPIDERMONKEY + +#include +#include +#include +/*dom events*/ +#include + +#include +#include +#include +#include +#include + + +#include + +#include + +#include +#include + + +JSBool gf_sg_js_event_add_listener(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, GF_Node *vrml_node); +JSBool gf_sg_js_event_remove_listener(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, GF_Node *vrml_node); + +typedef struct _widget_manager +{ + JSContext *ctx; + /*widget manager class*/ + JSClass widmanClass; + /*widget class used by the widget manager*/ + JSClass wmWidgetClass; + + /*widget class used by the widget scripts*/ + JSClass widgetClass; + + JSClass widgetAnyClass; + + JSObject *obj; + GF_Terminal *term; + GF_List *widget_instances; + /*list of loaded prototypes (eg 1 per all instances of the same widget*/ + GF_List *widgets; +} GF_WidgetManager; + + + +enum +{ + GF_WPIN_STRING, + GF_WPIN_INTEGER, + GF_WPIN_NUMBER, +}; + +typedef struct +{ + char *inner_path; + char *extracted_path; + Bool extracted; +} GF_WidgetPackageResource; + +typedef struct _widget_package_relocator +{ + GF_TERM_URI_RELOCATOR + GF_List *resources; + struct _widget *widget; + GF_WidgetManager *wm; + Bool is_zip; + char root_extracted_path[GF_MAX_PATH]; + char archive_id[14]; + char *package_path; + GF_DownloadSession *sess; +} GF_WidgetPackage; + + +enum +{ + GF_WM_PARAM_OUTPUT, + GF_WM_PARAM_INPUT, + GF_WM_INPUT_ACTION, + GF_WM_OUTPUT_TRIGGER, + GF_WM_BIND_ACTION, + GF_WM_UNBIND_ACTION, + GF_WM_PREF_CONNECT, + GF_WM_ACTIVATE_TRIGGER, + GF_WM_DEACTIVATE_TRIGGER, + GF_WM_PREF_SAVEDACTION, + GF_WM_PREF_RESTOREDACTION, + GF_WM_PREF_SAVETRIGGER, + GF_WM_PREF_RESTORETRIGGER, +}; + +#define GF_WM_PARAM_SCRIPT_STRING (u16) 0 +#define GF_WM_PARAM_SCRIPT_BOOL (u16) 1 +#define GF_WM_PARAM_SCRIPT_NUMBER (u16) 2 + +typedef struct +{ + struct __widget_message *msg; + + u16 type; + u16 script_type; + Bool in_action; + + char *name; + char *node; + char *attribute; + char *default_value; +} GF_WidgetPin; + +typedef struct __widget_message +{ + struct _widget_interface *ifce; + + char *name; + Bool is_output; + GF_List *params; + + GF_WidgetPin *input_action; + GF_WidgetPin *output_trigger; + +} GF_WidgetMessage; + +typedef struct _widget_interface +{ + struct __widget_content *content; + char *type; + GF_List *messages; + + GF_WidgetPin *bind_action; + GF_WidgetPin *unbind_action; + Bool provider, multiple_binding, required; + char *connectTo; + + JSObject *obj; +} GF_WidgetInterface; + +typedef struct _widget_component +{ + struct __widget_content *content; + char *id; /*may be NULL*/ + char *src; /*may be NULL*/ + GF_List *required_interfaces; /*may be empty*/ + GF_WidgetPin *activateTrigger; + GF_WidgetPin *deactivateTrigger; + GF_WidgetPin *activatedAction; + GF_WidgetPin *deactivatedAction; +} GF_WidgetComponent; + +enum +{ + GF_WM_PREF_READONLY = 1, + GF_WM_PREF_SAVE = 1<<1, + GF_WM_PREF_MIGRATE = 1<<2, +}; + +typedef struct +{ + char *name, *value; + u32 flags; + GF_WidgetPin *connectTo; +} GF_WidgetPreference; + +typedef struct +{ + char *name, *value; +} GF_WidgetFeatureParam; + +typedef struct +{ + char *name; + Bool required; + GF_List *params; +} GF_WidgetFeature; + +typedef struct __widget_content +{ + struct _widget *widget; + + char *src; + char *relocated_src; + u32 width, height; + + char *encoding, *mimetype; + + GF_List *interfaces; + GF_List *components; + /*list of preferences for the widget content*/ + GF_List *preferences; + + GF_WidgetPin *savedAction; + GF_WidgetPin *restoredAction; + GF_WidgetPin *saveTrigger; + GF_WidgetPin *restoreTrigger; +} GF_WidgetContent; + +typedef struct _widget +{ + GF_WidgetManager *wm; + + u32 nb_instances; + + /* url to the file.wgt file when zip packaged or to the config.xml file when unpackaged */ + char *url; + /* path to the manifest/config document */ + char *manifest_path; + + GF_List *icons; +/* + GF_WidgetContent *simple; + char *icon_url; +*/ + GF_WidgetContent *main; + + GF_WidgetPackage *wpack; + + /*misc metadata for W3C Widgets API*/ + char *name, *shortname, *identifier, + *authorName, *authorEmail, *authorHref, + *description, *version, + *uuid, *license, *licenseHref, *viewmodes; + + u32 width, height; + + GF_List *features; + + Bool discardable, multipleInstance; + + /*when a widget is being received from a remote peer, + we remember where we locally store it to be able to further remote it + This is only supported for packaged widgets*/ + char *local_path; +} GF_Widget; + +typedef struct _widget_instance +{ + GF_Widget *widget; + + u32 instance_id; + JSObject *obj; + u8 secname[18]; + GF_SceneGraph *scene; + /*node in the widget manager which holds the widget: Inline {} , , ...*/ + GF_Node *anchor; + + Bool activated, permanent; + + GF_List *output_triggers; + GF_List *bound_ifces; + /*list of components for a parent widget*/ + GF_List *components; + /*parent of the widget for a component widget*/ + struct _widget_instance *parent; + + GF_DOMParser *mpegu_context; + + + /*scripting context of the widget scene*/ + JSContext *scene_context; + JSObject *scene_global; + /*"Widget" object in the scene*/ + JSObject *scene_obj; +} GF_WidgetInstance; + + +typedef struct +{ + GF_WidgetInterface *ifce; + GF_WidgetInstance *wid; + char *hostname; + JSObject *obj; + JSObject *cookie; +} GF_WidgetInterfaceInstance; + +typedef struct +{ + GF_WidgetComponent *comp; + GF_WidgetInstance *wid; +} GF_WidgetComponentInstance; + + +GF_WidgetInstance *wm_load_widget(GF_WidgetManager *wm, const char *path, u32 InstanceID, Bool skip_context); + + +JSBool SMJS_FUNCTION(widget_has_feature); +JSBool SMJS_FUNCTION(widget_open_url); +JSBool SMJS_FUNCTION(widget_get_attention); +JSBool SMJS_FUNCTION(widget_show_notification); +JSBool SMJS_FUNCTION(widget_get_interface); +JSBool widget_getProperty(JSContext *c, JSObject *obj, SMJS_PROP_GETTER, jsval *vp); +JSBool widget_setProperty(JSContext *c, JSObject *obj, SMJS_PROP_SETTER, jsval *vp); + +void widget_on_interface_bind(GF_WidgetInterfaceInstance *ifce, Bool unbind); + +void widget_load(GF_WidgetManager *wm, GF_SceneGraph *scene, JSContext *c, JSObject *global, Bool unload); + +GF_WidgetComponentInstance *wm_activate_component(JSContext *c, GF_WidgetInstance *wid, GF_WidgetComponent *comp, Bool skip_wm_notification); + +void wm_deactivate_component(JSContext *c, GF_WidgetInstance *wid, GF_WidgetComponent *comp, GF_WidgetComponentInstance *comp_inst); + + + +const char *wm_xml_get_attr(GF_XMLNode *root, const char *name); + +GF_BaseInterface *LoadWidgetReader(); +void ShutdownWidgetReader(GF_BaseInterface *ifce); + + +#endif /*GPAC_HAS_SPIDERMONKEY*/ + +#endif diff --git a/modules/x11_out/Makefile b/modules/x11_out/Makefile index 0c1e0d3..cf47d9d 100644 --- a/modules/x11_out/Makefile +++ b/modules/x11_out/Makefile @@ -15,7 +15,6 @@ LDFLAGS+=-pg endif CFLAGS+=-I"$(SRC_PATH)/include" -# -I/usr/local/arm/3.3.2/include ifeq ($(X11_INC_PATH), ) @@ -64,7 +63,7 @@ all: $(LIB) $(LIB): $(OBJS) - $(CC) $(SHFLAGS) $(LDFLAGS) -lX11 -L../../bin/gcc -lgpac -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -lX11 -L../../bin/gcc -lgpac $(EXTRALIBS) ifeq ($(STATICBUILD),yes) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_x11_out-static.$(DYN_LIB_SUFFIX) $(OBJS) -lX11 -L../../bin/gcc -lgpac_static $(EXTRALIBS) endif diff --git a/src/Makefile b/src/Makefile index 06c8800..3bdad5b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -168,7 +168,7 @@ endif EXTRALIBS+=$(GPAC_SH_FLAGS) endif -LD_SONAME="-Wl,-soname,$(LIB)" +LD_SONAME="-Wl,-soname,libgpac.so.$(VERSION_MAJOR)" ifeq ($(CONFIG_DARWIN), yes) LD_SONAME= endif @@ -210,6 +210,11 @@ else ar cr ../bin/gcc/libgpac_static.a $(OBJS) ranlib ../bin/gcc/libgpac_static.a $(CC) $(SHFLAGS) $(LD_SONAME) $(LDFLAGS) -o ../bin/gcc/$@ $(OBJS) $(EXTRALIBS) +ifeq (,$(findstring yes, $(CONFIG_WIN32))) + mv ../bin/gcc/$@ ../bin/gcc/$@.$(VERSION_SONAME) + ln -sf $@.$(VERSION_SONAME) ../bin/gcc/$@.$(VERSION_MAJOR) + ln -sf $@.$(VERSION_SONAME) ../bin/gcc/$@ +endif endif dep: depend @@ -220,7 +225,9 @@ depend: clean: rm -f $(OBJS) ../bin/gcc/$(LIB) - rm -rf ../bin/gcc/libgpac_static.a + rm -rf ../bin/gcc/libgpac_static.a ../bin/gcc/libgpac.so \ + ../bin/gcc/libgpac.so.$(VERSION_MAJOR) \ + ../bin/gcc/libgpac.so.$(VERSION_SONAME) distclean: clean rm -f Makefile.bak .depend diff --git a/src/bifs/script.h b/src/bifs/script.h index 7796087..b305c88 100644 --- a/src/bifs/script.h +++ b/src/bifs/script.h @@ -102,7 +102,9 @@ enum }; GF_Err SFScript_Parse(GF_BifsDecoder *codec, SFScript *script_field, GF_BitStream *bs, GF_Node *n); +#ifndef GPAC_DISABLE_BIFS_ENC GF_Err SFScript_Encode(GF_BifsEncoder *codec, SFScript *script_field, GF_BitStream *bs, GF_Node *n); +#endif #endif /* !defined(GPAC_DISABLE_BIFS) && defined(GPAC_HAS_SPIDERMONKEY) */ diff --git a/src/bifs/script_enc.c b/src/bifs/script_enc.c index c6733e5..77c09fe 100644 --- a/src/bifs/script_enc.c +++ b/src/bifs/script_enc.c @@ -30,7 +30,7 @@ #include -#if !defined(GPAC_DISABLE_BIFS) && defined(GPAC_HAS_SPIDERMONKEY) +#if !defined(GPAC_DISABLE_BIFS) && !defined(GPAC_DISABLE_BIFS_ENC) && defined(GPAC_HAS_SPIDERMONKEY) typedef struct { @@ -1773,4 +1773,4 @@ void SFE_Params(ScriptEnc *sc_enc, u32 start, u32 end) } } -#endif /* !defined(GPAC_DISABLE_BIFS) && defined(GPAC_HAS_SPIDERMONKEY) */ +#endif /* !defined(GPAC_DISABLE_BIFS) && !defined(GPAC_DISABLE_BIFS_ENC) && defined(GPAC_HAS_SPIDERMONKEY) */ diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 7bdfb70..8672579 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -2339,7 +2339,7 @@ void gf_sc_traverse_subscene_ex(GF_Compositor *compositor, GF_Node *inline_paren new_tag = TAG_MPEG4_Layer3D; } } -#ifndef GPAC_DISABLE_3D +#if !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_3D) /*if the inlined root node is a 3D one except Layer3D and we are not in a 3D context, insert a Layer3D at the root*/ else if (!tr_state->visual->type_3d && ((tag==TAG_MPEG4_Group) || (tag==TAG_X3D_Group))) { diff --git a/src/compositor/mesh.c b/src/compositor/mesh.c index df401c7..8914608 100644 --- a/src/compositor/mesh.c +++ b/src/compositor/mesh.c @@ -255,7 +255,7 @@ void mesh_recompute_normals(GF_Mesh *mesh) } } -#ifndef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) void mesh_generate_tex_coords(GF_Mesh *mesh, GF_Node *__texCoords) { u32 i; @@ -797,7 +797,7 @@ void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node { u32 i, n, count, c_count, col_count; u32 index; - u32 first_idx, last_idx; + u32 first_idx, last_idx; Bool move_to; SFVec3f pt; SFColorRGBA colRGBA; @@ -805,7 +805,9 @@ void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord; M_Coordinate *coord = (M_Coordinate*) __coord; M_Color *colorRGB = (M_Color *) __color; +#ifndef GPAC_DISABLE_X3D X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color; +#endif if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) { coord = NULL; @@ -832,11 +834,16 @@ void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node } has_color = 0; if (__color) { +#ifndef GPAC_DISABLE_X3D if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) { colorRGB = NULL; has_color = (colorRGBA->color.count) ? 1 : 0; - } else { - colorRGBA = NULL; + } else +#endif + { +#ifndef GPAC_DISABLE_X3D + colorRGBA = NULL; +#endif has_color = (colorRGB->color.count) ? 1 : 0; } } @@ -848,7 +855,9 @@ void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node n = 0; if (has_color && !colorPerVertex) { index = colorIndex->count ? colorIndex->vals[0] : 0; +#ifndef GPAC_DISABLE_X3D if ((u32) index < col_count) MESH_GET_COL(colRGBA, index); +#endif } move_to = 1; @@ -865,14 +874,18 @@ void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node if (ncount) index = colorIndex->vals[n]; else if (ncount) index = colorIndex->vals[i]; else if (ivals[i]; else index = i; @@ -900,7 +913,9 @@ void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node mesh_set_line(mesh, last_idx, first_idx); } if (coord2D) mesh->flags |= MESH_IS_2D; +#ifndef GPAC_DISABLE_X3D if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA; +#endif mesh_update_bounds(mesh); } @@ -913,7 +928,9 @@ void mesh_new_ps(GF_Mesh *mesh, GF_Node *__coord, GF_Node *__color) M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord; M_Coordinate *coord = (M_Coordinate*) __coord; M_Color *colorRGB = (M_Color *) __color; +#ifndef GPAC_DISABLE_X3D X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color; +#endif if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) { coord = NULL; @@ -930,11 +947,16 @@ void mesh_new_ps(GF_Mesh *mesh, GF_Node *__coord, GF_Node *__color) has_color = 0; if (__color) { +#ifndef GPAC_DISABLE_X3D if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) { colorRGB = NULL; has_color = (colorRGBA->color.count) ? 1 : 0; - } else { + } else +#endif + { +#ifndef GPAC_DISABLE_X3D colorRGBA = NULL; +#endif has_color = (colorRGB->color.count) ? 1 : 0; } } @@ -943,7 +965,9 @@ void mesh_new_ps(GF_Mesh *mesh, GF_Node *__coord, GF_Node *__color) colRGBA.red = colRGBA.green = colRGBA.blue = colRGBA.alpha = FIX_ONE; for (i=0; ipoint.vals[i].x; pt.y = coord2D->point.vals[i].y; @@ -1047,7 +1071,9 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord; M_Coordinate *coord = (M_Coordinate*) __coord; M_Color *colorRGB = (M_Color *) __color; +#ifndef GPAC_DISABLE_X3D X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color; +#endif M_Normal *normal = (M_Normal*) __normal; M_TextureCoordinate *txcoord = (M_TextureCoordinate*) __texCoords; @@ -1059,15 +1085,21 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, coord = NULL; } else { coord2D = NULL; - if (!__coord) return; + if (!__coord) + return; /*not supported yet*/ - if (gf_node_get_tag(__coord) == TAG_X3D_CoordinateDouble) return; +#ifndef GPAC_DISABLE_X3D + if (gf_node_get_tag(__coord) == TAG_X3D_CoordinateDouble) + return; +#endif } gen_tex_coords = 0; +#ifndef GPAC_DISABLE_X3D if (__texCoords && (gf_node_get_tag(__texCoords)==TAG_X3D_TextureCoordinateGenerator)) { gen_tex_coords = 1; txcoord = NULL; } +#endif if (!coord2D && !coord) return; c_count = coord2D ? coord2D->point.count : coord->point.count; @@ -1115,11 +1147,16 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, has_color = 0; if (__color) { +#ifndef GPAC_DISABLE_X3D if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) { colorRGB = NULL; has_color = (colorRGBA->color.count) ? 1 : 0; - } else { + } else +#endif + { +#ifndef GPAC_DISABLE_X3D colorRGBA = NULL; +#endif has_color = (colorRGB->color.count) ? 1 : 0; } } @@ -1127,7 +1164,9 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, if (has_color) { if (!colorPerVertex) { index = colorIndex->count ? colorIndex->vals[0] : 0; +#ifndef GPAC_DISABLE_X3D MESH_GET_COL(colRGBA, index); +#endif } else { if (!colorIndex->vals) colorIndex = coordIndex; } @@ -1178,7 +1217,9 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, n++; if (has_color && !colorPerVertex) { GET_IDX(n, colorIndex); +#ifndef GPAC_DISABLE_X3D MESH_GET_COL(colRGBA, index); +#endif } if (has_normal && !normalPerVertex) { GET_IDX(n, normalIndex); @@ -1205,7 +1246,9 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, } else { if (has_color && colorPerVertex) { GET_IDX(i, colorIndex); +#ifndef GPAC_DISABLE_X3D MESH_GET_COL(colRGBA, index); +#endif } if (has_normal && normalPerVertex) { GET_IDX(i, normalIndex); @@ -1300,8 +1343,10 @@ void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, if (!coord2D) gf_mesh_build_aabbtree(mesh); +#ifndef GPAC_DISABLE_X3D if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA; if (gen_tex_coords) mesh_generate_tex_coords(mesh, __texCoords); +#endif } void mesh_new_ifs2d(GF_Mesh *mesh, GF_Node *node) @@ -1336,7 +1381,9 @@ void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node) M_ElevationGrid *eg = (M_ElevationGrid *) node; M_Normal *norm = (M_Normal *)eg->normal; M_Color *colorRGB = (M_Color *)eg->color; +#ifndef GPAC_DISABLE_X3D X_ColorRGBA *colorRGBA = (X_ColorRGBA *)eg->color; +#endif SFColorRGBA rgba; M_TextureCoordinate *txc = (M_TextureCoordinate *)eg->texCoord; @@ -1349,11 +1396,16 @@ void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node) has_normal = norm ? norm->vector.count : 0; has_color = 0; if (eg->color) { +#ifndef GPAC_DISABLE_X3D if (gf_node_get_tag(eg->color)==TAG_X3D_ColorRGBA) { colorRGB = NULL; has_color = colorRGBA->color.count ? 1 : 0; - } else { + } else +#endif + { +#ifndef GPAC_DISABLE_X3D colorRGBA = NULL; +#endif has_color = colorRGB->color.count ? 1 : 0; } } @@ -1424,7 +1476,9 @@ void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node) /*get face color*/ if (has_color && !eg->colorPerVertex) { idx = i + j * (xDimension-1); +#ifndef GPAC_DISABLE_X3D MESH_GET_COL(rgba, idx); +#endif vx.color = MESH_MAKE_COL(rgba); } /*get face normal*/ @@ -1447,7 +1501,9 @@ void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node) /*get color per vertex*/ if (has_color && eg->colorPerVertex) { idx = i+l + (j+k) * xDimension; +#ifndef GPAC_DISABLE_X3D MESH_GET_COL(rgba, idx); +#endif vx.color = MESH_MAKE_COL(rgba); } /*get tex coord*/ @@ -1555,7 +1611,9 @@ void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node) mesh_update_bounds(mesh); if (!eg->ccw) mesh->flags |= MESH_IS_CW; if (eg->solid) mesh->flags |= MESH_IS_SOLID; +#ifndef GPAC_DISABLE_X3D if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA; +#endif gf_mesh_build_aabbtree(mesh); } diff --git a/src/export.cpp b/src/export.cpp index 87b1536..0e67cd5 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -1053,12 +1053,12 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_media_make_psp) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_import) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_import_chapters) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_media_change_par) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_change_pl) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_media_fragment_file) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_avc_rewrite_samples) ) #endif /*GPAC_DISABLE_MEDIA_IMPORT*/ +#pragma comment (linker, EXPORT_SYMBOL(gf_media_change_par) ) + #ifndef GPAC_DISABLE_AV_PARSERS #pragma comment (linker, EXPORT_SYMBOL(gf_avc_get_sps_info) ) @@ -1163,7 +1163,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sm_load_bt_from_string) ) #endif -#ifndef GPAC_DISABLE_SCENE_ENCODER +#if !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_ISOM_WRITE) #pragma comment (linker, EXPORT_SYMBOL(gf_sm_encode_to_file) ) #endif @@ -1173,13 +1173,17 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sm_dump) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sm_dump_command_list) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sm_dump_graph) ) +#ifndef GPAC_DISABLE_OD_DUMP #pragma comment (linker, EXPORT_SYMBOL(gf_odf_dump_au) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_dump_com) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_dump_desc) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_dump_com_list) ) +#ifndef GPAC_MINIMAL_ODF #pragma comment (linker, EXPORT_SYMBOL(gf_oci_dump_event) ) #pragma comment (linker, EXPORT_SYMBOL(gf_oci_dump_au) ) #endif +#endif +#endif #ifndef GPAC_DISABLE_SENG /*bifsengine exports*/ @@ -1632,9 +1636,12 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dm_wget) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_wget_with_cache) ) -#ifndef GPAC_DISABLE_ISOM +#ifndef GPAC_DISABLE_ISOM_WRITE #pragma comment (linker, EXPORT_SYMBOL(gf_media_mpd_start) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_mpd_end) ) +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS +#pragma comment (linker, EXPORT_SYMBOL(gf_media_fragment_file) ) +#endif #endif /* dvb_mpe.h */ diff --git a/src/ietf/rtp_streamer.c b/src/ietf/rtp_streamer.c index be74f8f..850af4b 100644 --- a/src/ietf/rtp_streamer.c +++ b/src/ietf/rtp_streamer.c @@ -31,7 +31,7 @@ #endif #include -#ifndef GPAC_DISABLE_STREAMING +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_ISOM) struct __rtp_streamer { @@ -733,5 +733,5 @@ GF_Err gf_rtp_streamer_send_rtcp(GF_RTPStreamer *streamer, Bool force_ts, u32 rt return gf_rtp_send_rtcp_report(streamer->channel, NULL, NULL); } -#endif /*GPAC_DISABLE_STREAMING*/ +#endif /*GPAC_DISABLE_STREAMING && GPAC_DISABLE_ISOM*/ diff --git a/src/isomedia/box_code_base.c b/src/isomedia/box_code_base.c index 46a2603..ab39b6d 100644 --- a/src/isomedia/box_code_base.c +++ b/src/isomedia/box_code_base.c @@ -5846,12 +5846,11 @@ GF_Err tfhd_Size(GF_Box *s) return GF_OK; } - - #endif /*GPAC_DISABLE_ISOM_WRITE*/ #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ + void tims_del(GF_Box *s) { GF_TSHintEntryBox *tims = (GF_TSHintEntryBox *)s; @@ -6092,11 +6091,9 @@ GF_Box *traf_New() return (GF_Box *)tmp; } - #ifndef GPAC_DISABLE_ISOM_WRITE - GF_Err traf_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; @@ -7754,7 +7751,6 @@ GF_Err lsr1_Size(GF_Box *s) #endif /*GPAC_DISABLE_ISOM_WRITE*/ -#ifndef GPAC_DISABLE_ISOM_FRAGMENTS void sidx_del(GF_Box *s) { @@ -7863,7 +7859,6 @@ GF_Err sidx_Size(GF_Box *s) #endif /*GPAC_DISABLE_ISOM_WRITE*/ -#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ GF_Box *subs_New() @@ -7898,6 +7893,9 @@ void subs_del(GF_Box *s) gf_free(ptr); } + +#ifndef GPAC_DISABLE_ISOM_WRITE + GF_Err subs_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; @@ -7959,6 +7957,7 @@ GF_Err subs_Size(GF_Box *s) return GF_OK; } +#endif /*GPAC_DISABLE_ISOM_WRITE*/ GF_Err subs_Read(GF_Box *s, GF_BitStream *bs) { @@ -8004,6 +8003,8 @@ GF_Err subs_Read(GF_Box *s, GF_BitStream *bs) } +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + GF_Box *tfdt_New() { GF_TFBaseMediaDecodeTimeBox *tmp; @@ -8071,7 +8072,7 @@ GF_Err tfdt_Size(GF_Box *s) #endif /*GPAC_DISABLE_ISOM_WRITE*/ - +#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ GF_Box *rvcc_New() diff --git a/src/isomedia/box_dump.c b/src/isomedia/box_dump.c index 4af3783..bad1efc 100644 --- a/src/isomedia/box_dump.c +++ b/src/isomedia/box_dump.c @@ -3500,6 +3500,7 @@ GF_Err lsr1_dump(GF_Box *a, FILE * trace) return GF_OK; } + GF_Err sidx_dump(GF_Box *a, FILE * trace) { u32 i; @@ -3547,7 +3548,7 @@ GF_Err subs_dump(GF_Box *a, FILE * trace) return GF_OK; } - +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS GF_Err tfdt_dump(GF_Box *a, FILE * trace) { GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox*) a; @@ -3559,6 +3560,7 @@ GF_Err tfdt_dump(GF_Box *a, FILE * trace) fprintf(trace, "\n"); return GF_OK; } +#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ GF_Err rvcc_dump(GF_Box *a, FILE * trace) { diff --git a/src/isomedia/box_funcs.c b/src/isomedia/box_funcs.c index d17a27c..c870f45 100644 --- a/src/isomedia/box_funcs.c +++ b/src/isomedia/box_funcs.c @@ -565,9 +565,11 @@ GF_Box *gf_isom_box_new(u32 boxType) case GF_ISOM_BOX_TYPE_LSRC: return lsrc_New(); case GF_ISOM_BOX_TYPE_LSR1: return lsr1_New(); +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS case GF_ISOM_BOX_TYPE_SIDX: return sidx_New(); case GF_ISOM_BOX_TYPE_SUBS: return subs_New(); case GF_ISOM_BOX_TYPE_TFDT: return tfdt_New(); +#endif case GF_ISOM_BOX_TYPE_RVCC: return rvcc_New(); default: @@ -691,6 +693,7 @@ void gf_isom_box_del(GF_Box *a) case GF_ISOM_BOX_TYPE_MFHD: mfhd_del(a); return; case GF_ISOM_BOX_TYPE_TRAF: traf_del(a); return; case GF_ISOM_BOX_TYPE_TFHD: tfhd_del(a); return; + case GF_ISOM_BOX_TYPE_TFDT: tfdt_del(a); return; case GF_ISOM_BOX_TYPE_TRUN: trun_del(a); return; #endif @@ -820,7 +823,6 @@ void gf_isom_box_del(GF_Box *a) case GF_ISOM_BOX_TYPE_SIDX: sidx_del(a); return; case GF_ISOM_BOX_TYPE_SUBS: subs_del(a); return; - case GF_ISOM_BOX_TYPE_TFDT: tfdt_del(a); return; case GF_ISOM_BOX_TYPE_RVCC: rvcc_del(a); return; default: @@ -830,8 +832,6 @@ void gf_isom_box_del(GF_Box *a) } - - GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) { switch (a->type) { @@ -932,6 +932,7 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) case GF_ISOM_BOX_TYPE_MFHD: return mfhd_Read(a, bs); case GF_ISOM_BOX_TYPE_TRAF: return traf_Read(a, bs); case GF_ISOM_BOX_TYPE_TFHD: return tfhd_Read(a, bs); + case GF_ISOM_BOX_TYPE_TFDT: return tfdt_Read(a, bs); case GF_ISOM_BOX_TYPE_TRUN: return trun_Read(a, bs); #endif @@ -1053,7 +1054,6 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) case GF_ISOM_BOX_TYPE_SIDX: return sidx_Read(a, bs); case GF_ISOM_BOX_TYPE_SUBS: return subs_Read(a, bs); - case GF_ISOM_BOX_TYPE_TFDT: return tfdt_Read(a, bs); case GF_ISOM_BOX_TYPE_RVCC: return rvcc_Read(a, bs); default: @@ -1166,6 +1166,7 @@ GF_Err gf_isom_box_write(GF_Box *a, GF_BitStream *bs) case GF_ISOM_BOX_TYPE_MFHD: return mfhd_Write(a, bs); case GF_ISOM_BOX_TYPE_TRAF: return traf_Write(a, bs); case GF_ISOM_BOX_TYPE_TFHD: return tfhd_Write(a, bs); + case GF_ISOM_BOX_TYPE_TFDT: return tfdt_Write(a, bs); case GF_ISOM_BOX_TYPE_TRUN: return trun_Write(a, bs); #endif @@ -1287,7 +1288,6 @@ GF_Err gf_isom_box_write(GF_Box *a, GF_BitStream *bs) case GF_ISOM_BOX_TYPE_SIDX: return sidx_Write(a, bs); case GF_ISOM_BOX_TYPE_SUBS: return subs_Write(a, bs); - case GF_ISOM_BOX_TYPE_TFDT: return tfdt_Write(a, bs); case GF_ISOM_BOX_TYPE_RVCC: return rvcc_Write(a, bs); default: @@ -1399,6 +1399,7 @@ GF_Err gf_isom_box_size(GF_Box *a) case GF_ISOM_BOX_TYPE_MFHD: return mfhd_Size(a); case GF_ISOM_BOX_TYPE_TRAF: return traf_Size(a); case GF_ISOM_BOX_TYPE_TFHD: return tfhd_Size(a); + case GF_ISOM_BOX_TYPE_TFDT: return tfdt_Size(a); case GF_ISOM_BOX_TYPE_TRUN: return trun_Size(a); #endif @@ -1519,7 +1520,6 @@ GF_Err gf_isom_box_size(GF_Box *a) case GF_ISOM_BOX_TYPE_SIDX: return sidx_Size(a); case GF_ISOM_BOX_TYPE_SUBS: return subs_Size(a); - case GF_ISOM_BOX_TYPE_TFDT: return tfdt_Size(a); case GF_ISOM_BOX_TYPE_RVCC: return rvcc_Size(a); default: return defa_Size(a); diff --git a/src/isomedia/isom_intern.c b/src/isomedia/isom_intern.c index e24ee81..2875354 100644 --- a/src/isomedia/isom_intern.c +++ b/src/isomedia/isom_intern.c @@ -430,8 +430,9 @@ void gf_isom_delete_movie(GF_ISOFile *mov) #endif gf_isom_box_array_del(mov->TopBoxes); +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS gf_isom_box_array_del(mov->moof_list); - +#endif if (mov->fileName) gf_free(mov->fileName); gf_free(mov); @@ -496,7 +497,13 @@ GF_Err GetMediaTime(GF_TrackBox *trak, Bool force_non_empty, u64 movieTime, u64 if (! trak->editBox || !trak->editBox->editList) { *MediaTime = movieTime; //check this is in our media time line - if (!trak->moov->mov->use_segments && (*MediaTime > lastSampleTime)) *MediaTime = lastSampleTime; + if ((*MediaTime > lastSampleTime) +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + && !trak->moov->mov->use_segments +#endif + ) { + *MediaTime = lastSampleTime; + } *useEdit = 0; return GF_OK; } diff --git a/src/isomedia/isom_read.c b/src/isomedia/isom_read.c index 261304c..66821b9 100644 --- a/src/isomedia/isom_read.c +++ b/src/isomedia/isom_read.c @@ -59,7 +59,9 @@ u64 gf_isom_get_file_size(GF_ISOFile *the_file) { if (!the_file) return 0; if (the_file->movieFileMap) return gf_bs_get_size(the_file->movieFileMap->bs); +#ifndef GPAC_DISABLE_ISOM_WRITE if (the_file->editFileMap) return gf_bs_get_size(the_file->editFileMap->bs); +#endif return 0; } @@ -1023,7 +1025,11 @@ u32 gf_isom_get_sample_count(GF_ISOFile *the_file, u32 trackNumber) GF_TrackBox *trak; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return 0; - return trak->Media->information->sampleTable->SampleSize->sampleCount + trak->sample_count_at_seg_start; + return trak->Media->information->sampleTable->SampleSize->sampleCount +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + + trak->sample_count_at_seg_start +#endif + ; } u32 gf_isom_get_constant_sample_size(GF_ISOFile *the_file, u32 trackNumber) @@ -1395,7 +1401,11 @@ GF_Err gf_isom_get_sample_for_movie_time(GF_ISOFile *the_file, u32 trackNumber, return GF_EOS; } } - else if (!trak->dts_at_seg_start && (movieTime * trak->moov->mvhd->timeScale > trak->Header->duration * trak->Media->mediaHeader->timeScale)) { + else if ((movieTime * trak->moov->mvhd->timeScale > trak->Header->duration * trak->Media->mediaHeader->timeScale) +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + && !trak->dts_at_seg_start +#endif + ) { *sample = NULL; if (sampleNumber) *sampleNumber = 0; *StreamDescriptionIndex = 0; @@ -2692,11 +2702,15 @@ void gf_isom_reset_fragment_info(GF_ISOFile *movie) if (!movie) return; for (i=0; imoov->trackList); i++) { GF_TrackBox *trak = gf_list_get(movie->moov->trackList, i); + trak->Media->information->sampleTable->SampleSize->sampleCount = 0; +#ifdef GPAC_DISABLE_ISOM_FRAGMENTS + } +#else trak->dts_at_seg_start = 0; trak->sample_count_at_seg_start = 0; - trak->Media->information->sampleTable->SampleSize->sampleCount = 0; } movie->NextMoofNumber = 0; +#endif } GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *is_rap, Bool *has_roll, s32 *roll_distance) diff --git a/src/isomedia/isom_write.c b/src/isomedia/isom_write.c index b898dc9..33b7160 100644 --- a/src/isomedia/isom_write.c +++ b/src/isomedia/isom_write.c @@ -1953,17 +1953,18 @@ GF_Err gf_isom_use_compact_size(GF_ISOFile *movie, u32 trackNumber, u8 Compactio GF_Err gf_isom_set_brand_info(GF_ISOFile *movie, u32 MajorBrand, u32 MinorVersion) { u32 i, *p; - GF_Err e; if (!MajorBrand) return GF_BAD_PARAM; +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) { - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); if (e) return e; e = CheckNoData(movie); if (e) return e; } +#endif if (!movie->brand) { movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP); @@ -1997,17 +1998,18 @@ GF_Err gf_isom_set_brand_info(GF_ISOFile *movie, u32 MajorBrand, u32 MinorVersio GF_Err gf_isom_modify_alternate_brand(GF_ISOFile *movie, u32 Brand, u8 AddIt) { u32 i, k, *p; - GF_Err e; if (!Brand) return GF_BAD_PARAM; +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) { - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); if (e) return e; e = CheckNoData(movie); if (e) return e; } +#endif if (!movie->brand && AddIt) { movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP); @@ -2065,15 +2067,16 @@ found: GF_Err gf_isom_reset_alt_brands(GF_ISOFile *movie) { u32 *p; - GF_Err e; +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) { - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); if (e) return e; e = CheckNoData(movie); if (e) return e; } +#endif if (!movie->brand) { movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP); diff --git a/src/isomedia/movie_fragments.c b/src/isomedia/movie_fragments.c index 38f87cd..187ff4e 100644 --- a/src/isomedia/movie_fragments.c +++ b/src/isomedia/movie_fragments.c @@ -39,9 +39,6 @@ GF_TrackExtendsBox *GetTrex(GF_MovieBox *moov, u32 TrackID) return NULL; } - -#ifndef GPAC_DISABLE_ISOM_WRITE - GF_TrackFragmentBox *GetTraf(GF_ISOFile *mov, u32 TrackID) { u32 i; @@ -56,6 +53,9 @@ GF_TrackFragmentBox *GetTraf(GF_ISOFile *mov, u32 TrackID) return NULL; } + +#ifndef GPAC_DISABLE_ISOM_WRITE + GF_Err gf_isom_finalize_for_fragment(GF_ISOFile *movie, Bool use_segments) { GF_Err e; diff --git a/src/media_tools/filestreamer.c b/src/media_tools/filestreamer.c index feaf651..0bc694f 100644 --- a/src/media_tools/filestreamer.c +++ b/src/media_tools/filestreamer.c @@ -22,18 +22,18 @@ * */ -#include -#include -#include -#include #include -#include -#include #include #include #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING) +#include +#include +#include +#include +#include +#include typedef struct __tag_rtp_track { diff --git a/src/media_tools/ismacryp.c b/src/media_tools/ismacryp.c index aec2100..acaa0dc 100644 --- a/src/media_tools/ismacryp.c +++ b/src/media_tools/ismacryp.c @@ -560,7 +560,9 @@ GF_Err gf_ismacryp_encrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void ( GF_IPMPPtr *ipmpdp; GF_IPMP_Descriptor *ipmpd; GF_IPMPUpdate *ipmpdU; +#ifndef GPAC_MINIMAL_ODF GF_IPMPX_ISMACryp *ismac; +#endif GF_Err e; Bool prev_sample_encryped, has_crypted_samp; @@ -775,6 +777,7 @@ GF_Err gf_ismacryp_encrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void ( /*format IPMPD*/ ipmpd = (GF_IPMP_Descriptor*)gf_odf_desc_new(GF_ODF_IPMP_TAG); if (tci->ipmp_type==2) { +#ifndef GPAC_MINIMAL_ODF ipmpd->IPMP_DescriptorID = 0xFF; ipmpd->IPMP_DescriptorIDEx = tci->ipmp_desc_id; ipmpd->IPMPS_Type = 0xFFFF; @@ -788,6 +791,7 @@ GF_Err gf_ismacryp_encrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void ( ismac->key_indicator_length = 0; ismac->use_selective_encryption = (tci->sel_enc_type!=0)? 1 : 0; gf_list_add(ipmpd->ipmpx_data, ismac); +#endif } else { ipmpd->IPMP_DescriptorID = tci->ipmp_desc_id; } diff --git a/src/media_tools/isom_tools.c b/src/media_tools/isom_tools.c index 9f3939b..3f336a1 100644 --- a/src/media_tools/isom_tools.c +++ b/src/media_tools/isom_tools.c @@ -51,11 +51,14 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCo } break; case GF_STREAM_VISUAL: +#ifndef GPAC_DISABLE_AV_PARSERS if (esd->decoderConfig->decoderSpecificInfo) { GF_M4VDecSpecInfo dsi; gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); sprintf(szCodec, "mp4v.%02x.%02x", esd->decoderConfig->objectTypeIndication, dsi.VideoPL); - } else { + } else +#endif + { sprintf(szCodec, "mp4v.%02x", esd->decoderConfig->objectTypeIndication); } break; @@ -697,6 +700,8 @@ static u64 get_next_sap_time(GF_ISOFile *input, u32 track, u32 sample_count, u32 } +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + GF_EXPORT GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, const char *mpd_name, Double max_duration_sec, u32 dash_mode, Double dash_duration_sec, char *seg_rad_name, char *seg_ext, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool use_url_template, Bool single_segment_mode, const char *dash_ctx_file, GF_ISOFile *sample_descs, u32 rep_idx) { @@ -709,7 +714,6 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, const GF_Err e; char sOpt[100], sKey[100]; char szCodecs[200], szCodec[100]; - char szComponents[1000]; u32 cur_seg, fragment_index, nb_fragments, max_sap_type; GF_ISOFile *output; GF_ISOSample *sample, *next; @@ -916,6 +920,7 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, const } +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS //the initialization segment is not yet setup for fragmentation if (! gf_isom_is_track_fragmented(sample_descs, tf->TrackID)) { e = gf_isom_setup_track_fragment(sample_descs, sample_descs_track, @@ -933,9 +938,8 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, const e = gf_isom_change_track_fragment_defaults(output, TrackNum, defaultDuration, defaultSize, defaultDescriptionIndex, defaultRandomAccess, defaultPadding, defaultDegradationPriority); if (e) goto err_exit; - - } +#endif /*reset all sample desc and clone with new ones*/ gf_isom_clone_sample_descriptions(output, TrackNum, sample_descs, sample_descs_track, 1); @@ -991,30 +995,6 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, const nb_samp += count; } - /*format component info*/ - szComponents[0] = 0; - for (i=0; iMediaType) { - case GF_ISOM_MEDIA_TEXT: - gf_isom_get_media_language(input, i+1, langCode); - sprintf(szComponent, " \n", tf->TrackID, langCode); - break; - case GF_ISOM_MEDIA_VISUAL: - sprintf(szComponent, " \n", tf->TrackID); - break; - case GF_ISOM_MEDIA_SCENE: - case GF_ISOM_MEDIA_DIMS: - sprintf(szComponent, " \n", tf->TrackID, langCode); - break; - case GF_ISOM_MEDIA_AUDIO: - sprintf(szComponent, " \n", tf->TrackID, langCode); - break; - } - strcat(szComponents, szComponent); - } - if (!tfref) tfref = gf_list_get(fragmenters, 0); tfref->is_ref_track = 1; tfref_timescale = tfref->TimeScale; @@ -1022,8 +1002,10 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, const if (tfref->all_sample_raps) split_seg_at_rap = 1; //flush movie +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS e = gf_isom_finalize_for_fragment(output, dash_mode ? 1 : 0); if (e) goto err_exit; +#endif start_range = 0; file_size = gf_isom_get_file_size(output); @@ -1485,7 +1467,6 @@ restart_fragmentation_pass: fprintf(mpd, " bandwidth=\"%d\"", bandwidth); fprintf(mpd, ">\n"); - if (strlen(szComponents)) fprintf(mpd, "%s", szComponents); if (dash_ctx) { Double seg_dur; @@ -1582,8 +1563,9 @@ err_exit: return e; } +#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ -GF_Err gf_media_mpd_start(char *mpd_name, char *title, Bool use_url_template, Bool single_segment, char *dash_ctx, char *init_segment, Double period_duration) +GF_Err gf_media_mpd_start(char *mpd_name, char *title, Bool use_url_template, Bool single_segment, char *dash_ctx, GF_ISOFile *init_segment, Double period_duration) { u32 h, m; Double s; @@ -1606,11 +1588,37 @@ GF_Err gf_media_mpd_start(char *mpd_name, char *title, Bool use_url_template, Bo fprintf(mpd, " \n"); if (init_segment) { + u32 i; + char langCode[4]; + langCode[3] = 0; + + for (i=0; i\n", trackID, langCode); + break; + case GF_ISOM_MEDIA_VISUAL: + fprintf(mpd, " \n", trackID); + break; + case GF_ISOM_MEDIA_SCENE: + case GF_ISOM_MEDIA_DIMS: + fprintf(mpd, " \n", trackID, langCode); + break; + case GF_ISOM_MEDIA_AUDIO: + fprintf(mpd, " \n", trackID, langCode); + break; + } + } + if (use_url_template) { - fprintf(mpd, " \n", init_segment); + fprintf(mpd, " \n", gf_isom_get_filename(init_segment) ); } else if (0 && !single_segment) { fprintf(mpd, " \n"); - fprintf(mpd, " \n", init_segment); + fprintf(mpd, " \n", gf_isom_get_filename(init_segment) ); fprintf(mpd, " \n"); } } diff --git a/src/media_tools/m2ts_mux.c b/src/media_tools/m2ts_mux.c index 2c82391..be9abf9 100644 --- a/src/media_tools/m2ts_mux.c +++ b/src/media_tools/m2ts_mux.c @@ -26,7 +26,7 @@ #include #include -#ifndef GPAC_DISABLE_MPEG2TS_MUX +#if !defined(GPAC_DISABLE_MPEG2TS_MUX) && !defined(GPAC_DISABLE_MPEG2TS) /*num ms between PCR*/ #define PCR_UPDATE_MS 200 diff --git a/src/media_tools/media_export.c b/src/media_tools/media_export.c index f1374a0..32255fb 100644 --- a/src/media_tools/media_export.c +++ b/src/media_tools/media_export.c @@ -1522,10 +1522,12 @@ GF_Err gf_media_export_avi(GF_MediaExporter *dumper) } /*MPEG4*/ else { +#ifndef GPAC_DISABLE_AV_PARSERS /*ignore visual size info, get it from dsi*/ gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); w = dsi.width; h = dsi.height; +#endif v4CC = "XVID"; diff --git a/src/media_tools/media_import.c b/src/media_tools/media_import.c index ca904df..f097a4a 100644 --- a/src/media_tools/media_import.c +++ b/src/media_tools/media_import.c @@ -6811,6 +6811,41 @@ GF_Err gf_media_import(GF_MediaImporter *importer) return gf_import_message(importer, e, "Unknown input file type"); } + +GF_EXPORT +GF_Err gf_media_change_pl(GF_ISOFile *file, u32 track, u32 profile, u32 level) +{ + u32 i, count, stype; + GF_Err e; + GF_AVCConfig *avcc; + + stype = gf_isom_get_media_subtype(file, track, 1); + switch (stype) { + case GF_ISOM_SUBTYPE_AVC_H264: + case GF_ISOM_SUBTYPE_AVC2_H264: + break; + default: + return GF_OK; + } + + avcc = gf_isom_avc_config_get(file, track, 1); + if (level) avcc->AVCLevelIndication = level; + if (profile) avcc->AVCProfileIndication = profile; + count = gf_list_count(avcc->sequenceParameterSets); + for (i=0; isequenceParameterSets, i); + if (profile) slc->data[1] = profile; + if (level) slc->data[3] = level; + } + e = gf_isom_avc_config_update(file, track, 1, avcc); + assert (e == GF_OK); + gf_odf_avc_cfg_del(avcc); + return GF_OK; +} + +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + + GF_EXPORT GF_Err gf_media_change_par(GF_ISOFile *file, u32 track, s32 ar_num, s32 ar_den) { @@ -6862,37 +6897,3 @@ GF_Err gf_media_change_par(GF_ISOFile *file, u32 track, s32 ar_num, s32 ar_den) } return gf_isom_set_track_layout_info(file, track, tk_w<<16, tk_h<<16, 0, 0, 0); } - - -GF_EXPORT -GF_Err gf_media_change_pl(GF_ISOFile *file, u32 track, u32 profile, u32 level) -{ - u32 i, count, stype; - GF_Err e; - GF_AVCConfig *avcc; - - stype = gf_isom_get_media_subtype(file, track, 1); - switch (stype) { - case GF_ISOM_SUBTYPE_AVC_H264: - case GF_ISOM_SUBTYPE_AVC2_H264: - break; - default: - return GF_OK; - } - - avcc = gf_isom_avc_config_get(file, track, 1); - if (level) avcc->AVCLevelIndication = level; - if (profile) avcc->AVCProfileIndication = profile; - count = gf_list_count(avcc->sequenceParameterSets); - for (i=0; isequenceParameterSets, i); - if (profile) slc->data[1] = profile; - if (level) slc->data[3] = level; - } - e = gf_isom_avc_config_update(file, track, 1, avcc); - assert (e == GF_OK); - gf_odf_avc_cfg_del(avcc); - return GF_OK; -} - -#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ diff --git a/src/media_tools/mpd.c b/src/media_tools/mpd.c index c9b36b0..feeed1c 100644 --- a/src/media_tools/mpd.c +++ b/src/media_tools/mpd.c @@ -1241,8 +1241,8 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, pe->codecs[len-2] = 0; } -#ifndef GPAC_DISABLE_MEDIA_IMPORT width = height = samplerate = num_channels = 0; +#ifndef GPAC_DISABLE_MEDIA_IMPORT if (do_import) { GF_Err e; GF_MediaImporter import; diff --git a/src/media_tools/text_import.c b/src/media_tools/text_import.c index 3d4801f..4abc7e8 100644 --- a/src/media_tools/text_import.c +++ b/src/media_tools/text_import.c @@ -152,6 +152,7 @@ static void gf_text_get_video_size(GF_ISOFile *dest, u32 *width, u32 *height) } +#ifndef GPAC_DISABLE_MEDIA_IMPORT static void gf_text_import_set_language(GF_MediaImporter *import, u32 track) { if (import->esd && import->esd->langDesc) { @@ -163,7 +164,7 @@ static void gf_text_import_set_language(GF_MediaImporter *import, u32 track) gf_isom_set_media_language(import->dest, track, lang); } } - +#endif static char *gf_text_get_utf8_line(char *szLine, u32 lineSize, FILE *txt_in, s32 unicode_type) { @@ -237,6 +238,9 @@ static char *gf_text_get_utf8_line(char *szLine, u32 lineSize, FILE *txt_in, s32 return sOK; } + +#ifndef GPAC_DISABLE_MEDIA_IMPORT + static GF_Err gf_text_import_srt(GF_MediaImporter *import) { FILE *srt_in; @@ -1702,5 +1706,7 @@ GF_Err gf_import_timed_text(GF_MediaImporter *import) } } +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + #endif /*GPAC_DISABLE_ISOM_WRITE*/ diff --git a/src/odf/ipmpx_dump.c b/src/odf/ipmpx_dump.c index 6fbf895..3c708fd 100644 --- a/src/odf/ipmpx_dump.c +++ b/src/odf/ipmpx_dump.c @@ -24,7 +24,7 @@ #include -#ifndef GPAC_DISABLE_OD_DUMP +#if !defined(GPAC_DISABLE_OD_DUMP) && !defined(GPAC_MINIMAL_ODF) #define GF_IPMPX_MAX_TREE 100 diff --git a/src/odf/odf_dump.c b/src/odf/odf_dump.c index 37bdda9..12057c6 100644 --- a/src/odf/odf_dump.c +++ b/src/odf/odf_dump.c @@ -1209,6 +1209,7 @@ GF_Err gf_odf_dump_ipmp(GF_IPMP_Descriptor *ipmp, FILE *trace, u32 indent, Bool DumpInt(trace, "controlPointCode", ipmp->control_point, indent, XMTDump); if (ipmp->control_point) DumpInt(trace, "sequenceCode", ipmp->cp_sequence_code, indent, XMTDump); EndAttributes(trace, indent, XMTDump); +#ifndef GPAC_MINIMAL_ODF /*parse IPMPX data*/ StartElement(trace, "IPMPX_Data", indent, XMTDump, 1); indent++; @@ -1219,6 +1220,7 @@ GF_Err gf_odf_dump_ipmp(GF_IPMP_Descriptor *ipmp, FILE *trace, u32 indent, Bool } indent--; EndElement(trace, "IPMPX_Data", indent, XMTDump, 1); +#endif } else if (!ipmp->IPMPS_Type) { DumpString(trace, "URLString", ipmp->opaque_data, indent, XMTDump); @@ -1736,7 +1738,9 @@ GF_Err gf_odf_dump_ipmp_tool(GF_IPMP_Tool*t, FILE *trace, u32 indent, Bool XMTDu if (t->tool_url) DumpString(trace, "ToolURL", t->tool_url, indent, XMTDump); if (t->toolParamDesc) { StartElement(trace, "toolParamDesc" , indent, XMTDump, 0); +#ifndef GPAC_MINIMAL_ODF gf_ipmpx_dump_data((GF_IPMPX_Data *)t->toolParamDesc, trace, indent + (XMTDump ? 1 : 0), XMTDump); +#endif EndElement(trace, "toolParamDesc" , indent, XMTDump, 0); } EndAttributes(trace, indent, XMTDump); @@ -1887,6 +1891,8 @@ GF_Err gf_odf_dump_base_command(GF_BaseODCom *com, FILE *trace, u32 indent, Bool } +#ifndef GPAC_MINIMAL_ODF + GF_EXPORT GF_Err gf_oci_dump_event(OCIEvent *ev, FILE *trace, u32 indent, Bool XMTDump) { @@ -1944,4 +1950,6 @@ GF_Err gf_oci_dump_au(u8 version, char *au, u32 au_length, FILE *trace, u32 inde return e; } +#endif /*GPAC_MINIMAL_ODF*/ + #endif /*GPAC_DISABLE_OD_DUMP*/ diff --git a/src/odf/odf_parse.c b/src/odf/odf_parse.c index 2050b0d..ab93f3e 100644 --- a/src/odf/odf_parse.c +++ b/src/odf/odf_parse.c @@ -30,8 +30,6 @@ #include -#if !defined(GPAC_DISABLE_LOADER_BT) && !defined(GPAC_DISABLE_LOADER_XMT) - /* to complete...*/ u32 gf_odf_get_field_type(GF_Descriptor *desc, char *fieldName) @@ -695,4 +693,3 @@ Bool OD_ParseUIConfig(char *val, char **out_data, u32 *out_data_size) return 0; } -#endif /* defined(GPAC_DISABLE_LOADER_BT) || defined(GPAC_DISABLE_LOADER_XMT)*/ diff --git a/src/scene_manager/encode_isom.c b/src/scene_manager/encode_isom.c index 306eba2..5a04550 100644 --- a/src/scene_manager/encode_isom.c +++ b/src/scene_manager/encode_isom.c @@ -52,7 +52,7 @@ static void gf_sm_remove_mux_info(GF_ESD *src) static void gf_sm_finalize_mux(GF_ISOFile *mp4, GF_ESD *src, u32 offset_ts) { -#if !defined (GPAC_DISABLE_ISOM) || !defined(GPAC_DISABLE_ISOM_WRITE) +#if !defined (GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE) u32 track, mts, ts; GF_MuxInfo *mux = gf_sm_get_mux_info(src); if (!mux && !offset_ts) return; @@ -100,15 +100,21 @@ static GF_Err gf_sm_import_ui_stream(GF_ISOFile *mp4, GF_ESD *src, Bool rewrite_ } if (rewrite_esd_only) return GF_OK; +#ifndef GPAC_DISABLE_ISOM_WRITE /*what's the media type for input sensor ??*/ len = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_SCENE, 1000); if (!len) return gf_isom_last_error(mp4); gf_isom_set_track_enabled(mp4, len, 1); if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, len); return gf_isom_new_mpeg4_description(mp4, len, src, NULL, NULL, &i); +#else + return GF_NOT_SUPPORTED; +#endif } +#ifndef GPAC_DISABLE_MEDIA_IMPORT + static GF_Err gf_sm_import_stream(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_ESD *src, Double imp_time, char *mediaSource, Bool od_sample_rap) { u32 track, di, i; @@ -342,6 +348,9 @@ static GF_Err gf_sm_import_specials(GF_SceneManager *ctx) return GF_OK; } + +#endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + /*locate stream in all OD updates/ESD updates (needed for systems tracks)*/ static GF_ESD *gf_sm_locate_esd(GF_SceneManager *ctx, u16 ES_ID) { @@ -390,6 +399,9 @@ static GF_ESD *gf_sm_locate_esd(GF_SceneManager *ctx, u16 ES_ID) return NULL; } + +#ifndef GPAC_DISABLE_ISOM_WRITE + static GF_Err gf_sm_encode_scene(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, u32 scene_type) { char *data; @@ -559,7 +571,11 @@ static GF_Err gf_sm_encode_scene(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEnc if (!au && !esd->URLString) { /*if not in IOD, the stream will be imported when encoding the OD stream*/ if (!is_in_iod) continue; +#ifndef GPAC_DISABLE_MEDIA_IMPORT e = gf_sm_import_stream(ctx, mp4, esd, 0, NULL, 0); +#else + e = GF_BAD_PARAM; +#endif if (e) goto exit; gf_sm_finalize_mux(mp4, esd, 0); gf_isom_add_track_to_root_od(mp4, gf_isom_get_track_by_id(mp4, esd->ESID)); @@ -1049,7 +1065,11 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media switch (imp_esd->tag) { case GF_ODF_ESD_TAG: +#ifndef GPAC_DISABLE_MEDIA_IMPORT e = gf_sm_import_stream(ctx, mp4, imp_esd, au->timing_sec, mediaSource, au->flags & GF_SM_AU_RAP); +#else + e = GF_BAD_PARAM; +#endif if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] cannot import stream %d (error %s)\n", imp_esd->ESID, gf_error_to_string(e))); goto err_exit; @@ -1077,7 +1097,11 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) { switch (imp_esd->tag) { case GF_ODF_ESD_TAG: +#ifndef GPAC_DISABLE_MEDIA_IMPORT e = gf_sm_import_stream(ctx, mp4, imp_esd, au->timing_sec, mediaSource, au->flags & GF_SM_AU_RAP); +#else + e = GF_BAD_PARAM; +#endif if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] cannot import stream %d (error %s)\n", imp_esd->ESID, gf_error_to_string(e))); gf_odf_com_del(&com); @@ -1261,7 +1285,11 @@ GF_Err gf_sm_encode_to_file(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOp gf_isom_modify_alternate_brand(mp4, GF_ISOM_BRAND_MP41, 1); /*import specials, that is input remapping to BIFS*/ +#ifndef GPAC_DISABLE_MEDIA_IMPORT e = gf_sm_import_specials(ctx); +#else + e = GF_BAD_PARAM; +#endif if (e) return e; @@ -1313,4 +1341,6 @@ GF_Err gf_sm_encode_to_file(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOp return GF_OK; } +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + #endif /*GPAC_DISABLE_SCENE_ENCODER*/ diff --git a/src/scene_manager/loader_isom.c b/src/scene_manager/loader_isom.c index 1d0c77c..20eee00 100644 --- a/src/scene_manager/loader_isom.c +++ b/src/scene_manager/loader_isom.c @@ -31,7 +31,7 @@ -#ifndef GPAC_DISABLE_LOADER_ISOM +#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_LOADER_ISOM) static void UpdateODCommand(GF_ISOFile *mp4, GF_ODCom *com) { @@ -406,4 +406,4 @@ GF_Err gf_sm_load_init_isom(GF_SceneLoader *load) return GF_OK; } -#endif /*GPAC_DISABLE_LOADER_ISOM*/ +#endif /*GPAC_DISABLE_ISOM && GPAC_DISABLE_LOADER_ISOM*/ diff --git a/src/scene_manager/scene_dump.c b/src/scene_manager/scene_dump.c index 4f69376..b60a27a 100644 --- a/src/scene_manager/scene_dump.c +++ b/src/scene_manager/scene_dump.c @@ -808,9 +808,11 @@ static void gf_dump_vrml_field(GF_SceneDumper *sdump, GF_Node *node, GF_FieldInf case GF_SG_VRML_MFNODE: needs_field_container = 0; if (sdump->XMLDump && sdump->X3DDump) needs_field_container = gf_dump_vrml_needs_container(node, &field); +#ifndef GPAC_DISABLE_X3D if (!sdump->X3DDump) { if (gf_node_get_tag(node)==TAG_X3D_Switch) field.name = "choice"; } +#endif list = * ((GF_ChildNodeItem **) field.far_ptr); assert(list); if (!sdump->XMLDump || !sdump->X3DDump) StartList(sdump, field.name); @@ -1273,12 +1275,16 @@ static Bool scene_dump_vrml_can_dump(GF_SceneDumper *sdump, GF_Node *node) name = gf_node_get_class_name(node); #ifndef GPAC_DISABLE_X3D tag = gf_node_x3d_type_by_class_name(name); -#endif return tag ? 1 : 0; +#else + return 0; +#endif } else { if (node->sgprivate->tag<=GF_NODE_RANGE_LAST_MPEG4) return 1; +#ifndef GPAC_DISABLE_X3D if (node->sgprivate->tag==TAG_X3D_Rectangle2D) return 1; if (node->sgprivate->tag==TAG_X3D_Circle2D) return 1; +#endif name = gf_node_get_class_name(node); tag = gf_node_mpeg4_type_by_class_name(name); return tag ? 1 : 0; @@ -1317,9 +1323,11 @@ static void gf_dump_vrml_node(GF_SceneDumper *sdump, GF_Node *node, Bool in_list if (sdump->X3DDump) { if (node->sgprivate->tag == TAG_MPEG4_Circle) name = "Circle2D"; else if (node->sgprivate->tag == TAG_MPEG4_Rectangle) name = "Rectangle2D"; +#ifndef GPAC_DISABLE_X3D } else if (!sdump->X3DDump) { if (node->sgprivate->tag == TAG_X3D_Circle2D) name = "Circle"; else if (node->sgprivate->tag == TAG_X3D_Rectangle2D) name = "Rectangle"; +#endif } #endif @@ -1361,7 +1369,9 @@ static void gf_dump_vrml_node(GF_SceneDumper *sdump, GF_Node *node, Bool in_list base = NULL; switch (gf_node_get_tag(node)) { #ifndef GPAC_DISABLE_VRML +#ifndef GPAC_DISABLE_X3D case TAG_X3D_Script: +#endif case TAG_MPEG4_Script: isScript = 1; break; @@ -1586,10 +1596,13 @@ static void gf_dump_vrml_node(GF_SceneDumper *sdump, GF_Node *node, Bool in_list gf_dump_vrml_field(sdump, node, field); } } else { +#ifndef GPAC_DISABLE_X3D /*X3D script metadata, NOT DYN*/ if ((i==3) && (node->sgprivate->tag==TAG_X3D_Script) ) { if (*((GF_Node **)field.far_ptr)) gf_dump_vrml_field(sdump, node, field); - } else { + } else +#endif + { gf_dump_vrml_dyn_field(sdump, node, field, 0); } } diff --git a/src/scene_manager/scene_engine.c b/src/scene_manager/scene_engine.c index 3147182..0221033 100644 --- a/src/scene_manager/scene_engine.c +++ b/src/scene_manager/scene_engine.c @@ -288,8 +288,10 @@ GF_Err gf_seng_enable_aggregation(GF_SceneEngine *seng, u16 ESID, u16 onESID) static GF_Err gf_seng_encode_dims_au(GF_SceneEngine *seng, u16 ESID, GF_List *commands, char **data, u32 *size) { - GF_Err e; +#ifndef GPAC_DISABLE_SCENE_DUMP GF_SceneDumper *dumper = NULL; +#endif + GF_Err e; char rad_name[4096]; char file_name[4096]; FILE *file = NULL; @@ -335,16 +337,18 @@ start: #endif } +#ifndef GPAC_DISABLE_SCENE_DUMP dumper = gf_sm_dumper_new(seng->ctx->scene_graph, rad_name, ' ', GF_SM_DUMP_SVG); if (!dumper) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot create SVG dumper for %s.svg\n", rad_name)); e = GF_IO_ERR; goto exit; - } + } if (commands && gf_list_count(commands)) { e = gf_sm_dump_command_list(dumper, commands, 0, 0); - } else { + } + else { e = gf_sm_dump_graph(dumper, 0, 0); } gf_sm_dumper_del(dumper); @@ -368,6 +372,8 @@ start: GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot dump DIMS Commands\n")); goto exit; } +#endif + #ifdef DUMP_DIMS_LOG_WITH_TIME if (do_dump_with_time) { do_dump_with_time = 0; @@ -546,7 +552,7 @@ static GF_Err gf_sm_live_encode_scene_au(GF_SceneEngine *seng, gf_seng_callback break; #endif -#ifndef GPAC_DISABLE_BIFS_ENC +#ifndef GPAC_DISABLE_LASER case GPAC_OTI_SCENE_LASER: e = gf_laser_encode_au(seng->lsrenc, sc->ESID, au->commands, 0, &data, &size); break; @@ -584,6 +590,9 @@ GF_Err gf_seng_dump_rap_on(GF_SceneEngine *seng, Bool dump_rap) GF_EXPORT GF_Err gf_seng_save_context(GF_SceneEngine *seng, char *ctxFileName) { +#ifdef GPAC_DISABLE_SCENE_DUMP + return GF_NOT_SUPPORTED; +#else u32 d_mode, do_enc; char szF[GF_MAX_PATH], *ext; GF_Err e; @@ -617,6 +626,7 @@ GF_Err gf_seng_save_context(GF_SceneEngine *seng, char *ctxFileName) e = gf_sm_dump(seng->ctx, ctxFileName ? szF : NULL, d_mode); } return e; +#endif } static GF_AUContext *gf_seng_create_new_au(GF_StreamContext *sc, u32 time) @@ -723,7 +733,7 @@ GF_Err gf_seng_encode_from_commands(GF_SceneEngine *seng, u16 ESID, Bool disable break; #endif -#ifndef GPAC_DISABLE_BIFS_ENC +#ifndef GPAC_DISABLE_LASER case GPAC_OTI_SCENE_LASER: e = gf_laser_encode_au(seng->lsrenc, ESID, new_au->commands, 0, &data, &size); break; @@ -806,7 +816,7 @@ void gf_seng_terminate(GF_SceneEngine *seng) if (seng->bifsenc) gf_bifs_encoder_del(seng->bifsenc); #endif -#ifndef GPAC_DISABLE_BIFS_ENC +#ifndef GPAC_DISABLE_LASER if (seng->lsrenc) gf_laser_encoder_del(seng->lsrenc); #endif diff --git a/src/scenegraph/dom_smjs.c b/src/scenegraph/dom_smjs.c index b0ee905..8b4ec65 100644 --- a/src/scenegraph/dom_smjs.c +++ b/src/scenegraph/dom_smjs.c @@ -182,7 +182,7 @@ static void define_dom_exception(JSContext *c, JSObject *global) DEF_EXC(TYPE_MISMATCH_ERR); #undef DEF_EXC - JS_AliasProperty(c, global, "DOMException", "e"); + //JS_AliasProperty(c, global, "DOMException", "e"); obj = JS_DefineObject(c, global, "EventException", NULL, 0, 0); JS_DefineProperty(c, obj, "UNSPECIFIED_EVENT_TYPE_ERR", INT_TO_JSVAL(0), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineProperty(c, obj, "DISPATCH_REQUEST_ERR", INT_TO_JSVAL(1), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); @@ -523,7 +523,7 @@ JSBool SMJS_FUNCTION_EXT(gf_sg_js_event_add_listener, GF_Node *on_node) GF_SceneGraph *sg = NULL; JSFunction*fun = NULL; GF_Node *n = NULL; - jsval funval = 0; + jsval funval = JSVAL_NULL; JSObject *evt_handler; SMJS_OBJ SMJS_ARGS @@ -597,7 +597,7 @@ JSBool SMJS_FUNCTION_EXT(gf_sg_js_event_add_listener, GF_Node *on_node) if (!callback) { handler->js_fun = fun; - handler->js_fun_val = funval; + handler->js_fun_val = *(u64 *) &funval; if (handler->js_fun_val) { handler->js_context = c; /*protect the function - we don't know how it was passed to us, so prevent it from being GCed*/ @@ -665,7 +665,7 @@ JSBool SMJS_FUNCTION_EXT(gf_sg_js_event_remove_listener, GF_Node *vrml_node) u32 evtType, i, count; char *inNS = NULL; GF_Node *node = NULL; - jsval funval = 0; + jsval funval = JSVAL_NULL; GF_SceneGraph *sg = NULL; GF_DOMEventTarget *target = NULL; SMJS_OBJ @@ -712,7 +712,7 @@ JSBool SMJS_FUNCTION_EXT(gf_sg_js_event_remove_listener, GF_Node *vrml_node) funval = argv[of+1]; } } - if (!callback && !funval) goto err_exit; + if (!callback && JSVAL_IS_NULL(funval) ) goto err_exit; evtType = gf_dom_event_type_by_name(type); if (evtType==GF_EVENT_UNKNOWN) goto err_exit; @@ -732,8 +732,8 @@ JSBool SMJS_FUNCTION_EXT(gf_sg_js_event_remove_listener, GF_Node *vrml_node) if (!info.far_ptr) continue; hdl = (SVG_handlerElement *) ((XMLRI*)info.far_ptr)->target; if (!hdl) continue; - if (funval) { - if (funval != (jsval) hdl->js_fun_val) continue; + if (! JSVAL_IS_NULL(funval) ) { + if (*(u64 *) &funval != hdl->js_fun_val) continue; } else if (hdl->children) { txt = (GF_DOMText *) hdl->children->node; if (txt->sgprivate->tag != TAG_DOMText) continue; @@ -3915,7 +3915,7 @@ void dom_js_define_document(JSContext *c, JSObject *global, GF_SceneGraph *doc) JSObject *dom_js_define_event(JSContext *c, JSObject *global) { JSObject *obj = JS_DefineObject(c, global, "evt", &dom_rt->domEventClass, 0, 0 ); - JS_AliasProperty(c, global, "evt", "event"); + //JS_AliasProperty(c, global, "evt", "event"); return obj; } diff --git a/src/scenegraph/vrml_smjs.c b/src/scenegraph/vrml_smjs.c index ee4a0e1..e7961c3 100644 --- a/src/scenegraph/vrml_smjs.c +++ b/src/scenegraph/vrml_smjs.c @@ -185,7 +185,6 @@ typedef struct JSContext *ctx; GF_Mutex *mx; - JSClass SFNodeClass; #ifndef GPAC_DISABLE_VRML @@ -287,6 +286,16 @@ static void gf_sg_unload_script_modules() } +#ifdef NO_JS_RUNTIMETHREAD +void JS_SetRuntimeThread(JSRuntime *jsr) +{ +} +void JS_ClearRuntimeThread(JSRuntime *jsr) +{ +} +#endif + + #ifdef __SYMBIAN32__ const long MAX_HEAP_BYTES = 256 * 1024L; #else @@ -311,14 +320,25 @@ JSContext *gf_sg_ecmascript_new(GF_SceneGraph *sg) } js_rt->nb_inst++; ctx = JS_NewContext(js_rt->js_runtime, STACK_CHUNK_BYTES); + JS_SetOptions(ctx, JS_GetOptions(ctx) | JSOPTION_WERROR); + +#ifdef JS_THREADSAFE +#if (JS_VERSION>=185) + JS_ClearContextThread(ctx); + JS_ClearRuntimeThread(js_rt->js_runtime); +#endif +#endif return ctx; } void gf_sg_ecmascript_del(JSContext *ctx) { #ifdef JS_THREADSAFE - JS_ClearContextThread(ctx); +#if (JS_VERSION>=185) + assert(js_rt); + JS_SetRuntimeThread(js_rt->js_runtime); JS_SetContextThread(ctx); +#endif #endif JS_DestroyContext(ctx); @@ -700,9 +720,9 @@ static void on_route_to_object(GF_Node *node, GF_Route *_r) // gf_js_remove_root(priv->js_ctx, &r->obj); r->obj=NULL; } - if (r->fun) { + if ( ! JSVAL_IS_VOID(r->fun)) { // gf_js_remove_root(priv->js_ctx, &r->fun); - r->fun=0; + r->fun=JSVAL_NULL; } return; } @@ -865,7 +885,7 @@ static JSBool SMJS_FUNCTION(deleteRoute) if (!JSVAL_IS_OBJECT(argv[0]) || !JS_InstanceOf(c, JSVAL_TO_OBJECT(argv[0]), &js_rt->SFNodeClass, NULL) ) return JS_FALSE; - if (JSVAL_IS_STRING(argv[1]) && (argv[2]==JSVAL_NULL) && (argv[3]==JSVAL_NULL)) { + if (JSVAL_IS_STRING(argv[1]) && JSVAL_IS_NULL(argv[2]) && JSVAL_IS_NULL(argv[3])) { ptr = (GF_JSField *) JS_GetPrivate(c, JSVAL_TO_OBJECT(argv[0])); assert(ptr->field.fieldType==GF_SG_VRML_SFNODE); n1 = * ((GF_Node **)ptr->field.far_ptr); @@ -1143,7 +1163,11 @@ JSBool gf_sg_script_eventout_set_prop(JSContext *c, JSObject *obj, SMJS_PROP_SET GF_Node *n; GF_ScriptField *sf; GF_FieldInfo info; - JSString *str = JS_ValueToString(c, id); + jsval idval; + JSString *str; + JS_IdToValue(c, id, &idval); + if (! SMJS_ID_IS_STRING(id)) return JS_FALSE; + str = SMJS_ID_TO_STRING(id); if (!str) return JS_FALSE; script = JS_GetScriptStack(c); @@ -3752,6 +3776,7 @@ static void gf_sg_script_update_cached_object(GF_ScriptPriv *priv, JSObject *obj if(parent) gf_node_get_field(parent, field->fieldIndex, &jsf->field); \ #define SETUP_MF_FIELD \ + if (!obj) return JSVAL_NULL; \ jsf = (GF_JSField *) JS_GetPrivate(priv->js_ctx, obj); \ jsf->owner = parent; \ if (parent) gf_node_get_field(parent, field->fieldIndex, &jsf->field); \ @@ -4761,25 +4786,36 @@ Bool gf_sg_javascript_initialized() #ifdef GPAC_HAS_SPIDERMONKEY +/* + * locking/try-locking the JS context + * we need to test whether the calling thread already has the lock on the script context + * if this is not the case (i.e. first lock on mutex), we switch JS context threads and + * call begin/end requests. Nesting begin/end request in a reentrant way crashes JS + * (mozilla doc is wrong here) + * + * */ void gf_sg_lock_javascript(struct JSContext *cx, Bool LockIt) { if (!js_rt) return; + assert(cx); if (LockIt) { gf_mx_p(js_rt->mx); #ifdef JS_THREADSAFE - if (cx) { + if (gf_mx_get_num_locks(js_rt->mx)==1) { #if (JS_VERSION>=185) - JS_SetContextThread(cx); + JS_SetRuntimeThread(js_rt->js_runtime); + JS_SetContextThread(cx); #endif JS_BeginRequest(cx); } #endif } else { #ifdef JS_THREADSAFE - if (cx) { + if (gf_mx_get_num_locks(js_rt->mx)==1) { JS_EndRequest(cx); #if (JS_VERSION>=185) - JS_ClearContextThread(cx); + JS_ClearContextThread(cx); + JS_ClearRuntimeThread(js_rt->js_runtime); #endif } #endif @@ -4789,11 +4825,13 @@ void gf_sg_lock_javascript(struct JSContext *cx, Bool LockIt) Bool gf_sg_try_lock_javascript(struct JSContext *cx) { + assert(cx); if (gf_mx_try_lock(js_rt->mx)) { #ifdef JS_THREADSAFE - if (cx) { + if (gf_mx_get_num_locks(js_rt->mx)==1) { #if (JS_VERSION>=185) - JS_SetContextThread(cx); + JS_SetRuntimeThread(js_rt->js_runtime); + JS_SetContextThread(cx); #endif JS_BeginRequest(cx); } diff --git a/src/utils/color.c b/src/utils/color.c index 3504752..4487c76 100644 --- a/src/utils/color.c +++ b/src/utils/color.c @@ -854,6 +854,7 @@ GF_Err gf_stretch_bits(GF_VideoSurface *dst, GF_VideoSurface *src, GF_Window *ds s32 src_row; u32 i, yuv_planar_type = 0; Bool no_memcpy; + Bool force_load_odd_yuv_lines = 0; Bool yuv_init = 0; Bool has_alpha = (alpha!=0xFF) ? 1 : 0; u32 dst_bpp, dst_w_size; @@ -988,6 +989,8 @@ GF_Err gf_stretch_bits(GF_VideoSurface *dst, GF_VideoSurface *src, GF_Window *ds tmp = (u8 *) gf_malloc(sizeof(u8) * src_w * (yuv_planar_type ? 8 : 4) ); rows = tmp; + if ( (src_h / dst_h) * dst_h != src_h) force_load_odd_yuv_lines = 1; + dst_bits = (u8 *) dst->video_buffer; pos_y = 0x10000; @@ -1031,8 +1034,8 @@ GF_Err gf_stretch_bits(GF_VideoSurface *dst, GF_VideoSurface *src, GF_Window *ds if (prev_row != src_row) { u32 the_row = src_row - 1; if (yuv_planar_type) { - if ( the_row % 2) { - if (!yuv_init) { + if (the_row % 2) { + if (!yuv_init || force_load_odd_yuv_lines) { yuv_init = 1; the_row --; if (flip) the_row = src->height-2 - the_row; @@ -1091,12 +1094,18 @@ GF_Err gf_stretch_bits(GF_VideoSurface *dst, GF_VideoSurface *src, GF_Window *ds if (key) { for (i=0; i 3*0xFE) tmp[idx+3] = ka; -// if ( (tmp[idx]==kr) && (tmp[idx+1]==kg) && (tmp[idx+2]==kb)) tmp[idx+3] = ka; + s32 thres, v; + v = tmp[idx]-kr; thres = ABS(v); + v = tmp[idx+1]-kg; thres += ABS(v); + v = tmp[idx+2]-kb; thres += ABS(v); + thres/=3; +#if 0 + if (thres < kl) tmp[idx+3] = 0; + else if (thres <= kh) tmp[idx+3] = (thres-kl)*ka / (kh-kl); +#else + if (thres < kh) tmp[idx+3] = 0; +#endif + else tmp[idx+3] = ka; } } }