⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio_input.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / Scene Rendering sub-project * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <gpac/internal/renderer_dev.h>#define MIN_RESYNC_TIME		1000static char *AI_FetchFrame(void *callback, u32 *size, u32 audio_delay_ms){	char *frame;	u32 obj_time, ts;	s32 drift;	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);	/*invalidate scene on end of stream to refresh audio graph*/	if (ai->stream_finished) gf_sr_invalidate(ai->compositor, NULL);	/*no more data or not enough data, reset syncro drift*/	if (!frame) {		GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Audio Render] No data in audio object (eos %d)\n", ai->stream_finished));		gf_mo_adjust_clock(ai->stream, 0);		return NULL;	}	ai->need_release = 1;		gf_mo_get_object_time(ai->stream, &obj_time);	obj_time += audio_delay_ms;	drift = (s32)obj_time;	drift -= (s32)ts;	/*too early (silence insertions), don't render*/	if (drift + (s32) audio_delay_ms + MIN_RESYNC_TIME < 0) {		GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Audio Render] audio too early %d (CTS %d)\n", drift + audio_delay_ms + MIN_RESYNC_TIME, ts));		ai->need_release = 0;		gf_mo_release_data(ai->stream, 0, 0);		return NULL;	}	/*adjust drift*/	if (audio_delay_ms) {		/*CU is way too late, discard and fetch a new one - this usually happen when media speed is more than 1*/		if (drift>500) {			GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Audio Render] Audio data too late (drift %d ms) - resync forced\n", drift));			gf_mo_release_data(ai->stream, *size, 2);			ai->need_release = 0;			return AI_FetchFrame(callback, size, audio_delay_ms);		}		GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Audio Render] 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 AI_ReleaseFrame(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 Fixed AI_GetSpeed(void *callback){	GF_AudioInput *ai = (GF_AudioInput *) callback;	return gf_mo_get_speed(ai->stream, ai->speed);}static Bool AI_GetChannelVolume(void *callback, Fixed *vol){	GF_AudioInput *ai = (GF_AudioInput *) callback;	if (ai->snd && ai->snd->GetChannelVolume) {		return ai->snd->GetChannelVolume(ai->snd->owner, vol);	} else {		vol[0] = vol[1] = vol[2] = vol[3] = vol[4] = vol[5] = ai->intensity;		return (ai->intensity==FIX_ONE) ? 0 : 1;	}}static Bool AI_IsMuted(void *callback){	GF_AudioInput *ai = (GF_AudioInput *) callback;	if (!ai->stream) return 1;	if (ai->is_muted) return 1;	return gf_mo_is_muted(ai->stream);}static Bool AI_GetConfig(GF_AudioInterface *aifc, Bool for_recf){	GF_AudioInput *ai = (GF_AudioInput *) aifc->callback;	if (!ai->stream) return 0;	/*watchout for object reuse*/	if (aifc->sr && (gf_mo_get_flags(ai->stream) & GF_MO_IS_INIT)) return 1;	if (!for_recf) 		return 0;	gf_mo_get_audio_info(ai->stream, &aifc->sr, &aifc->bps , &aifc->chan, &aifc->ch_cfg);	if (aifc->sr * aifc->chan * aifc->bps && ((aifc->chan<=2) || aifc->ch_cfg))  {		gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, 1);		return 1;	}	gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, 0);	return 0;}GF_EXPORTvoid gf_sr_audio_setup(GF_AudioInput *ai, GF_Renderer *sr, GF_Node *node){	memset(ai, 0, sizeof(GF_AudioInput));	ai->owner = node;	ai->compositor = sr;	ai->stream = NULL;	/*setup io interface*/	ai->input_ifce.FetchFrame = AI_FetchFrame;	ai->input_ifce.ReleaseFrame = AI_ReleaseFrame;	ai->input_ifce.GetConfig = AI_GetConfig;	ai->input_ifce.GetChannelVolume = AI_GetChannelVolume;	ai->input_ifce.GetSpeed = AI_GetSpeed;	ai->input_ifce.IsMuted = AI_IsMuted;	ai->input_ifce.callback = ai;	ai->intensity = FIX_ONE;	ai->speed = FIX_ONE;}GF_EXPORTGF_Err gf_sr_audio_open(GF_AudioInput *ai, MFURL *url, Double clipBegin, Double clipEnd){	if (ai->is_open) return GF_BAD_PARAM;	/*get media object*/	ai->stream = gf_mo_find(ai->owner, url, 0);	/*bad URL*/	if (!ai->stream) return GF_NOT_SUPPORTED;	/*store url*/	gf_sg_vrml_field_copy(&ai->url, url, GF_SG_VRML_MFURL);	/*request play*/	gf_mo_play(ai->stream, clipBegin, clipEnd, 0);	ai->stream_finished = 0;	ai->is_open = 1;	gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, 0);	return GF_OK;}GF_EXPORTvoid gf_sr_audio_stop(GF_AudioInput *ai){	if (!ai->is_open) return;		/*we must make sure audio mixer is not using the stream otherwise we may leave it dirty (with unrelease frame)*/	gf_mixer_lock(ai->compositor->audio_renderer->mixer, 1);	assert(!ai->need_release);	gf_mo_stop(ai->stream);	gf_sg_vrml_mf_reset(&ai->url, GF_SG_VRML_MFURL);	ai->is_open = 0;	ai->stream = NULL;	gf_mixer_lock(ai->compositor->audio_renderer->mixer, 0);}GF_EXPORTvoid gf_sr_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;	gf_mo_restart(ai->stream);}GF_EXPORTBool gf_sr_audio_check_url(GF_AudioInput *ai, MFURL *url){	if (!ai->stream) return url->count;	return gf_mo_url_changed(ai->stream, url);}GF_EXPORTvoid gf_sr_audio_register(GF_AudioInput *ai, GF_BaseEffect *eff){	/*check interface is valid*/	if (!ai->input_ifce.FetchFrame		|| !ai->input_ifce.GetChannelVolume		|| !ai->input_ifce.GetConfig		|| !ai->input_ifce.GetSpeed		|| !ai->input_ifce.IsMuted		|| !ai->input_ifce.ReleaseFrame		) return;	if (eff->audio_parent) {		/*this assume only one parent may use an audio node*/		if (ai->register_with_parent) return;		if (ai->register_with_renderer) {			gf_sr_ar_remove_src(ai->compositor->audio_renderer, &ai->input_ifce);			ai->register_with_renderer = 0;		}		eff->audio_parent->add_source(eff->audio_parent, ai);		ai->register_with_parent = 1;		ai->snd = eff->sound_holder;	} else if (!ai->register_with_renderer) {				if (ai->register_with_parent) {			ai->register_with_parent = 0;			/*if used in a parent audio group, do a complete traverse to rebuild the group*/			gf_sr_invalidate(ai->compositor, NULL);		}		gf_sr_ar_add_src(ai->compositor->audio_renderer, &ai->input_ifce);		ai->register_with_renderer = 1;		ai->snd = eff->sound_holder;	}}GF_EXPORTvoid gf_sr_audio_unregister(GF_AudioInput *ai){	if (ai->register_with_renderer) {		ai->register_with_renderer = 0;		gf_sr_ar_remove_src(ai->compositor->audio_renderer, &ai->input_ifce);	} else {		/*if used in a parent audio group, do a complete traverse to rebuild the group*/		gf_sr_invalidate(ai->compositor, NULL);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -