void MC_Modified(GF_Node *node) { MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node); if (!stack) return; if (stack->changed!=2) { /*check URL*/ if (MC_URLChanged(&stack->url, &stack->control->url)) stack->changed = 2; /*check speed (play/pause)*/ else if (stack->media_speed != stack->control->mediaSpeed) stack->changed = 1; /*check mediaStartTime (seek)*/ else if (stack->media_start != stack->control->mediaStartTime) { /*do not reevaluate if mediaStartTime is reset to -1 (current time)*/ if (stack->control->mediaStartTime!=-1.0) stack->changed = 2; /*check mediaStopTime <0 (timeshift buffer control)*/ } else if (stack->media_stop != stack->control->mediaStopTime) { if (stack->control->mediaStopTime<=0) stack->changed = 2; } // else stack->changed = 1; } gf_node_dirty_set( gf_sg_get_root_node(gf_node_get_graph(node)), 0, 1); /*invalidate scene, we recompute MC state in render*/ gf_term_invalidate_compositor(stack->parent->root_od->term); }
static void gf_inline_check_restart(GF_Scene *scene) { /*no ctrl if no duration*/ if (!scene->duration) return; if (!scene->needs_restart) gf_odm_check_segment_switch(scene->root_od); if (scene->needs_restart) return; if (scene->root_od->media_ctrl && scene->root_od->media_ctrl->control->loop) { GF_Clock *ck = gf_odm_get_media_clock(scene->root_od); if (ck->has_seen_eos) { u32 now = gf_clock_time(ck); u64 dur = scene->duration; if (scene->root_od->media_ctrl->current_seg) { /*only process when all segments are played*/ if (gf_list_count(scene->root_od->media_ctrl->seg) <= scene->root_od->media_ctrl->current_seg) { scene->needs_restart = 1; scene->root_od->media_ctrl->current_seg = 0; } } else { Double s, e; s = now; s/=1000; e = -1; MC_GetRange(scene->root_od->media_ctrl, &s, &e); if ((e>=0) && (e<GF_MAX_FLOAT)) dur = (u32) (e*1000); if (dur<=now) { scene->needs_restart = 1; scene->root_od->media_ctrl->current_seg = 0; } else { /*trigger render until to watch for restart...*/ gf_term_invalidate_compositor(scene->root_od->term); } } } else { /*trigger render until to watch for restart...*/ gf_term_invalidate_compositor(scene->root_od->term); } } }
void gf_cm_unlock_input(GF_CompositionMemory *cb, GF_CMUnit *cu, u32 cu_size, Bool codec_reordering) { /*nothing dispatched, ignore*/ if (!cu_size || (!cu->data && !cu->frame && !cb->pY) ) { if (cu->frame) { cu->frame->Release(cu->frame); cu->frame = NULL; } cu->dataLength = 0; cu->TS = 0; return; } gf_odm_lock(cb->odm, 1); // assert(cu->frame); if (codec_reordering) { cb->input = cb->input->next; } else { cu = gf_cm_reorder_unit(cb, cu, codec_reordering); assert(cu); } if (cu) { /*FIXME - if the CU already has data, this is spatial scalability so same num buffers*/ if (!cu->dataLength) cb->UnitCount += 1; cu->dataLength = cu_size; cu->RenderedLength = 0; /*turn off buffering for audio - this must be done now rather than when fetching first output frame since we're not sure output is fetched (Switch node, ...)*/ if ( (cb->Status == CB_BUFFER) && (cb->UnitCount >= cb->Capacity) ) { /*done with buffering*/ cb->Status = CB_BUFFER_DONE; //for audio, turn off buffering now. For video, we will wait for the first frame to be drawn if (cb->odm->codec->type == GF_STREAM_AUDIO) cb_set_buffer_off(cb); } //new FPS regulation doesn't need this signaling #if 0 /*since a new CU is here notify the compositor*/ if ((cb->odm->codec->type==GF_STREAM_VISUAL) && cb->odm->mo && cb->odm->mo->num_open) { gf_term_invalidate_compositor(cb->odm->term); } #endif } gf_odm_lock(cb->odm, 0); }
/*render : setup media sensor and update timing in case of inline scenes*/ void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy) { GF_Clock *ck; MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node); if (is_destroy) { /*unlink from OD*/ if (st->stream && st->stream->odm) gf_list_del_item(st->stream->odm->ms_stack, st); gf_list_del(st->seg); gf_free(st); return; } if (!st->stream) st->stream = gf_mo_register(node, &st->sensor->url, 0, 0); if (!st->stream || !st->stream->odm) return; if (!st->is_init) { gf_list_add(st->stream->odm->ms_stack, st); gf_odm_init_segments(st->stream->odm, st->seg, &st->sensor->url); st->is_init = 1; st->active_seg = 0; } /*media sensor bound to natural media (audio, video) is updated when fetching the stream data for rendering.*/ ck = NULL; /*check inline scenes - if the scene is set to restart DON'T MODIFY SENSOR: since we need a 2 render passes to restart inline, scene is considered as not running*/ if (st->stream->odm->subscene && !st->stream->odm->subscene->needs_restart) { if (st->stream->odm->subscene->scene_codec) ck = st->stream->odm->subscene->scene_codec->ck; /*dynamic scene*/ else ck = st->stream->odm->subscene->dyn_ck; /*since audio may be used alone through an inline scene, we need to refresh the graph*/ if (ck && !ck->has_seen_eos && st->stream->odm->state) gf_term_invalidate_compositor(st->stream->odm->term); } /*check anim streams*/ else if (st->stream->odm->codec && (st->stream->odm->codec->type==GF_STREAM_SCENE)) ck = st->stream->odm->codec->ck; /*check OCR streams*/ else if (st->stream->odm->ocr_codec) ck = st->stream->odm->ocr_codec->ck; if (ck && gf_clock_is_started(ck) ) { st->stream->odm->current_time = gf_clock_time(ck); mediasensor_update_timing(st->stream->odm, 0); } }
void gf_cm_set_eos(GF_CompositionMemory *cb) { gf_odm_lock(cb->odm, 1); /*we may have a pb if the stream is so short that the EOS is signaled while we're buffering. In this case we shall turn the clock on and keep a trace of the EOS notif*/ if (cb->Status == CB_BUFFER) { cb->Status = CB_BUFFER_DONE; gf_clock_buffer_off(cb->odm->codec->ck); cb->odm->codec->ck->data_timeout = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering)); } cb->HasSeenEOS = 1; gf_term_invalidate_compositor(cb->odm->term); gf_odm_lock(cb->odm, 0); }
void gf_cm_unlock_input(GF_CompositionMemory *cb, GF_CMUnit *cu, u32 cu_size, Bool codec_reordering) { /*nothing dispatched, ignore*/ if (!cu_size) { cu->dataLength = 0; cu->TS = 0; return; } gf_odm_lock(cb->odm, 1); if (cu->TS < cb->input->TS) cu = cu; if (codec_reordering) { cb->input = cb->input->next; } else { cu = gf_cm_reorder_unit(cb, cu, codec_reordering); assert(cu); } if (cu) { /*FIXME - if the CU already has data, this is spatial scalability so same num buffers*/ if (!cu->dataLength) cb->UnitCount += 1; cu->dataLength = cu_size; cu->RenderedLength = 0; /*turn off buffering - this must be done now rather than when fetching first output frame since we're not sure output is fetched (Switch node, ...)*/ if ( (cb->Status == CB_BUFFER) && (cb->UnitCount >= cb->Capacity) ) { /*done with buffering, signal to the clock (ONLY ONCE !)*/ cb->Status = CB_BUFFER_DONE; gf_clock_buffer_off(cb->odm->codec->ck); cb->odm->codec->ck->data_timeout = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering)); gf_term_service_media_event(cb->odm->parentscene->root_od, GF_EVENT_MEDIA_CANPLAY); } /*since a new CU is here notify the compositor*/ if ((cb->odm->codec->type==GF_STREAM_VISUAL) && cb->odm->mo && cb->odm->mo->num_open) { gf_term_invalidate_compositor(cb->odm->term); } } gf_odm_lock(cb->odm, 0); }
static Bool gf_inline_set_scene(M_Inline *root) { GF_MediaObject *mo; GF_Scene *parent; GF_SceneGraph *graph = gf_node_get_graph((GF_Node *) root); parent = (GF_Scene *)gf_sg_get_private(graph); if (!parent) return 0; mo = gf_scene_get_media_object_ex(parent, &root->url, GF_MEDIA_OBJECT_SCENE, 0, NULL, 0, (GF_Node*)root); if (!mo || !mo->odm) return 0; if (!mo->odm->subscene) { gf_term_invalidate_compositor(parent->root_od->term); return 0; } /*assign inline scene as private stack of inline node, and remember inline node for event propagation*/ gf_node_set_private((GF_Node *)root, mo->odm->subscene); /*play*/ gf_mo_play(mo, 0, -1, 0); return 1; }
/*only URL can be changed, so reset and get new URL*/ void MS_Modified(GF_Node *node) { MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node); if (!st) return; while (gf_list_count(st->seg)) gf_list_rem(st->seg, 0); if (st->stream) { /*unlink from OD*/ if (st->stream->odm && st->stream->odm->ms_stack) gf_list_del_item(st->stream->odm->ms_stack, st); gf_mo_unregister(node, st->stream); if (st->sensor->isActive) { st->sensor->isActive = 0; gf_node_event_out((GF_Node *) st->sensor, 4/*"isActive"*/); } } st->stream = NULL; st->is_init = 0; gf_term_invalidate_compositor(st->parent->root_od->term); }
void gf_cm_set_eos(GF_CompositionMemory *cb) { gf_odm_lock(cb->odm, 1); /*we may have a pb if the stream is so short that the EOS is signaled while we're buffering. In this case we shall turn the clock on and keep a trace of the EOS notif*/ if (cb->Status == CB_BUFFER) { cb->Status = CB_BUFFER_DONE; gf_clock_buffer_off(cb->odm->codec->ck); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB EOS - ODM%d: buffering off at OTB %u (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck), gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering)); } cb->HasSeenEOS = 1; //in bench mode eos cannot be signaled through flush of composition memory since it is always empty - do it here if (cb->odm->term->bench_mode==2) { cb->Status = CB_STOP; gf_odm_signal_eos(cb->odm); } gf_term_invalidate_compositor(cb->odm->term); gf_odm_lock(cb->odm, 0); }
void gf_inline_restart(GF_Scene *scene) { scene->needs_restart = 1; gf_term_invalidate_compositor(scene->root_od->term); }
void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy) { Bool shall_restart, need_restart; GF_MediaObject *prev; GF_ObjectManager *odm; GF_TraverseState *tr_state = (GF_TraverseState *)rs; MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node); if (is_destroy) { GF_ObjectManager *odm; MediaControlStack *stack = (MediaControlStack *) gf_node_get_private(node); /*reset ODM using this control*/ if (stack->stream) { if (stack->stream->odm) { odm = stack->stream->odm; gf_odm_remove_mediacontrol(odm, stack); } /*also removes the association ck<->MC if the object has been destroyed before the node*/ if (stack->ck) stack->ck->mc = NULL; } gf_list_del(stack->seg); gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL); gf_free(stack); return; } //we need to disable culling otherwise we may never be called back again ... tr_state->disable_cull = 1; /*not changed nothing to do - note we need to register with stream yet for control switching...*/ if (stack->stream && (!stack->changed || !stack->control->enabled)) return; need_restart = (stack->changed==2) ? 1 : 0; shall_restart = (stack->control->mediaStartTime>=0) ? 1 : 0; /*check url target*/ if (stack->stream) { if (MC_URLChanged(&stack->url, &stack->control->url)) { gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL); prev = stack->stream; if (gf_list_find(stack->parent->scene_objects, prev)<0) prev = NULL; stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0); if (stack->stream) { if (!stack->stream->odm) return; /*MediaControl on inline: if dynamic scene, make sure it is connected before attaching...*/ if (stack->stream->odm->subscene) { if (stack->stream->odm->subscene->is_dynamic_scene && !stack->stream->odm->subscene->dyn_ck) return; } gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL); /*remove from prev*/ if (prev && prev->odm && (prev != stack->stream)) gf_odm_remove_mediacontrol(prev->odm, stack); /*register with new*/ /*if we assigned the media control to an exiting object - force the state of the object*/ gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack); while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0); gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url); stack->current_seg = 0; //do not restart if no mediaStartTime and speed is 1 if ((stack->control->mediaStartTime>0) || gf_list_count(stack->seg) || (stack->control->mediaSpeed != FIX_ONE) ) { shall_restart = need_restart = 1; } else { shall_restart = need_restart = 0; //URL changed, we are by default in PLAY mode. stack->media_speed = 1; } stack->ck = gf_odm_get_media_clock(stack->stream->odm); } /*control has been removed and we were paused, resume*/ else if (stack->paused) { mediacontrol_resume((GF_ObjectManager *) prev->odm, 0); stack->paused = 0; } /*MediaControl has been detached*/ else { if (prev) gf_odm_remove_mediacontrol(prev->odm, stack); return; } } } else { stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0); if (!stack->stream || !stack->stream->odm) { if (stack->control->url.count) gf_term_invalidate_compositor(stack->parent->root_od->term); stack->stream = NULL; stack->changed = 0; return; } stack->ck = gf_odm_get_media_clock(stack->stream->odm); /*OD not ready yet*/ if (!stack->ck) { stack->stream = NULL; if (stack->control->url.count) { stack->is_init = 0; gf_term_invalidate_compositor(stack->parent->root_od->term); } return; } gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL); gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack); while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0); gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url); stack->current_seg = 0; /*we shouldn't have to restart unless start/stop times have been changed, which is tested below*/ need_restart = 0; } if (!stack->changed || !stack->control->enabled || !stack->stream) return; /*if not previously enabled and now enabled, switch all other controls off and reactivate*/ if (!stack->enabled) { stack->enabled = 1; need_restart = gf_odm_switch_mediacontrol(stack->stream->odm, stack); } stack->changed = 0; if (!stack->control->mediaSpeed) shall_restart = 0; odm = (GF_ObjectManager *)stack->stream->odm; /*check for changes*/ if (!stack->is_init) { /*not linked yet*/ if (!odm) return; stack->media_speed = stack->control->mediaSpeed; stack->enabled = stack->control->enabled; stack->media_start = stack->control->mediaStartTime; stack->media_stop = stack->control->mediaStopTime; stack->is_init = 1; stack->paused = 0; /*the object has already been started, and media start time is not 0, restart*/ if (stack->stream->num_open) { if ( (stack->media_start > 0) || (gf_list_count(stack->seg)>0 ) || (stack->media_speed!=FIX_ONE ) ) { mediacontrol_restart(odm); } else if (stack->media_speed == 0) { mediacontrol_pause(odm); stack->paused = 1; } } return; } if (stack->media_speed != stack->control->mediaSpeed) { /*if no speed pause*/ if (!stack->control->mediaSpeed && !stack->paused) { mediacontrol_pause(odm); stack->paused = 1; } /*else resume if paused*/ else if (stack->control->mediaSpeed && stack->paused) { mediacontrol_resume(odm, 0); stack->paused = 0; need_restart += shall_restart; } /*else set speed*/ else if (stack->media_speed && stack->control->mediaSpeed) { /*don't set speed if we have to restart the media ...*/ if (!shall_restart) MC_SetSpeed(odm, stack->control->mediaSpeed); need_restart += shall_restart; } /*init state was paused*/ else if (!stack->media_speed) { need_restart ++; } stack->media_speed = stack->control->mediaSpeed; } /*check start/stop changes*/ if (stack->media_start != stack->control->mediaStartTime) { stack->media_start = stack->control->mediaStartTime; need_restart += shall_restart; } /*stop change triggers restart no matter what (new range) if playing*/ if (stack->media_stop != stack->control->mediaStopTime) { stack->media_stop = stack->control->mediaStopTime; if (stack->control->mediaSpeed) need_restart = 1; } if (need_restart) { mediacontrol_restart(odm); } /*handle preroll*/ }