static char *gf_audio_input_fetch_frame(void *callback, u32 *size, u32 audio_delay_ms) { char *frame; u32 obj_time, ts; s32 drift; Fixed speed; GF_AudioInput *ai = (GF_AudioInput *) callback; /*even if the stream is signaled as finished we must check it, because it may have been restarted by a mediaControl*/ if (!ai->stream) return NULL; frame = gf_mo_fetch_data(ai->stream, 0, &ai->stream_finished, &ts, size, NULL, NULL); /*invalidate scene on end of stream to refresh audio graph*/ if (ai->stream_finished) gf_sc_invalidate(ai->compositor, NULL); /*no more data or not enough data, reset syncro drift*/ if (!frame) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] No data in audio object (eos %d)\n", ai->stream_finished)); gf_mo_adjust_clock(ai->stream, 0); *size = 0; return NULL; } ai->need_release = 1; speed = gf_mo_get_current_speed(ai->stream); gf_mo_get_object_time(ai->stream, &obj_time); obj_time += audio_delay_ms; drift = (s32)obj_time; drift -= (s32)ts; #ifdef ENABLE_EARLY_FRAME_DETECTION /*too early (silence insertions), skip*/ if (drift < 0) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] audio too early of %d (CTS %u at OTB %u with audio delay %d ms)\n", drift + audio_delay_ms, ts, obj_time, audio_delay_ms)); ai->need_release = 0; gf_mo_release_data(ai->stream, 0, 0); *size = 0; return NULL; } #endif /*adjust drift*/ if (audio_delay_ms) { s32 resync_delay = FIX2INT(speed * MAX_RESYNC_TIME); /*CU is way too late, discard and fetch a new one - this usually happen when media speed is more than 1*/ if (drift>resync_delay) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] Audio data too late obj time %d - CTS %d - drift %d ms - resync forced\n", obj_time - audio_delay_ms, ts, drift)); gf_mo_release_data(ai->stream, *size, 2); ai->need_release = 0; return gf_audio_input_fetch_frame(callback, size, audio_delay_ms); } GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[Audio Input] Audio clock: delay %d - obj time %d - CTS %d - adjust drift %d\n", audio_delay_ms, obj_time - audio_delay_ms, ts, drift)); gf_mo_adjust_clock(ai->stream, drift); } return frame; }
static void gf_audio_input_release_frame(void *callback, u32 nb_bytes) { GF_AudioInput *ai = (GF_AudioInput *) callback; if (!ai->stream) return; gf_mo_release_data(ai->stream, nb_bytes, 1); ai->need_release = 0; }
static void gf_audio_input_release_frame(void *callback, u32 nb_bytes) { GF_AudioInput *ai = (GF_AudioInput *) callback; if (!ai->stream) return; gf_mo_release_data(ai->stream, nb_bytes, 1); ai->need_release = 0; /*as soon as we have released a frame for this audio stream, update resync tolerance*/ ai->is_open = MIN_RESYNC_TIME; }
GF_EXPORT void gf_sc_audio_restart(GF_AudioInput *ai) { if (!ai->is_open) return; if (ai->need_release) gf_mo_release_data(ai->stream, 0xFFFFFFFF, 2); ai->need_release = 0; ai->stream_finished = 0; if (ai->filter) gf_af_reset(ai->filter); gf_mo_restart(ai->stream); }
GF_EXPORT void gf_sc_texture_release_stream(GF_TextureHandler *txh) { if (txh->needs_release) { assert(txh->stream); gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); txh->needs_release = 0; } txh->needs_refresh = 0; }
GF_EXPORT void gf_sc_texture_stop(GF_TextureHandler *txh) { if (!txh->is_open) return; /*release texture WITHOUT droping frame*/ if (txh->needs_release) { gf_mo_release_data(txh->stream, 0xFFFFFFFF, -1); txh->needs_release = 0; } gf_sc_invalidate(txh->compositor, NULL); if (gf_mo_stop(txh->stream)) { txh->data = NULL; } txh->is_open = 0; /*and deassociate object*/ gf_mo_unregister(txh->owner, txh->stream); txh->stream = NULL; }
GF_EXPORT void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) { Bool needs_reload = 0; u32 size, ts; s32 ms_until_pres, ms_until_next; /*already refreshed*/ if (txh->needs_refresh) return; if (!txh->stream) { txh->data = NULL; return; } /*should never happen!!*/ if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); /*check init flag*/ if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { needs_reload = 1; txh->data = NULL; if (txh->tx_io) { gf_sc_texture_release(txh); } } txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next); if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { needs_reload = 1; } else if (size && txh->size && (size != txh->size)) { needs_reload = 1; } if (needs_reload) { /*if we had a texture this means the object has changed - delete texture and resetup. Do not skip texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/ if (txh->tx_io) { gf_sc_texture_release(txh); txh->needs_refresh = 1; } if (gf_mo_is_private_media(txh->stream)) { setup_texture_object(txh, 1); gf_node_dirty_set(txh->owner, 0, 0); } } /*if no frame or muted don't draw*/ if (!txh->data || !size) { GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("|Visual Texture] No output frame available \n")); /*TODO - check if this is needed */ if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { //txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); } return; } /*if setup and same frame return*/ if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) { gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); txh->needs_release = 0; if (!txh->stream_finished) { if (ms_until_next>0 && (txh->compositor->next_frame_delay > (u32) ms_until_next)) txh->compositor->next_frame_delay = ms_until_next; } return; } txh->needs_release = 1; txh->last_frame_time = ts; txh->size = size; if (txh->raw_memory) { gf_mo_get_raw_image_planes(txh->stream, (u8 **) &txh->data, (u8 **) &txh->pU, (u8 **) &txh->pV); } if (gf_mo_is_muted(txh->stream)) return; if (txh->nb_frames) { s32 push_delay = txh->upload_time / txh->nb_frames; if (push_delay > ms_until_pres) ms_until_pres = 0; else ms_until_pres -= push_delay; } if (txh->compositor->frame_delay < ms_until_pres) txh->compositor->frame_delay = ms_until_pres; txh->compositor->next_frame_delay = 1; if (!txh->tx_io) { setup_texture_object(txh, 0); } /*try to push texture on graphics but don't complain if failure*/ gf_sc_texture_set_data(txh); txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); }
GF_EXPORT void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) { u32 size, ts; /*already refreshed*/ if (txh->needs_refresh) return; if (!txh->stream) { txh->data = NULL; return; } /*should never happen!!*/ if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); /*check init flag*/ if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { /*if we had a texture this means the object has changed - delete texture and force next frame composition (this will take care of OD reuse)*/ if (txh->tx_io) { gf_sc_texture_release(txh); txh->data = NULL; txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); return; } if (gf_mo_is_private_media(txh->stream)) { setup_texture_object(txh, 1); gf_node_dirty_set(txh->owner, 0, 0); } } txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size); /*if no frame or muted don't draw*/ if (!txh->data || !size) { /*TODO - check if this is needed */ if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { //txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); } return; } /*if setup and same frame return*/ if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) { gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); txh->needs_release = 0; return; } txh->needs_release = 1; txh->last_frame_time = ts; if (gf_mo_is_muted(txh->stream)) return; if (!txh->tx_io) { setup_texture_object(txh, 0); } /*try to push texture on graphics but don't complain if failure*/ gf_sc_texture_set_data(txh); txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); }
GF_EXPORT void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) { u32 size, ts; /*already refreshed*/ if (txh->needs_refresh) return; if (!txh->stream) { txh->data = NULL; return; } /*should never happen!!*/ if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); /*check init flag*/ if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { /*if we had a texture this means the object has changed - delete texture and resetup. Do not skip texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/ if (txh->tx_io) { gf_sc_texture_release(txh); txh->data = NULL; txh->needs_refresh = 1; } if (gf_mo_is_private_media(txh->stream)) { setup_texture_object(txh, 1); gf_node_dirty_set(txh->owner, 0, 0); } } txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size); /*if no frame or muted don't draw*/ if (!txh->data || !size) { GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("No output frame available\n")); /*TODO - check if this is needed */ if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { //txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); } return; } /*if setup and same frame return*/ if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) { gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); txh->needs_release = 0; return; } txh->needs_release = 1; txh->last_frame_time = ts; if (gf_mo_is_muted(txh->stream)) return; if (!txh->tx_io) { setup_texture_object(txh, 0); } /*try to push texture on graphics but don't complain if failure*/ gf_sc_texture_set_data(txh); txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); }
static char *gf_audio_input_fetch_frame(void *callback, u32 *size, u32 audio_delay_ms) { char *frame; u32 obj_time, ts; s32 drift; Fixed speed; Bool done; GF_AudioInput *ai = (GF_AudioInput *) callback; /*even if the stream is signaled as finished we must check it, because it may have been restarted by a mediaControl*/ if (!ai->stream) return NULL; done = ai->stream_finished; frame = gf_mo_fetch_data(ai->stream, ai->compositor->audio_renderer->step_mode ? GF_MO_FETCH_PAUSED : GF_MO_FETCH, &ai->stream_finished, &ts, size, NULL, NULL); /*invalidate scene on end of stream to refresh audio graph*/ if (done != ai->stream_finished) { gf_sc_invalidate(ai->compositor, NULL); } /*no more data or not enough data, reset syncro drift*/ if (!frame) { if (!ai->stream_finished) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] No data in audio object\n")); } gf_mo_adjust_clock(ai->stream, 0); *size = 0; return NULL; } ai->need_release = GF_TRUE; //step mode, return the frame without sync check if (ai->compositor->audio_renderer->step_mode) return frame; speed = gf_mo_get_current_speed(ai->stream); gf_mo_get_object_time(ai->stream, &obj_time); obj_time += audio_delay_ms; if (ai->compositor->bench_mode) { drift = 0; } else { drift = (s32)obj_time; drift -= (s32)ts; } #ifdef ENABLE_EARLY_FRAME_DETECTION /*too early (silence insertions), skip*/ if (drift < 0) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] audio too early of %d (CTS %u at OTB %u with audio delay %d ms)\n", drift + audio_delay_ms, ts, obj_time, audio_delay_ms)); ai->need_release = GF_FALSE; gf_mo_release_data(ai->stream, 0, -1); *size = 0; return NULL; } #endif /*adjust drift*/ if (audio_delay_ms) { s32 resync_delay = speed > 0 ? FIX2INT(speed * MAX_RESYNC_TIME) : FIX2INT(-speed * MAX_RESYNC_TIME); /*CU is way too late, discard and fetch a new one - this usually happen when media speed is more than 1*/ if (drift>resync_delay) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] Audio data too late obj time %d - CTS %d - drift %d ms - resync forced\n", obj_time - audio_delay_ms, ts, drift)); gf_mo_release_data(ai->stream, *size, 2); ai->need_release = GF_FALSE; return gf_audio_input_fetch_frame(callback, size, audio_delay_ms); } resync_delay = gf_mo_get_clock_drift(ai->stream) - drift; if (resync_delay < 0) resync_delay = -resync_delay; if (resync_delay > MIN_DRIFT_ADJUST) { GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[Audio Input] Audio clock: delay %d - obj time %d - audio delay %d - CTS %d - adjust drift %d\n", audio_delay_ms, obj_time, audio_delay_ms, ts, drift)); gf_mo_adjust_clock(ai->stream, drift); } } return frame; }