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 Fixed gf_audio_input_get_speed(void *callback) { GF_AudioInput *ai = (GF_AudioInput *) callback; return gf_mo_get_current_speed(ai->stream); }
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; }