Bool gf_term_lock_codec(GF_Codec *codec, Bool lock, Bool trylock) { Bool res = 1; CodecEntry *ce; GF_Terminal *term = codec->odm->term; ce = mm_get_codec(term->codecs, codec); if (!ce) return 0; if (ce->mx) { if (lock) { if (trylock) { res = gf_mx_try_lock(ce->mx); } else { res = gf_mx_p(ce->mx); } } else gf_mx_v(ce->mx); } else { if (lock) { if (trylock) { res = gf_mx_try_lock(term->mm_mx); } else { res = gf_mx_p(term->mm_mx); } } else gf_mx_v(term->mm_mx); } return res; }
void gf_term_remove_codec(GF_Terminal *term, GF_Codec *codec) { u32 i; Bool locked; CodecEntry *ce; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Unregistering codec %s\n", codec->decio ? codec->decio->module_name : "RAW")); /*cf note above*/ locked = gf_mx_try_lock(term->mm_mx); i=0; while ((ce = (CodecEntry*)gf_list_enum(term->codecs, &i))) { if (ce->dec != codec) continue; if (ce->thread) { if (ce->flags & GF_MM_CE_RUNNING) { ce->flags &= ~GF_MM_CE_RUNNING; while (! (ce->flags & GF_MM_CE_DEAD)) gf_sleep(10); ce->flags &= ~GF_MM_CE_DEAD; } gf_th_del(ce->thread); gf_mx_del(ce->mx); } if (locked) { gf_free(ce); gf_list_rem(term->codecs, i-1); } else { ce->flags |= GF_MM_CE_DISCARDED; } break; } if (locked) gf_mx_v(term->mm_mx); return; }
GF_EXPORT void gf_sc_texture_destroy(GF_TextureHandler *txh) { GF_Compositor *compositor = txh->compositor; Bool lock = gf_mx_try_lock(compositor->mx); gf_sc_texture_release(txh); if (txh->is_open) gf_sc_texture_stop(txh); gf_list_del_item(txh->compositor->textures, txh); if (lock) gf_mx_v(compositor->mx); }
void gf_term_stop_codec(GF_Codec *codec, Bool is_pause) { GF_CodecCapability cap; Bool locked = 0; CodecEntry *ce; GF_Terminal *term = codec->odm->term; ce = mm_get_codec(term->codecs, codec); if (!ce) return; if (ce->mx) gf_mx_p(ce->mx); /*We must make sure: 1- media codecs are synchrounously stop otherwise we could destroy the composition memory while the codec writes to it 2- prevent deadlock for other codecs waiting for the scene graph */ else if (codec->CB) { locked = 1; gf_mx_p(term->mm_mx); } else { locked = gf_mx_try_lock(term->mm_mx); } if (!is_pause) { cap.CapCode = GF_CODEC_ABORT; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); if (codec->decio && codec->odm->mo && (codec->odm->mo->flags & GF_MO_DISPLAY_REMOVE) ) { cap.CapCode = GF_CODEC_SHOW_SCENE; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); codec->odm->mo->flags &= ~GF_MO_DISPLAY_REMOVE; } } /*set status directly and don't touch CB state*/ codec->Status = GF_ESM_CODEC_STOP; /*don't wait for end of thread since this can be triggered within the decoding thread*/ if (ce->flags & GF_MM_CE_RUNNING) { ce->flags &= ~GF_MM_CE_RUNNING; if (!ce->thread) term->cumulated_priority -= codec->Priority+1; } if (codec->CB) gf_cm_abort_buffering(codec->CB); if (ce->mx) gf_mx_v(ce->mx); /*cf note above*/ else if (locked) gf_mx_v(term->mm_mx); }
GF_EXPORT void gf_term_download_del(GF_DownloadSession * sess) { Bool locked; GF_ClientService *serv; if (!sess) return; serv = (GF_ClientService *)gf_dm_sess_get_private(sess); /*avoid sending data back to user*/ gf_dm_sess_abort(sess); locked = gf_mx_try_lock(serv->term->media_queue_mx); /*unregister from service*/ gf_list_del_item(serv->dnloads, sess); /*same as service: this may be called in the downloader thread (typically when download fails) so we must queue the downloader and let the term delete it later on*/ gf_list_add(serv->term->net_services_to_remove, sess); if (locked) gf_term_lock_media_queue(serv->term, 0); }
GF_Err gf_sr_set_size(GF_Renderer *sr, u32 NewWidth, u32 NewHeight) { Bool lock_ok; if (!NewWidth || !NewHeight) { sr->override_size_flags &= ~2; return GF_OK; } /*EXTRA CARE HERE: the caller (user app) is likely a different thread than the renderer one, and depending on window manager we may get called here as a result of a message sent to user but not yet returned */ lock_ok = gf_mx_try_lock(sr->mx); sr->new_width = NewWidth; sr->new_height = NewHeight; sr->msg_type |= GF_SR_CFG_SET_SIZE; /*if same size only request for video setup */ if ((sr->width == NewWidth) && (sr->height == NewHeight) ) sr->msg_type |= GF_SR_CFG_WINDOWSIZE_NOTIF; if (lock_ok) gf_sr_lock(sr, 0); return GF_OK; }
void gf_term_add_codec(GF_Terminal *term, GF_Codec *codec) { u32 i, count; Bool locked; Bool threaded; CodecEntry *cd; CodecEntry *ptr, *next; GF_CodecCapability cap; assert(codec); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Registering codec %s\n", codec->decio ? codec->decio->module_name : "RAW")); /*caution: the mutex can be grabbed by a decoder waiting for a mutex owned by the calling thread this happens when several scene codecs are running concurently and triggering play/pause on media*/ locked = gf_mx_try_lock(term->mm_mx); cd = mm_get_codec(term->codecs, codec); if (cd) goto exit; GF_SAFEALLOC(cd, CodecEntry); cd->dec = codec; if (!cd->dec->Priority) cd->dec->Priority = 1; /*we force audio codecs to be threaded in free mode, so that we avoid waiting in the audio renderer if another decoder is locking the main mutex this can happen when the audio decoder is running late*/ if (codec->type==GF_STREAM_AUDIO) { threaded = 1; } else { cap.CapCode = GF_CODEC_WANTS_THREAD; cap.cap.valueInt = 0; gf_codec_get_capability(codec, &cap); threaded = cap.cap.valueInt; } if (threaded) cd->flags |= GF_MM_CE_REQ_THREAD; if (term->flags & GF_TERM_MULTI_THREAD) { if ((codec->type==GF_STREAM_AUDIO) || (codec->type==GF_STREAM_VISUAL)) threaded = 1; } else if (term->flags & GF_TERM_SINGLE_THREAD) { threaded = 0; } if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) threaded = 0; if (threaded) { cd->thread = gf_th_new(cd->dec->decio->module_name); cd->mx = gf_mx_new(cd->dec->decio->module_name); cd->flags |= GF_MM_CE_THREADED; gf_list_add(term->codecs, cd); goto exit; } //add codec 1- per priority 2- per type, audio being first //priorities inherits from Systems (5bits) so range from 0 to 31 //we sort from MAX to MIN count = gf_list_count(term->codecs); for (i=0; i<count; i++) { ptr = (CodecEntry*)gf_list_get(term->codecs, i); if (ptr->flags & GF_MM_CE_THREADED) continue; //higher priority, continue if (ptr->dec->Priority > codec->Priority) continue; //same priority, put audio first if (ptr->dec->Priority == codec->Priority) { //we insert audio (0x05) before video (0x04) if (ptr->dec->type < codec->type) { gf_list_insert(term->codecs, cd, i); goto exit; } //same prior, same type: insert after if (ptr->dec->type == codec->type) { if (i+1==count) { gf_list_add(term->codecs, cd); } else { gf_list_insert(term->codecs, cd, i+1); } goto exit; } //we insert video (0x04) after audio (0x05) if next is not audio //last one if (i+1 == count) { gf_list_add(term->codecs, cd); goto exit; } next = (CodecEntry*)gf_list_get(term->codecs, i+1); //# priority level, insert if ((next->flags & GF_MM_CE_THREADED) || (next->dec->Priority != codec->Priority)) { gf_list_insert(term->codecs, cd, i+1); goto exit; } //same priority level and at least one after : continue continue; } gf_list_insert(term->codecs, cd, i); goto exit; } //if we got here, first in list gf_list_add(term->codecs, cd); exit: if (locked) gf_mx_v(term->mm_mx); return; }
/*dispatch the AU in the DB*/ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) { u32 time; GF_DBUnit *au; if (!ch->buffer || !ch->len) { if (ch->buffer) { gf_free(ch->buffer); ch->buffer = NULL; } return; } au = gf_db_unit_new(); if (!au) { gf_free(ch->buffer); ch->buffer = NULL; ch->len = 0; return; } au->CTS = ch->CTS; au->DTS = ch->DTS; if (ch->IsRap) au->flags |= GF_DB_AU_RAP; if (ch->CTS_past_offset) { au->CTS = ch->CTS_past_offset; au->flags |= GF_DB_AU_CTS_IN_PAST; ch->CTS_past_offset = 0; } if (ch->no_timestamps) { au->flags |= GF_DB_AU_NO_TIMESTAMPS; ch->no_timestamps=0; } au->data = ch->buffer; au->dataLength = ch->len; au->PaddingBits = ch->padingBits; ch->IsRap = 0; ch->padingBits = 0; au->next = NULL; ch->buffer = NULL; if (ch->len + ch->media_padding_bytes != ch->allocSize) { au->data = (char*)gf_realloc(au->data, sizeof(char) * (au->dataLength + ch->media_padding_bytes)); } if (ch->media_padding_bytes) memset(au->data + au->dataLength, 0, sizeof(char)*ch->media_padding_bytes); ch->len = ch->allocSize = 0; gf_es_lock(ch, 1); if (ch->service && ch->service->cache) { GF_SLHeader slh; memset(&slh, 0, sizeof(GF_SLHeader)); slh.accessUnitEndFlag = slh.accessUnitStartFlag = 1; slh.compositionTimeStampFlag = slh.decodingTimeStampFlag = 1; slh.decodingTimeStamp = ch->net_dts; slh.compositionTimeStamp = ch->net_cts; slh.randomAccessPointFlag = (au->flags & GF_DB_AU_RAP) ? 1 : 0; ch->service->cache->Write(ch->service->cache, ch, au->data, au->dataLength, &slh); } if (!ch->AU_buffer_first) { ch->AU_buffer_first = au; ch->AU_buffer_last = au; ch->AU_Count = 1; } else { if (ch->AU_buffer_last->DTS<=au->DTS) { ch->AU_buffer_last->next = au; ch->AU_buffer_last = ch->AU_buffer_last->next; } /*enable deinterleaving only for audio channels (some video transport may not be able to compute DTS, cf MPEG1-2/RTP) HOWEVER, we must recompute a monotone increasing DTS in case the decoder does perform frame reordering in which case the DTS is used for presentation time!!*/ else if (ch->esd->decoderConfig->streamType!=GF_STREAM_AUDIO) { #if 0 GF_DBUnit *au_prev, *ins_au; u32 DTS; #endif au->DTS = 0; /*append AU*/ ch->AU_buffer_last->next = au; ch->AU_buffer_last = ch->AU_buffer_last->next; #if 0 GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] Media deinterleaving OD %d ch %d\n", ch->esd->ESID, ch->odm->OD->objectDescriptorID)); DTS = au->DTS; au_prev = ch->AU_buffer_first; /*locate first AU in buffer with DTS greater than new unit CTS*/ while (au_prev->next && (au_prev->DTS < DTS) ) au_prev = au_prev->next; /*remember insertion point*/ ins_au = au_prev; /*shift all following frames DTS*/ while (au_prev->next) { au_prev->next->DTS = au_prev->DTS; au_prev = au_prev->next; } /*and apply*/ ins_au->DTS = DTS; #endif } else { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] Audio deinterleaving OD %d ch %d\n", ch->esd->ESID, ch->odm->OD->objectDescriptorID)); /*de-interleaving of AUs*/ if (ch->AU_buffer_first->DTS > au->DTS) { au->next = ch->AU_buffer_first; ch->AU_buffer_first = au; } else { GF_DBUnit *au_prev = ch->AU_buffer_first; while (au_prev->next && au_prev->next->DTS<au->DTS) { au_prev = au_prev->next; } assert(au_prev); if (au_prev->next->DTS==au->DTS) { gf_free(au->data); gf_free(au); } else { au->next = au_prev->next; au_prev->next = au; } } } ch->AU_Count += 1; } Channel_UpdateBufferTime(ch); ch->au_duration = 0; if (duration) ch->au_duration = (u32) ((u64)1000 * duration / ch->ts_res); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d - Dispatch AU DTS %d - CTS %d - size %d time %d Buffer %d Nb AUs %d - First AU relative timing %d\n", ch->esd->ESID, au->DTS, au->CTS, au->dataLength, gf_clock_real_time(ch->clock), ch->BufferTime, ch->AU_Count, ch->AU_buffer_first ? ch->AU_buffer_first->DTS - gf_clock_time(ch->clock) : 0 )); /*little optimisation: if direct dispatching is possible, try to decode the AU we must lock the media scheduler to avoid deadlocks with other codecs accessing the scene or media resources*/ if (ch->dispatch_after_db) { u32 retry = 100; u32 current_frame; GF_Terminal *term = ch->odm->term; ch_buffer_off(ch); gf_es_lock(ch, 0); if (gf_mx_try_lock(term->mm_mx)) { switch (ch->esd->decoderConfig->streamType) { case GF_STREAM_OD: gf_codec_process(ch->odm->subscene->od_codec, 100); break; case GF_STREAM_SCENE: if (ch->odm->codec) gf_codec_process(ch->odm->codec, 100); else gf_codec_process(ch->odm->subscene->scene_codec, 100); break; } gf_mx_v(term->mm_mx); } gf_es_lock(ch, 1); current_frame = term->compositor->frame_number; /*wait for initial setup to complete before giving back the hand to the caller service*/ while (retry) { /*Scene bootstrap: if the scene is attached, wait for first frame to complete so that initial PLAY on objects can be evaluated*/ if (term->compositor->scene && (term->compositor->frame_number==current_frame) ) { retry--; gf_sleep(1); continue; } /*Media bootstrap: wait for all pending requests on media objects are processed*/ if (gf_list_count(term->media_queue)) { retry--; gf_sleep(1); continue; } break; } } time = gf_term_get_time(ch->odm->term); if (ch->BufferOn) { ch->last_au_time = time; Channel_UpdateBuffering(ch, 1); } else { /*trigger the data progress every 500 ms*/ if (ch->last_au_time + 500 > time) { gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_PROGRESS); ch->last_au_time = time; } } gf_es_lock(ch, 0); }
/*special handling of decoders not using ESM*/ static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable) { Bool resume_clock; u32 now; GF_Channel *ch; GF_Scene *scene_locked; GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio; GF_Err e = GF_OK; /*muting systems codec means we don't decode until mute is off - likely there will be visible however there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/ if (codec->Muted) return GF_OK; if (codec->Status == GF_ESM_CODEC_EOS) { gf_term_stop_codec(codec); return GF_OK; } scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene; ch = (GF_Channel*)gf_list_get(codec->inChannels, 0); if (!ch) return GF_OK; resume_clock = 0; /*init channel clock*/ if (!ch->IsClockInit) { Bool started; /*signal seek*/ if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK; gf_es_init_dummy(ch); sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, -1, GF_CODEC_LEVEL_NORMAL); gf_mx_v(scene_locked->root_od->term->compositor->mx); started = gf_clock_is_started(ch->clock); /*let's be nice to the scene loader (that usually involves quite some parsing), pause clock while parsing*/ gf_clock_pause(ch->clock); codec->last_unit_dts = 0; if (!started) return GF_OK; } codec->odm->current_time = codec->last_unit_cts = gf_clock_time(codec->ck); /*lock scene*/ GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[PrivateDec] Codec %s Processing at %d\n", sdec->module_name , codec->odm->current_time)); if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK; now = gf_term_get_time(codec->odm->term); e = sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, codec->odm->current_time, GF_CODEC_LEVEL_NORMAL); now = gf_term_get_time(codec->odm->term) - now; codec->last_unit_dts ++; /*resume on error*/ if (e && (codec->last_unit_dts<2) ) { gf_clock_resume(ch->clock); codec->last_unit_dts = 2; } /*resume clock on 2nd decode (we assume parsing is done in 2 steps, one for first frame display, one for complete parse)*/ else if (codec->last_unit_dts==2) { gf_clock_resume(ch->clock); } codec_update_stats(codec, 0, now); gf_mx_v(scene_locked->root_od->term->compositor->mx); if (e==GF_EOS) { /*first end of stream, evaluate duration*/ //if (!codec->odm->duration) gf_odm_set_duration(codec->odm, ch, codec->odm->current_time); gf_es_on_eos(ch); return GF_OK; } return e; }
static GF_Err SystemCodec_Process(GF_Codec *codec, u32 TimeAvailable) { GF_DBUnit *AU; GF_Channel *ch; u32 now, obj_time, mm_level, au_time, cts; GF_Scene *scene_locked; Bool check_next_unit; GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio; GF_Err e = GF_OK; scene_locked = NULL; /*for resync, if needed - the logic behind this is that there is no composition memory on sytems codecs so "frame dropping" is done by preventing the compositor from redrawing after an update and decoding following AU so that the compositor is always woken up once all late systems AUs are decoded. This flag is overriden when seeking*/ check_next_unit = (codec->odm->term->flags & GF_TERM_SYSDEC_RESYNC) ? 1 : 0; check_unit: /*muting systems codec means we don't decode until mute is off - likely there will be visible however there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/ if (codec->Muted) goto exit; /*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, move to STOP*/ if (codec->Status == GF_ESM_CODEC_EOS) { GF_CodecCapability cap; cap.CapCode = GF_CODEC_MEDIA_NOT_OVER; cap.cap.valueInt = 0; sdec->GetCapabilities(codec->decio, &cap); if (!cap.cap.valueInt) { gf_term_stop_codec(codec); if ((codec->type==GF_STREAM_OD) && (codec->nb_dec_frames==1)) { /*this is just by safety, since seeking is only allowed when a single clock is present in the scene*/ if (gf_list_count(codec->odm->net_service->Clocks)==1) codec->odm->subscene->static_media_ressources=1; } } } goto exit; } #ifndef GPAC_DISABLE_VRML if (ch && ch->odm->media_ctrl && !ch->odm->media_ctrl->media_speed) goto exit; #endif /*get the object time*/ obj_time = gf_clock_time(codec->ck); /*clock is not started*/ // if (ch->first_au_fetched && !gf_clock_is_started(ch->clock)) goto exit; /*check timing based on the input channel and main FPS*/ if (AU->DTS > obj_time /*+ codec->odm->term->half_frame_duration*/) goto exit; cts = AU->CTS; /*in cases where no CTS was set for the BIFS (which may be interpreted as "now", although not compliant), use the object clock*/ if (AU->flags & GF_DB_AU_NO_TIMESTAMPS) au_time = obj_time; /*case where CTS is in the past (carousels) */ else if (AU->flags & GF_DB_AU_CTS_IN_PAST) { au_time = - (s32) AU->CTS; cts = AU->DTS; } /*regular case, SFTime will be from CTS (since DTS == CTS)*/ else au_time = AU->DTS; /*check seeking and update timing - do NOT use the base layer, since BIFS streams may depend on other streams not on the same clock*/ if (codec->last_unit_cts == cts) { /*seeking for systems is done by not releasing the graph until seek is done*/ check_next_unit = 1; mm_level = GF_CODEC_LEVEL_SEEK; } /*set system stream timing*/ else { codec->last_unit_cts = AU->CTS; /*we're droping the frame*/ if (scene_locked) codec->nb_droped ++; mm_level = GF_CODEC_LEVEL_NORMAL; } /*lock scene*/ if (!scene_locked) { scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene; if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK; /*if terminal is paused, force step-mode: it won't hurt in regular pause/play and ensures proper frame dumping*/ if (codec->odm->term->play_state) codec->odm->term->compositor->step_mode=1; } /*current media time for system objects is the clock time, since the media is likely to have random updates in time*/ codec->odm->current_time = gf_clock_time(codec->ck); now = gf_term_get_time(codec->odm->term); e = sdec->ProcessData(sdec, AU->data, AU->dataLength, ch->esd->ESID, au_time, mm_level); now = gf_term_get_time(codec->odm->term) - now; GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d at %d decoded AU TS %d in %d ms\n", sdec->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, codec->odm->current_time, AU->CTS, now)); codec_update_stats(codec, AU->dataLength, now); codec->prev_au_size = AU->dataLength; /*destroy this AU*/ gf_es_drop_au(ch); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[SysDec] Codec %s AU CTS %d Decode error %s\n", sdec->module_name , cts, gf_error_to_string(e) )); if (e<0) ch->stream_state = 2; goto exit; } /*in broadcast mode, generate a scene if none is available*/ if (codec->ck->no_time_ctrl) { GF_Scene *scene = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene; /*static OD resources (embedded in ESD) in broadcast mode, reset time*/ if (codec->flags & GF_ESM_CODEC_IS_STATIC_OD) gf_clock_reset(codec->ck); /*generate a temp scene if none is in place*/ if (scene->graph_attached != 1) { Bool prev_dyn = scene->is_dynamic_scene; scene->is_dynamic_scene = 1; gf_scene_regenerate(scene); scene->graph_attached = 2; scene->is_dynamic_scene = prev_dyn; GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[Decoder] Got OD resources before scene - generating temporary scene\n")); } } /*if no release restart*/ if (check_next_unit) goto check_unit; exit: if (scene_locked) { gf_mx_v(scene_locked->root_od->term->compositor->mx); } return e; }
void gf_term_stop_codec(GF_Codec *codec, Bool is_pause) { GF_CodecCapability cap; Bool locked = 0; CodecEntry *ce; GF_Terminal *term = codec->odm->term; ce = mm_get_codec(term->codecs, codec); if (!ce) return; if (ce->mx) gf_mx_p(ce->mx); /*We must make sure: 1- media codecs are synchrounously stop otherwise we could destroy the composition memory while the codec writes to it 2- prevent deadlock for other codecs waiting for the scene graph */ else if (codec->CB) { locked = 1; gf_mx_p(term->mm_mx); } else { locked = gf_mx_try_lock(term->mm_mx); } if (!is_pause) { cap.CapCode = GF_CODEC_ABORT; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); if (codec->decio && codec->odm->mo && (codec->odm->mo->flags & GF_MO_DISPLAY_REMOVE) ) { cap.CapCode = GF_CODEC_SHOW_SCENE; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); codec->odm->mo->flags &= ~GF_MO_DISPLAY_REMOVE; } } /*for audio codec force CB to stop state to discard any pending AU. Not doing so would lead to a wrong estimation of the clock drift when resuming the object*/ if (codec->type==GF_STREAM_AUDIO) { gf_codec_set_status(codec, GF_ESM_CODEC_STOP); } //if video is in a dynamic scene, reset the CB if user stop (eg codec was not in EOS). Otherwise (bifs,svg) we may want to keep the last decoded image else if ((codec->Status<GF_ESM_CODEC_EOS) && codec->odm && codec->odm->parentscene && codec->odm->parentscene->is_dynamic_scene && codec->CB && (codec->CB->Capacity>1)) { gf_codec_set_status(codec, GF_ESM_CODEC_STOP); } /*otherwise set status directly and don't touch CB state*/ else { codec->Status = GF_ESM_CODEC_STOP; } /*don't wait for end of thread since this can be triggered within the decoding thread*/ if (ce->flags & GF_MM_CE_RUNNING) { ce->flags &= ~GF_MM_CE_RUNNING; if (!ce->thread) term->cumulated_priority -= codec->Priority+1; } if (codec->CB) gf_cm_abort_buffering(codec->CB); if (ce->mx) gf_mx_v(ce->mx); /*cf note above*/ else if (locked) gf_mx_v(term->mm_mx); }
void MPEGVSensorCallback( void* ptr, const char* data) { GF_BitStream *bs; char *buf; u32 buf_size; float x, y, z, a, b; struct __input_device * dr = (struct __input_device *)ptr; MPEGVSCTX; if (!gf_mx_try_lock(rc->mx)) return; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); if ( rc->sensorIOSType == SENSOR_ACCELEROMETER || rc->sensorIOSType == SENSOR_GYROSCOPE //|| rc->sensorIOSType == 3 || rc->sensorIOSType == SENSOR_MAGNETOMETER ) { sscanf(data, "%f;%f;%f;", &x, &y, &z); gf_bs_write_int(bs, 1, 1); gf_bs_write_float(bs, x); gf_bs_write_float(bs, y); gf_bs_write_float(bs, z); } else if ( rc->sensorIOSType == 5 || rc->sensorIOSType == 6 ) { sscanf(data, "%f;", &x); gf_bs_write_int(bs, 1, 1); gf_bs_write_float(bs, x); } else if ( rc->sensorIOSType == 11 ) { sscanf(data, "%f;%f;%f;", &x, &y, &z); gf_bs_write_int(bs, 1, 1); gf_bs_write_float(bs, x); gf_bs_write_float(bs, y); gf_bs_write_float(bs, z); /*gf_bs_write_float(bs, q);*/ } else if ( rc->sensorIOSType == SENSOR_GPS ) { sscanf(data, "%f;%f;%f;%f;%f;", &x, &y, &z, &a, &b); gf_bs_write_int(bs, 1, 1); gf_bs_write_float(bs, x); gf_bs_write_float(bs, y); gf_bs_write_float(bs, z); gf_bs_write_int(bs, 1, 1); gf_bs_write_float(bs, a); gf_bs_write_int(bs, 1, 1); gf_bs_write_float(bs, b); /*gf_bs_write_float(bs, q);*/ } gf_bs_align(bs); gf_bs_get_content(bs, &buf, &buf_size); gf_bs_del(bs); dr->DispatchFrame(dr, (u8*)buf, buf_size); gf_free(buf); gf_mx_v(rc->mx); }
static Bool gf_sr_on_event_ex(GF_Renderer *sr , GF_Event *event, Bool from_user) { /*not assigned yet*/ if (!sr || !sr->visual_renderer) return 0; /*we're reconfiguring the video output, cancel all messages*/ if (sr->msg_type & GF_SR_IN_RECONFIG) return 0; switch (event->type) { case GF_EVENT_REFRESH: if (!sr->draw_next_frame) sr->draw_next_frame = 2; break; case GF_EVENT_VIDEO_SETUP: gf_sr_reset_graphics(sr); break; case GF_EVENT_SIZE: /*resize message from plugin: if we own the output, resize*/ if (!sr->user->os_window_handler) { /*EXTRA CARE HERE: the caller (video output) is likely a different thread than the renderer one, and the renderer may be locked on the video output (flush or whatever)!! */ Bool lock_ok = gf_mx_try_lock(sr->mx); sr->new_width = event->size.width; sr->new_height = event->size.height; sr->msg_type |= GF_SR_CFG_SET_SIZE; if (lock_ok) gf_sr_lock(sr, 0); } /*otherwise let the user decide*/ else { GF_USER_SENDEVENT(sr->user, event); } break; case GF_EVENT_KEYDOWN: case GF_EVENT_KEYUP: switch (event->key.key_code) { case GF_KEY_SHIFT: if (event->type==GF_EVENT_KEYDOWN) { sr->key_states |= GF_KEY_MOD_SHIFT; } else { sr->key_states &= ~GF_KEY_MOD_SHIFT; } break; case GF_KEY_CONTROL: if (event->type==GF_EVENT_KEYDOWN) { sr->key_states |= GF_KEY_MOD_CTRL; } else { sr->key_states &= ~GF_KEY_MOD_CTRL; } break; case GF_KEY_ALT: if (event->type==GF_EVENT_KEYDOWN) { sr->key_states |= GF_KEY_MOD_ALT; } else { sr->key_states &= ~GF_KEY_MOD_ALT; } break; } event->key.flags |= sr->key_states; /*key sensor*/ if (sr->term && (sr->interaction_level & GF_INTERACT_INPUT_SENSOR) ) { gf_term_keyboard_input(sr->term, event->key.key_code, event->key.hw_code, (event->type==GF_EVENT_KEYUP) ? 1 : 0); } return SR_UserInputIntern(sr, event, from_user); case GF_EVENT_TEXTINPUT: if (sr->term && (sr->interaction_level & GF_INTERACT_INPUT_SENSOR) ) gf_term_string_input(sr->term , event->character.unicode_char); return SR_UserInputIntern(sr, event, from_user); /*switch fullscreen off!!!*/ case GF_EVENT_SHOWHIDE: gf_sr_set_option(sr, GF_OPT_FULLSCREEN, !sr->fullscreen); break; case GF_EVENT_SET_CAPTION: sr->video_out->ProcessEvent(sr->video_out, event); break; case GF_EVENT_MOUSEMOVE: event->mouse.button = 0; case GF_EVENT_MOUSEDOWN: case GF_EVENT_MOUSEUP: case GF_EVENT_MOUSEWHEEL: event->mouse.key_states = sr->key_states; return SR_UserInputIntern(sr, event, from_user); /*when we process events we don't forward them to the user*/ default: GF_USER_SENDEVENT(sr->user, event); break; } return 1; }