static char *storage_get_section(M_Storage *storage) { GF_Scene *scene; char *szPath; u8 hash[20], name[50]; u32 i, len; scene = (GF_Scene *)gf_node_get_private((GF_Node*)storage); len = strlen(scene->root_od->net_service->url)+strlen(storage->name.buffer)+2; szPath = gf_malloc(sizeof(char)* len); strcpy(szPath, scene->root_od->net_service->url); strcat(szPath, "@"); strcat(szPath, storage->name.buffer); gf_sha1_csum(szPath, strlen(szPath), hash); gf_free(szPath); strcpy(name, "@cache="); for (i=0; i<20; i++) { char t[3]; t[2] = 0; sprintf(t, "%02X", hash[i]); strcat(name, t); } return gf_strdup(name); }
DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char * cache_directory, const char * url , u64 start_range, u64 end_range, Bool mem_storage) { char tmp[_CACHE_TMP_SIZE]; u8 hash[_CACHE_HASH_SIZE]; int sz; char ext[_CACHE_MAX_EXTENSION_SIZE]; DownloadedCacheEntry entry = NULL; if ( !dm || !url || !cache_directory) { GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry :%d, dm=%p, url=%s cache_directory=%s, aborting.\n", __LINE__, dm, url, cache_directory)); return entry; } sz = (u32) strlen ( url ); if ( sz > _CACHE_TMP_SIZE ) { GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d : ERROR, URL is too long (%d chars), more than %d chars.\n", __LINE__, sz, _CACHE_TMP_SIZE )); return entry; } tmp[0] = '\0'; /*generate hash of the full url*/ if (start_range && end_range) { sprintf(tmp, "%s_"LLD"-"LLD, url, start_range, end_range ); } else { strcpy ( tmp, url ); } gf_sha1_csum ((u8*) tmp, (u32) strlen ( tmp ), hash ); tmp[0] = 0; { int i; for ( i=0; i<20; i++ ) { char t[3]; t[2] = 0; sprintf ( t, "%02X", hash[i] ); strcat ( tmp, t ); } } assert ( strlen ( tmp ) == (_CACHE_HASH_SIZE * 2) ); GF_SAFEALLOC(entry, struct __DownloadedCacheEntryStruct); if ( !entry ) { GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("gf_cache_create_entry:%d : OUT of memory !\n", __LINE__)); return NULL; } GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, entry=%p\n", __LINE__, entry)); entry->url = gf_strdup ( url ); entry->hash = gf_strdup ( tmp ); entry->memory_stored = mem_storage; entry->cacheSize = 0; entry->contentLength = 0; entry->serverETag = NULL; entry->diskETag = NULL; entry->flags = NO_VALIDATION; entry->validity = 0; entry->diskLastModified = NULL; entry->serverLastModified = NULL; entry->dm = dm; entry->range_start = start_range; entry->range_end = end_range; #ifdef ENABLE_WRITE_MX { char name[1024]; snprintf(name, sizeof(name), "CachedEntryWriteMx=%p, url=%s", (void*) entry, url); entry->write_mutex = gf_mx_new(name); assert(entry->write_mutex); } #endif entry->deletableFilesOnDelete = 0; entry->write_session = NULL; entry->sessions = gf_list_new(); if (entry->memory_stored) { entry->cache_filename = gf_malloc ( strlen ("gmem://") + 8 + strlen("@") + 16 + 1); } else { /* Sizeof cache directory + hash + possible extension */ entry->cache_filename = gf_malloc ( strlen ( cache_directory ) + strlen(cache_file_prefix) + strlen(tmp) + _CACHE_MAX_EXTENSION_SIZE + 1); } if ( !entry->hash || !entry->url || !entry->cache_filename || !entry->sessions) { GF_Err err; /* Probably out of memory */ GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, aborting due to OUT of MEMORY !\n", __LINE__)); err = gf_cache_delete_entry ( entry ); assert ( err == GF_OK ); return NULL; } if (entry->memory_stored) { sprintf(entry->cache_filename, "gmem://%d@%p", entry->contentLength, entry->mem_storage); return entry; } tmp[0] = '\0'; strcpy ( entry->cache_filename, cache_directory ); strcat( entry->cache_filename, cache_file_prefix ); strcat ( entry->cache_filename, entry->hash ); strcpy ( tmp, url ); { char * parser; parser = strrchr ( tmp, '?' ); if ( parser ) parser[0] = '\0'; parser = strrchr ( tmp, '#' ); if ( parser ) parser[0] = '\0'; parser = strrchr ( tmp, '.' ); if ( parser && ( strlen ( parser ) < _CACHE_MAX_EXTENSION_SIZE ) ) strncpy(ext, parser, _CACHE_MAX_EXTENSION_SIZE); else strncpy(ext, default_cache_file_suffix, _CACHE_MAX_EXTENSION_SIZE); assert (strlen(ext)); strcat( entry->cache_filename, ext); } tmp[0] = '\0'; strcpy( tmp, cache_file_prefix); strcat( tmp, entry->hash ); strcat( tmp , ext); strcat ( tmp, cache_file_info_suffix ); entry->properties = gf_cfg_force_new ( cache_directory, tmp ); if ( !entry->properties ) { GF_Err err; /* OUT of memory ? */ GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, aborting due to OUT of MEMORY !\n", __LINE__)); err = gf_cache_delete_entry ( entry ); assert ( err == GF_OK ); return NULL; } gf_cache_set_etag_on_disk(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_ETAG)); gf_cache_set_etag_on_server(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_ETAG)); gf_cache_set_mime_type(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_MIME_TYPE)); gf_cache_set_last_modified_on_disk(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_LAST_MODIFIED)); gf_cache_set_last_modified_on_server(entry, gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_LAST_MODIFIED)); { const char * keyValue = gf_cfg_get_key ( entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_URL ); if ( keyValue == NULL || stricmp ( url, keyValue ) ) entry->flags |= CORRUPTED; keyValue = gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_RANGE); if (keyValue) { u64 s, e; sscanf(keyValue, LLD"-"LLD, &s, &e); /*mark as corrupted if not same range (we don't support this for the time being ...*/ if ((s!=entry->range_start) || (e!=entry->range_end)) entry->flags |= CORRUPTED; } } gf_cache_check_if_cache_file_is_corrupted(entry); return entry; }
static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) { GF_CMUnit *CU; GF_DBUnit *AU; GF_Channel *ch, *prev_ch; u32 mmlevel, cts; u32 first, entryTime, now, obj_time, unit_size; GF_MediaDecoder *mdec = (GF_MediaDecoder*)codec->decio; GF_Err e = GF_OK; CU = NULL; /*if video codec muted don't decode (try to saves ressources) if audio codec muted we dispatch to keep sync in place*/ if (codec->Muted && (codec->type==GF_STREAM_VISUAL) ) return GF_OK; entryTime = gf_term_get_time(codec->odm->term); /*fetch next AU in DTS order for this codec*/ Decoder_GetNextAU(codec, &ch, &AU); /*no active channel return*/ if (!AU || !ch) { /*if the codec is in EOS state, assume we're done*/ if (codec->Status == GF_ESM_CODEC_EOS) { /*if codec is reordering, try to flush it*/ if (codec->is_reordering) { if ( LockCompositionUnit(codec, codec->last_unit_cts+1, &CU, &unit_size) == GF_OUT_OF_MEM) return GF_OK; assert( CU ); e = mdec->ProcessData(mdec, NULL, 0, 0, CU->data, &unit_size, 0, 0); if (e==GF_OK) e = UnlockCompositionUnit(codec, CU, unit_size); } gf_term_stop_codec(codec); if (codec->CB) gf_cm_set_eos(codec->CB); } /*if no data, and channel not buffering, ABORT CB buffer (data timeout or EOS not detectable)*/ else if (ch && !ch->BufferOn) gf_cm_abort_buffering(codec->CB); return GF_OK; } /*get the object time*/ obj_time = gf_clock_time(codec->ck); /*Media Time for media codecs is updated in the CB*/ if (!codec->CB) { gf_es_drop_au(ch); return GF_BAD_PARAM; } /*image codecs*/ if (codec->CB->Capacity == 1) { /*usually only one image is tolerated in the stream, but just in case force reset of CB*/ if (codec->CB->UnitCount && (obj_time>=AU->CTS)) { gf_mx_p(codec->odm->mx); codec->CB->output->dataLength = 0; codec->CB->UnitCount = 0; gf_mx_v(codec->odm->mx); } /*CB is already full*/ if (codec->CB->UnitCount) return GF_OK; /*a SHA signature is computed for each AU. This avoids decoding/recompositing when identical (for instance streaming a carousel)*/ { u8 new_unit_signature[20]; gf_sha1_csum(AU->data, AU->dataLength, new_unit_signature); if (!memcmp(codec->last_unit_signature, new_unit_signature, sizeof(new_unit_signature))) { codec->nb_repeted_frames++; gf_es_drop_au(ch); return GF_OK; } codec->nb_repeted_frames = 0; memcpy(codec->last_unit_signature, new_unit_signature, sizeof(new_unit_signature)); } } /*try to refill the full buffer*/ first = 1; while (codec->CB->Capacity > codec->CB->UnitCount) { /*set media processing level*/ mmlevel = GF_CODEC_LEVEL_NORMAL; /*SEEK: if the last frame had the same TS, we are seeking. Ask the codec to drop*/ if (!ch->skip_sl && codec->last_unit_cts && (codec->last_unit_cts == AU->CTS) && !ch->esd->dependsOnESID) { mmlevel = GF_CODEC_LEVEL_SEEK; /*object clock is paused by media control or terminal is paused: exact frame seek*/ if ( #ifndef GPAC_DISABLE_VRML (codec->ck->mc && codec->ck->mc->paused) || #endif (codec->odm->term->play_state) ) { gf_cm_rewind_input(codec->CB); mmlevel = GF_CODEC_LEVEL_NORMAL; /*force staying in step-mode*/ codec->odm->term->compositor->step_mode=1; } } /*only perform drop in normal playback*/ else if (codec->CB->Status == CB_PLAY) { /*extremely late, set the level to drop NOTE: the 100 ms safety gard is to avoid discarding audio*/ if (!ch->skip_sl && (AU->CTS + 100 < obj_time) ) { mmlevel = GF_CODEC_LEVEL_DROP; GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d: frame too late (%d vs %d) - using drop level\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS, obj_time)); if (ch->resync_drift && (AU->CTS + ch->resync_drift < obj_time)) { ch->clock->StartTime += (obj_time - AU->CTS); GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] ODM%d: decoder too slow on OCR stream - rewinding clock of %d ms\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, obj_time - AU->CTS)); obj_time = gf_clock_time(codec->ck); } } /*we are late according to the media manager*/ else if (codec->PriorityBoost) { mmlevel = GF_CODEC_LEVEL_VERY_LATE; } /*otherwise we must have an idea of the load in order to set the right level use the composition buffer for that, only on the first frame*/ else if (first) { //if the CB is almost empty set to very late if (codec->CB->UnitCount <= codec->CB->Min+1) { mmlevel = GF_CODEC_LEVEL_VERY_LATE; } else if (codec->CB->UnitCount * 2 <= codec->CB->Capacity) { mmlevel = GF_CODEC_LEVEL_LATE; } first = 0; } } /*when using temporal scalability make sure we can decode*/ if (ch->esd->dependsOnESID && (codec->last_unit_dts > AU->DTS)){ // printf("SCALABLE STREAM DEAD!!\n"); goto drop; } if (ch->skip_sl) { if (codec->bytes_per_sec) { AU->CTS = codec->last_unit_cts + ch->ts_offset + codec->cur_audio_bytes * 1000 / codec->bytes_per_sec; } else if (codec->fps) { AU->CTS = codec->last_unit_cts + ch->ts_offset + (u32) (codec->cur_video_frames * 1000 / codec->fps); } } if ( LockCompositionUnit(codec, AU->CTS, &CU, &unit_size) == GF_OUT_OF_MEM) return GF_OK; scalable_retry: now = gf_term_get_time(codec->odm->term); assert( CU ); if (!CU->data && unit_size) e = GF_OUT_OF_MEM; else e = mdec->ProcessData(mdec, AU->data, AU->dataLength, ch->esd->ESID, CU->data, &unit_size, AU->PaddingBits, mmlevel); now = gf_term_get_time(codec->odm->term) - now; if (codec->Status == GF_ESM_CODEC_STOP) return GF_OK; /*input is too small, resize composition memory*/ switch (e) { case GF_BUFFER_TOO_SMALL: /*release but no dispatch*/ UnlockCompositionUnit(codec, CU, 0); ResizeCompositionBuffer(codec, unit_size); continue; /*this happens a lot when using non-MPEG-4 streams (ex: ffmpeg demuxer)*/ case GF_PACKED_FRAMES: /*in seek don't dispatch any output*/ if (mmlevel == GF_CODEC_LEVEL_SEEK) unit_size = 0; e = UnlockCompositionUnit(codec, CU, unit_size); GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI|GF_LOG_CODEC, ("[%s] ODM%d at %d decoded packed frame TS %d in %d ms\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock), AU->CTS, now)); if (ch->skip_sl) { if (codec->bytes_per_sec) { codec->cur_audio_bytes += unit_size; } else if (codec->fps && unit_size) { codec->cur_video_frames += 1; } } else { u32 deltaTS = 0; if (codec->bytes_per_sec) { deltaTS = unit_size * 1000 / codec->bytes_per_sec; } /*else if (0 && codec->fps && unit_size) { deltaTS = (u32) (1000.0f / codec->fps); } */else { deltaTS = (AU->DTS - codec->last_unit_dts); } AU->CTS += deltaTS; } codec_update_stats(codec, 0, now); continue; /*for all cases below, don't release the composition buffer until we are sure we are not processing a scalable stream*/ case GF_OK: if (unit_size) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI|GF_LOG_CODEC, ("[%s] ODM%d at %d decoded frame TS %d in %d ms (DTS %d) - %d in CB\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock), AU->CTS, now, AU->DTS, codec->CB->UnitCount + 1)); } /*if no size the decoder is not using the composition memory - if the object is in intitial buffering resume it!!*/ else if (codec->CB->Status == CB_BUFFER) { gf_cm_abort_buffering(codec->CB); } codec_update_stats(codec, AU->dataLength, now); if (ch->skip_sl) { if (codec->bytes_per_sec) { codec->cur_audio_bytes += unit_size; while (codec->cur_audio_bytes>codec->bytes_per_sec) { codec->cur_audio_bytes -= codec->bytes_per_sec; codec->last_unit_cts += 1000; } } else if (codec->fps && unit_size) { codec->cur_video_frames += 1; } } #ifndef GPAC_DISABLE_LOGS if (codec->odm->flags & GF_ODM_PREFETCH) { GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d At %d decoding frame TS %d in prefetch mode\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock) )); } #endif break; default: unit_size = 0; /*error - if the object is in intitial buffering resume it!!*/ gf_cm_abort_buffering(codec->CB); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d At %d (frame TS %d - %d ms ): decoded error %s\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock), AU->CTS, now, gf_error_to_string(e) )); e = GF_OK; break; } codec->last_unit_dts = AU->DTS; /*remember base layer timing*/ if (!ch->esd->dependsOnESID && !ch->skip_sl) codec->last_unit_cts = AU->CTS; drop: /*store current CTS*/ cts = AU->CTS; prev_ch = ch; gf_es_drop_au(ch); AU = NULL; if (e) { UnlockCompositionUnit(codec, CU, unit_size); return e; } Decoder_GetNextAU(codec, &ch, &AU); /*same CTS: same output, likely scalable stream so don't release the CB*/ if (AU && (AU->CTS == cts) && (ch !=prev_ch) ) { unit_size = codec->CB->UnitSize; goto scalable_retry; } /*in seek don't dispatch any output*/ if (mmlevel == GF_CODEC_LEVEL_SEEK) unit_size = 0; UnlockCompositionUnit(codec, CU, unit_size); if (!ch || !AU) return GF_OK; /*escape from decoding loop only if above critical limit - this is to avoid starvation on audio*/ if (!ch->esd->dependsOnESID && (codec->CB->UnitCount > codec->CB->Min)) { now = gf_term_get_time(codec->odm->term); if (now - entryTime >= TimeAvailable) { return GF_OK; } } Decoder_GetNextAU(codec, &ch, &AU); if (!ch || !AU) return GF_OK; } return GF_OK; }
static void imagetexture_update(GF_TextureHandler *txh) { if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) { MFURL url = ((M_ImageTexture *) txh->owner)->url; /*setup texture if needed*/ if (!txh->is_open && url.count) { gf_sc_texture_play(txh, &url); } gf_sc_texture_update_frame(txh, 0); if ( /*URL is present but not opened - redraw till fetch*/ /* (txh->stream && !txh->tx_io) && */ /*image has been updated*/ txh->needs_refresh) { /*mark all subtrees using this image as dirty*/ gf_node_dirty_parents(txh->owner); gf_sc_invalidate(txh->compositor, NULL); } return; } /*cache texture case*/ else { M_CacheTexture *ct = (M_CacheTexture *) txh->owner; /*decode cacheTexture data */ if ((ct->data || ct->image.buffer) && !txh->data) { #ifndef GPAC_DISABLE_AV_PARSERS u32 out_size; GF_Err e; /*BT/XMT playback: load to memory*/ if (ct->image.buffer) { char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); char *src_url = gf_url_concatenate(par, ct->image.buffer); FILE *test = gf_fopen( src_url ? src_url : ct->image.buffer, "rb"); if (test) { fseek(test, 0, SEEK_END); ct->data_len = (u32) gf_ftell(test); ct->data = gf_malloc(sizeof(char)*ct->data_len); fseek(test, 0, SEEK_SET); if (ct->data_len != fread(ct->data, 1, ct->data_len, test)) { GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: IO err\n", src_url ? src_url : ct->image.buffer ) ); gf_free(ct->data); ct->data = NULL; ct->data_len = 0; } gf_fclose(test); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: not found\n", src_url ? src_url : ct->image.buffer ) ); } ct->image.buffer = NULL; if (src_url) gf_free(src_url); } /*BIFS decoded playback*/ switch (ct->objectTypeIndication) { case GPAC_OTI_IMAGE_JPEG: out_size = 0; e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3); if (e==GF_BUFFER_TOO_SMALL) { u32 BPP; txh->data = gf_malloc(sizeof(char) * out_size); if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1; else BPP = 3; e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP); if (e==GF_OK) { gf_sc_texture_allocate(txh); gf_sc_texture_set_data(txh); txh->needs_refresh = 1; txh->stride = out_size / txh->height; } } break; case GPAC_OTI_IMAGE_PNG: out_size = 0; e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size); if (e==GF_BUFFER_TOO_SMALL) { txh->data = gf_malloc(sizeof(char) * out_size); e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size); if (e==GF_OK) { gf_sc_texture_allocate(txh); gf_sc_texture_set_data(txh); txh->needs_refresh = 1; txh->stride = out_size / txh->height; } } break; } #endif // GPAC_DISABLE_AV_PARSERS /*cacheURL is specified, store the image*/ if (ct->cacheURL.buffer) { u32 i; u8 hash[20]; FILE *cached_texture; char szExtractName[GF_MAX_PATH], section[64], *opt, *src_url; opt = (char *) gf_cfg_get_key(txh->compositor->user->config, "General", "CacheDirectory"); if (opt) { strcpy(szExtractName, opt); } else { opt = gf_get_default_cache_directory(); strcpy(szExtractName, opt); gf_free(opt); } strcat(szExtractName, "/"); src_url = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); gf_sha1_csum((u8 *)src_url, (u32) strlen(src_url), hash); for (i=0; i<20; i++) { char t[3]; t[2] = 0; sprintf(t, "%02X", hash[i]); strcat(szExtractName, t); } strcat(szExtractName, "_"); strcat(szExtractName, ct->cacheURL.buffer); cached_texture = gf_fopen(szExtractName, "wb"); if (cached_texture) { gf_fwrite(ct->data, 1, ct->data_len, cached_texture); gf_fclose(cached_texture); } /*and write cache info*/ if (ct->expirationDate!=0) { sprintf(section, "@cache=%p", ct); gf_cfg_set_key(txh->compositor->user->config, section, "serviceURL", src_url); gf_cfg_set_key(txh->compositor->user->config, section, "cacheFile", szExtractName); gf_cfg_set_key(txh->compositor->user->config, section, "cacheName", ct->cacheURL.buffer); if (ct->expirationDate>0) { char exp[50]; u32 sec, frac; gf_net_get_ntp(&sec, &frac); sec += ct->expirationDate; sprintf(exp, "%u", sec); gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", exp); } else { gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", "0"); } } } /*done with image, destroy buffer*/ if (ct->data) gf_free(ct->data); ct->data = NULL; ct->data_len = 0; } } }
GF_Err gf_bifs_dec_sf_field(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node, GF_FieldInfo *field) { GF_Err e; GF_Node *new_node; u32 size, length, w, h, i; char *buffer; //blindly call unquantize. return is OK, error or GF_EOS if (codec->ActiveQP && node) { e = gf_bifs_dec_unquant_field(codec, bs, node, field); if (e != GF_EOS) return e; } //not quantized, use normal scheme switch (field->fieldType) { case GF_SG_VRML_SFBOOL: * ((SFBool *) field->far_ptr) = (SFBool) gf_bs_read_int(bs, 1); break; case GF_SG_VRML_SFCOLOR: ((SFColor *)field->far_ptr)->red = BD_ReadSFFloat(codec, bs);; ((SFColor *)field->far_ptr)->green = BD_ReadSFFloat(codec, bs); ((SFColor *)field->far_ptr)->blue = BD_ReadSFFloat(codec, bs); break; case GF_SG_VRML_SFFLOAT: *((SFFloat *)field->far_ptr) = BD_ReadSFFloat(codec, bs); break; case GF_SG_VRML_SFINT32: *((SFInt32 *)field->far_ptr) = (s32) gf_bs_read_int(bs, 32); break; case GF_SG_VRML_SFTIME: *((SFTime *)field->far_ptr) = gf_bs_read_double(bs); if (node) BD_CheckSFTimeOffset(codec, node, field); break; case GF_SG_VRML_SFVEC2F: ((SFVec2f *)field->far_ptr)->x = BD_ReadSFFloat(codec, bs); ((SFVec2f *)field->far_ptr)->y = BD_ReadSFFloat(codec, bs); break; case GF_SG_VRML_SFVEC3F: ((SFVec3f *)field->far_ptr)->x = BD_ReadSFFloat(codec, bs); ((SFVec3f *)field->far_ptr)->y = BD_ReadSFFloat(codec, bs); ((SFVec3f *)field->far_ptr)->z = BD_ReadSFFloat(codec, bs); break; case GF_SG_VRML_SFROTATION: ((SFRotation *)field->far_ptr)->x = BD_ReadSFFloat(codec, bs); ((SFRotation *)field->far_ptr)->y = BD_ReadSFFloat(codec, bs); ((SFRotation *)field->far_ptr)->z = BD_ReadSFFloat(codec, bs); ((SFRotation *)field->far_ptr)->q = BD_ReadSFFloat(codec, bs); break; case GF_SG_VRML_SFSTRING: size = gf_bs_read_int(bs, 5); length = gf_bs_read_int(bs, size); if (gf_bs_available(bs) < length) return GF_NON_COMPLIANT_BITSTREAM; if (node && (node->sgprivate->tag==TAG_MPEG4_CacheTexture) && (field->fieldIndex<=2)) { Bool skip_file_url_proto=0; char *name; FILE *f; M_CacheTexture *ct = (M_CacheTexture *) node; char *buf = gf_malloc(sizeof(char)*length); gf_bs_read_data(bs, buf, length); if (ct->cacheURL.buffer) { name = gf_strdup(ct->cacheURL.buffer); } else { char szImg[100], *ext; switch (ct->objectTypeIndication) { case GPAC_OTI_IMAGE_JPEG: ext = "jpg"; break; case GPAC_OTI_IMAGE_PNG: ext = "png"; break; case GPAC_OTI_IMAGE_JPEG_2000: ext = "jp2"; break; default: ext = "img"; } sprintf(szImg, "%p%p.%s", codec, ct, ext); name = gf_strdup(szImg); } if (codec->extraction_path) { char *path; u32 len = strlen(name)+strlen(codec->extraction_path)+2; if (strnicmp(codec->extraction_path, "file://", 7)) len+=7; /*SHA1 of service in hexa*/ if (codec->service_url) len += 41; path = gf_malloc(sizeof(char)*len); path[0] = 0; /*force using file:// URL prototype to avoid confusion with resources adressed from the root of the source server*/ if (strnicmp(codec->extraction_path, "file://", 7)) strcpy(path, "file://"); strcat(path, codec->extraction_path); strcat(path, "/"); if (codec->service_url) { u8 hash[20]; u32 i; gf_sha1_csum(codec->service_url, strlen(codec->service_url), hash); for (i=0; i<20; i++) { char t[3]; t[2] = 0; sprintf(t, "%02X", hash[i]); strcat(path, t); } strcat(path, "_"); } strcat(path, name); gf_free(name); name = path; skip_file_url_proto = 1; } ((SFString *)field->far_ptr)->buffer = name; /*skip the initial file://*/ f = gf_f64_open(name + (skip_file_url_proto ? 7 : 0), "wb"); fwrite(buf, 1, length, f); fclose(f); gf_free(buf); } else { if ( ((SFString *)field->far_ptr)->buffer ) gf_free( ((SFString *)field->far_ptr)->buffer); ((SFString *)field->far_ptr)->buffer = (char *)gf_malloc(sizeof(char)*(length+1)); memset(((SFString *)field->far_ptr)->buffer , 0, length+1); for (i=0; i<length; i++) { ((SFString *)field->far_ptr)->buffer[i] = gf_bs_read_int(bs, 8); } } break; case GF_SG_VRML_SFURL: { SFURL *url = (SFURL *) field->far_ptr; size = gf_bs_read_int(bs, 1); if (size) { if (url->url) gf_free(url->url ); url->url = NULL; length = gf_bs_read_int(bs, 10); url->OD_ID = length; } else { if ( url->OD_ID ) url->OD_ID = (u32) -1; size = gf_bs_read_int(bs, 5); length = gf_bs_read_int(bs, size); if (gf_bs_available(bs) < length) return GF_NON_COMPLIANT_BITSTREAM; buffer = NULL; if (length) { buffer = (char *)gf_malloc(sizeof(char)*(length+1)); memset(buffer, 0, length+1); for (i=0; i<length; i++) buffer[i] = gf_bs_read_int(bs, 8); } if (url->url) gf_free( url->url); /*if URL is empty set it to NULL*/ if (buffer && strlen(buffer)) { url->url = buffer; } else { gf_free(buffer); url->url = NULL; } } } break; case GF_SG_VRML_SFIMAGE: if (((SFImage *)field->far_ptr)->pixels) gf_free(((SFImage *)field->far_ptr)->pixels); w = gf_bs_read_int(bs, 12); h = gf_bs_read_int(bs, 12); length = gf_bs_read_int(bs, 2); if (length > 3) length = 3; length += 1; size = w * h * length; if (gf_bs_available(bs) < size) return GF_NON_COMPLIANT_BITSTREAM; ((SFImage *)field->far_ptr)->width = w; ((SFImage *)field->far_ptr)->height = h; ((SFImage *)field->far_ptr)->numComponents = length; ((SFImage *)field->far_ptr)->pixels = (unsigned char *)gf_malloc(sizeof(char)*size); //WARNING: Buffers are NOT ALIGNED IN THE BITSTREAM for (i=0; i<size; i++) { ((SFImage *)field->far_ptr)->pixels[i] = gf_bs_read_int(bs, 8); } break; case GF_SG_VRML_SFCOMMANDBUFFER: { SFCommandBuffer *sfcb = (SFCommandBuffer *)field->far_ptr; if (sfcb->buffer) { gf_free(sfcb->buffer); sfcb->buffer = NULL; } while (gf_list_count(sfcb->commandList)) { GF_Command *com = (GF_Command*)gf_list_get(sfcb->commandList, 0); gf_list_rem(sfcb->commandList, 0); gf_sg_command_del(com); } size = gf_bs_read_int(bs, 5); length = gf_bs_read_int(bs, size); if (gf_bs_available(bs) < length) return GF_NON_COMPLIANT_BITSTREAM; sfcb->bufferSize = length; if (length) { sfcb->buffer = (unsigned char *)gf_malloc(sizeof(char)*(length)); //WARNING Buffers are NOT ALIGNED IN THE BITSTREAM for (i=0; i<length; i++) { sfcb->buffer[i] = gf_bs_read_int(bs, 8); } } //notify the node - this is needed in case an enhencement layer replaces the buffer, in which case //the # ID Bits may change SFCommandBufferChanged(codec, node); /* 1 - memory mode, register command buffer for later parsing 2 - InputSensor only works on decompressed commands */ if (codec->dec_memory_mode || (node->sgprivate->tag==TAG_MPEG4_InputSensor)) { CommandBufferItem *cbi = (CommandBufferItem *)gf_malloc(sizeof(CommandBufferItem)); cbi->node = node; cbi->cb = sfcb; gf_list_add(codec->command_buffers, cbi); } } break; case GF_SG_VRML_SFNODE: //for nodes the field ptr is a ptr to the field, which is a node ptr ;) new_node = gf_bifs_dec_node(codec, bs, field->NDTtype); if (new_node) { e = gf_node_register(new_node, node); if (e) return e; } //it may happen that new_node is NULL (this is valid for a proto declaration) *((GF_Node **) field->far_ptr) = new_node; break; case GF_SG_VRML_SFSCRIPT: #ifdef GPAC_HAS_SPIDERMONKEY codec->LastError = SFScript_Parse(codec, (SFScript*)field->far_ptr, bs, node); #else return GF_NOT_SUPPORTED; #endif break; case GF_SG_VRML_SFATTRREF: { SFAttrRef *ar = (SFAttrRef *)field->far_ptr; u32 nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); ar->node = gf_sg_find_node(codec->current_graph, nodeID); if (!ar->node) { } else { u32 nbBitsDEF = gf_get_bit_size(gf_node_get_num_fields_in_mode(ar->node, GF_SG_FIELD_CODING_DEF) - 1); u32 field_ref = gf_bs_read_int(bs, nbBitsDEF); codec->LastError = gf_bifs_get_field_index(ar->node, field_ref, GF_SG_FIELD_CODING_DEF, &ar->fieldIndex); } } break; default: return GF_NON_COMPLIANT_BITSTREAM; } return codec->LastError; }