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

📄 waveout_win32.c

📁 大名鼎鼎的CE下播放软件,TCPPMP的源代码!!!2410下可以流畅的解QVGA的H264,MPEG4等格式.
💻 C
📖 第 1 页 / 共 2 页
字号:
    }
}

static int UpdatePCM(waveout* p,const audio* InputFormat)
{
	p->SpeedTime = p->Speed;
	p->SpeedTime.Num *= TICKSPERSEC;
	p->SpeedTime.Den *= GetTimeFreq();

	p->BufferScaledTime = Scale(TICKSPERSEC,p->Speed.Num*p->BufferLength,p->Speed.Den*p->Format.nAvgBytesPerSec);
	if (p->BufferLength)
		p->BufferScaledAdjust = (p->BufferScaledTime*4096) / p->BufferLength;
	else
		p->BufferScaledAdjust = 0;
	if (!p->Speed.Num)
		p->PCMSpeed = SPEED_ONE;
	else
		p->PCMSpeed = Scale(SPEED_ONE,p->Speed.Num,p->Speed.Den);
	p->AdjustedRate = Scale(p->Output.Format.Audio.SampleRate,p->Speed.Den,p->Speed.Num);

	PCMRelease(p->PCM);
	p->PCM = PCMCreate(&p->Output.Format.Audio,InputFormat,p->Dither,p->SoftwareVolume || p->PreAmp);
	return ERR_NONE;
}

static int UpdateBufferTime(waveout* p)
{
	p->BufferLimit = Scale(p->BufferMode?BUFFER_VIDEO:BUFFER_MUSIC,p->Format.nAvgBytesPerSec,p->BufferLength*TICKSPERSEC);
	p->BufferLimitFull = p->BufferLimit;
	return ERR_NONE;
}

static int Process(waveout* p,const packet* Packet,const flowstate* State)
{
	if (!Packet)
	{
		if (State->DropLevel)
			++p->Dropped;
		else
			Write(p,State->CurrTime);
		return (p->Waiting<=0 || p->Speed.Num==0) ? ERR_NONE : ERR_BUFFER_FULL;
	}

	if (p->Speed.Num==0) // benchmark mode (auto adjust speed)
	{
		int Pos = p->BenchWaitPos;
		int OldSum;
		int Speed;

		if (p->Play)
		{
			while (Packet->Length > p->BenchAvgLimit)
				UpdateBenchAvg(p);

			p->BenchCurrSum -= p->BenchWait[Pos];
			p->BenchWait[Pos] = (p->Waiting * p->BufferLength) >> 12;
			p->BenchCurrSum += p->BenchWait[Pos];

			OldSum = p->BenchSum[Pos];
			p->BenchSum[Pos] = p->BenchCurrSum;

			if (++Pos == BENCH_SIZE)
				Pos = 0;

			p->BenchWaitPos = Pos;

			if (p->BenchCurrSum < 2*BENCH_SIZE*p->BenchAvg)
				Speed = (p->BenchCurrSum+1) * p->BenchSpeedAvg;
			else
				Speed = 2*SPEED_ONE+(p->BenchCurrSum-2*BENCH_SIZE*p->BenchAvg+1) * 4*p->BenchSpeedAvg;

			Speed -= p->BenchAdj*(p->BenchCurrSum - OldSum);

			if (p->Waiting < 3)
				Speed -= SPEED_ONE/5;
		}
		else
			Speed = SPEED_ONE;

		//DEBUG_MSG3(-1,T("Audio speed:%d length:%d (wait:%d)"),Speed,Packet->Length,p->Waiting);
		return Send(p,Packet->Data,Packet->Length,Packet->RefTime,State->CurrTime,Speed);
	}

	if (State->DropLevel)
		return ERR_NONE;

	if (p->Used >= p->BufferLimit)
	{
		Write(p,State->CurrTime);
		return ERR_BUFFER_FULL;
	}

	DEBUG_MSG3(DEBUG_AUDIO,T("Waveout reftime:%d used:%d waiting:%d"),Packet->RefTime,p->Used,p->Waiting);
	return Send(p,Packet->Data,Packet->Length,Packet->RefTime,State->CurrTime,p->PCMSpeed);
}

static bool_t FreeBuffers(waveout* p);

static int UpdateInput(waveout* p)
{
	Reset(p);
	FreeBuffers(p);

	if (p->Handle)
	{
		waveOutClose(p->Handle);
		p->Handle = NULL;
	}
	p->Total = 0;
	p->Dropped = 0;
	p->Process = DummyProcess;

	if (p->Input.Type == PACKET_AUDIO)
	{
		MMRESULT MMResult;
		int Try;

		if (p->Input.Format.Audio.Format != AUDIOFMT_PCM) 
		{
			PacketFormatClear(&p->Input);
			return ERR_INVALID_DATA;
		}

		if (p->Input.Format.Audio.Channels == 0 ||
			p->Input.Format.Audio.SampleRate == 0)
			return ERR_NONE; // probably initialized later

		p->Output.Type = PACKET_AUDIO;
		p->Output.Format.Audio = p->Input.Format.Audio;
		p->Output.Format.Audio.Flags = 0;
		p->Dither = 0;

		if (p->Stereo==STEREO_SWAPPED)
			p->Output.Format.Audio.Flags |= PCM_SWAPPEDSTEREO;
		else
		if (p->Stereo!=STEREO_NORMAL)
		{
			p->Output.Format.Audio.Channels = 1;
			if (p->Stereo==STEREO_LEFT)
				p->Output.Format.Audio.Flags |= PCM_ONLY_LEFT;
			if (p->Stereo==STEREO_RIGHT)
				p->Output.Format.Audio.Flags |= PCM_ONLY_RIGHT;
		}

		switch (p->Quality)
		{
		case 0: // low quality for very poor devices
			p->Output.Format.Audio.Bits = 8;
			p->Output.Format.Audio.FracBits = 7;
			p->Output.Format.Audio.Channels = 1;
			p->Output.Format.Audio.SampleRate = 22050;
			break;

		case 1: // no dither and only standard samplerate
			p->Output.Format.Audio.Bits = 16;
			p->Output.Format.Audio.FracBits = 15;
			if (p->Output.Format.Audio.SampleRate >= 44100)
				p->Output.Format.Audio.SampleRate = 44100;
			else
				p->Output.Format.Audio.SampleRate = 22050;
			break;

		default:
		case 2: // original samplerate 
			p->Output.Format.Audio.Bits = 16;
			p->Output.Format.Audio.FracBits = 15;
			p->Dither = 1;
			break;
		}

		Try = 0;
		do
		{
			if (p->Output.Format.Audio.Bits <= 8)
				p->Output.Format.Audio.Flags |= PCM_UNSIGNED;

			p->Format.wFormatTag = WAVE_FORMAT_PCM;
			p->Format.nChannels = (WORD)p->Output.Format.Audio.Channels;
			p->Format.nSamplesPerSec = p->Output.Format.Audio.SampleRate;
			p->Format.wBitsPerSample = (WORD)p->Output.Format.Audio.Bits;
			p->Format.nBlockAlign = (WORD)((p->Format.nChannels * p->Format.wBitsPerSample) >> 3);
			p->Format.nAvgBytesPerSec = p->Format.nSamplesPerSec * p->Format.nBlockAlign;
			p->Format.cbSize = 0;

			MMResult = waveOutOpen(&p->Handle, WAVE_MAPPER, &p->Format,(DWORD)WaveProc,
									(DWORD)p,CALLBACK_FUNCTION);

			if (MMResult==WAVERR_BADFORMAT)
			{
				++Try;
				if (Try==1)
				{
					if (p->Output.Format.Audio.SampleRate > 35000)
						p->Output.Format.Audio.SampleRate = 44100;
					else
						++Try;
				}
				if (Try==2)
				{
					if (p->Output.Format.Audio.SampleRate != 22050)
						p->Output.Format.Audio.SampleRate = 22050;
					else
						++Try;
				}
				if (Try==3)
				{
					if (p->Output.Format.Audio.Channels > 1)
						p->Output.Format.Audio.Channels = 1;
					else
						++Try;
				}
				if (Try==4)
				{
					if (p->Output.Format.Audio.Bits != 8)
					{
						p->Output.Format.Audio.Bits = 8;
						p->Output.Format.Audio.FracBits = 7;
					}
					else
						++Try;
				}
				if (Try==5)
					break;
			}
		}
		while (MMResult==WAVERR_BADFORMAT);

		if (p->Handle)
		{
			p->Process = Process;
			p->TimeRef = GetTimeTick();
			p->BufferLength = 4096;
			if (p->Format.nAvgBytesPerSec > 65536)
				p->BufferLength *= 2;
			if (p->Format.nAvgBytesPerSec > 2*65536)
				p->BufferLength *= 2;
			UpdateBufferTime(p);
		
			p->FillPos = p->BufferLength;
			p->VolumeRamp = 0;

			UpdatePCM(p,&p->Input.Format.Audio);
			Reset(p);
		}
		else
		{
			PacketFormatClear(&p->Input);
			ShowError(p->Node.Class,ERR_ID,ERR_DEVICE_ERROR);
			return ERR_DEVICE_ERROR;
		}
	}
	else
	if (p->Input.Type != PACKET_NONE)
		return ERR_INVALID_DATA;
		
	return ERR_NONE;
}

static int Update(waveout* p)
{
	wavebuffer *OldFirst;
	wavebuffer *OldLast;
	audio OldFormat;
	wavebuffer* OldBuffers;
	wavebuffer* OldFill;
	int OldFillPos; 
	int OldUsed;
	bool_t OldVolume;
	int OldPreAmp;
	wavebuffer *Buffer,*Next;

	EnterCriticalSection(&p->Section);

	OldVolume = p->SoftwareVolume;
	OldPreAmp = p->PreAmp;
	OldUsed = p->Used;
	OldFirst = p->FreeFirst;
	OldLast = p->FreeLast;
	OldFormat = p->Output.Format.Audio;
	OldFormat.SampleRate = p->AdjustedRate;

	OldFill = p->FillFirst;
	OldFillPos = p->FillPos;

	p->FillFirst = NULL;
	p->FillLast = NULL;
	p->FillPos = p->BufferLength;
	p->FreeFirst = NULL;
	p->FreeLast = NULL;

	LeaveCriticalSection(&p->Section);

	Reset(p);

	OldBuffers = p->FreeFirst;
	if (p->FreeLast)
		p->FreeLast->Next = OldFill;
	else
		OldBuffers = OldFill;

	if (OldBuffers)
		p->FillLastTime = OldBuffers->EstRefTime - p->BufferScaledTime;

	p->PreAmp = 0;
	p->SoftwareVolume = 0;
	p->Used = OldUsed;
	p->FreeFirst = OldFirst;
	p->FreeLast = OldLast;

	// setup temporary format
	UpdatePCM(p,&OldFormat);

	for (Buffer=OldBuffers;Buffer;Buffer=Next)
	{
		Next = Buffer->Next;
		Send(p,Buffer->Planes,Next ? p->BufferLength:OldFillPos,Buffer->RefTime,-1,p->PCMSpeed);
		ReleaseBuffer(p,Buffer,0);
	}

	p->SoftwareVolume = OldVolume;
	p->PreAmp = OldPreAmp;
	UpdatePCM(p,&p->Input.Format.Audio);
	return ERR_NONE;
}

static bool_t FreeBuffers(waveout* p)
{
	wavebuffer** Ptr;
	wavebuffer* Buffer;
	bool_t Changed = 0;

	while (p->FreeFirst)
	{
		Buffer = p->FreeFirst;
		p->FreeFirst = Buffer->Next;

		// remove from global chain
		Ptr = &p->Buffers;
		while (*Ptr && *Ptr != Buffer)
			Ptr = &(*Ptr)->GlobalNext;
		if (*Ptr == Buffer)
			*Ptr = Buffer->Next;

		waveOutUnprepareHeader(p->Handle, &Buffer->Head, sizeof(WAVEHDR));
		FreeBlock(&Buffer->Block);
		free(Buffer);
		Changed = 1;
	}
	p->FreeLast = NULL;

	return Changed;
}

static int Hibernate(waveout* p,int Mode)
{
	bool_t Changed = 0;

	EnterCriticalSection(&p->Section);
	Changed = FreeBuffers(p);
	LeaveCriticalSection(&p->Section);

	return Changed ? ERR_NONE : ERR_OUT_OF_MEMORY;
}

static void Pause(waveout* p)
{
	p->Pausing = &p->FillFirst;
	waveOutReset(p->Handle);
	p->Pausing = NULL;
	p->FillLast = p->FillFirst;
	if (p->FillLast)
		while (p->FillLast->Next) p->FillLast = p->FillLast->Next;
}

static int UpdatePlay(waveout* p)
{
	if (p->Play)
	{
		p->TimeRef = GetTimeTick();
		if (p->Handle)
			Write(p,p->Tick);
	}
	else
	{
		if (!p->Waiting)
			p->Tick += Scale(GetTimeTick()-p->TimeRef,p->SpeedTime.Num,p->SpeedTime.Den);
		else
		if (p->Handle)
			Pause(p);
	}
	return ERR_NONE;
}

static int SetVolumeDev(waveout* p,int v)
{
	p->VolumeDev = v;
	if (p->Mute)
		waveOutSetVolume(NULL,0);
	else
		waveOutSetVolume(NULL,0x10001 * ((0xFFFF * p->VolumeDev) / 100));
	return ERR_NONE;
}

static int TimerSet(void* pt, int No, const void* Data, int Size)
{
	waveout* p = WAVEOUT(pt);
	int Result = ERR_INVALID_PARAM;
	switch (No)
	{
	case TIMER_PLAY: SETVALUECMP(p->Play,bool_t,UpdatePlay(p),EqBool); break;
	case TIMER_SPEED: SETVALUECMP(p->Speed,fraction,Update(p),EqFrac); break;
	case TIMER_TIME:
		assert(Size == sizeof(tick_t));
		EnterCriticalSection(&p->Section);
		p->Tick = *(tick_t*)Data;
		p->TimeRef = GetTimeTick();
		LeaveCriticalSection(&p->Section);
		Result = ERR_NONE;
		break;
	}
	return Result;
}

static void UpdateSoftwareVolume(waveout* p)
{
	bool_t SoftwareVolume = !QueryAdvanced(ADVANCED_SYSTEMVOLUME);
	if (SoftwareVolume != p->SoftwareVolume)
	{
		p->SoftwareVolume = SoftwareVolume;
		SetVolumeSoft(p,p->VolumeSoft,p->Mute);
		if (p->Handle)
			UpdatePCM(p,&p->Input.Format.Audio);
	}
}

static int UpdatePreAmp(waveout* p)
{
	SetVolumeSoft(p,p->VolumeSoft,p->Mute);
	if (p->Handle)
		UpdatePCM(p,&p->Input.Format.Audio);
	return ERR_NONE;
}

static int Set(waveout* p, int No, const void* Data, int Size)
{
	int Result = ERR_INVALID_PARAM;
	switch (No)
	{
	case OUT_INPUT|PIN_FORMAT: 
		if (PacketFormatSimilarAudio(&p->Input,(const packetformat*)Data))
		{
			PacketFormatCopy(&p->Input,(const packetformat*)Data);
			Result = UpdatePCM(p,&p->Input.Format.Audio);
		}
		else
			SETPACKETFORMATCMP(p->Input,packetformat,UpdateInput(p)); 
		break;
	case OUT_INPUT: SETVALUE(p->Pin,pin,ERR_NONE); break;
	case OUT_TOTAL: SETVALUE(p->Total,int,ERR_NONE); break;
	case OUT_DROPPED: SETVALUE(p->Dropped,int,ERR_NONE); break;

	case AOUT_VOLUME: 
		assert(Size==sizeof(int));
		UpdateSoftwareVolume(p);
		if (p->SoftwareVolume)
			Result = SetVolumeSoft(p,*(int*)Data,p->Mute);
		else
			Result = SetVolumeDev(p,*(int*)Data);
		break;

	case AOUT_PREAMP: SETVALUECMP(p->PreAmp,int,UpdatePreAmp(p),EqInt); break; 

	case AOUT_MUTE:
		assert(Size==sizeof(bool_t));
		UpdateSoftwareVolume(p);
		if (p->SoftwareVolume)
			Result = SetVolumeSoft(p,p->VolumeSoft,*(bool_t*)Data);
		else
		{
			if (!p->Mute) GetVolume(p); // save old volume to p->VolumeDev
			p->Mute = *(bool_t*)Data;
			Result = SetVolumeDev(p,p->VolumeDev);
		}
		break;

	case AOUT_STEREO: SETVALUECMP(p->Stereo,int,UpdateInput(p),EqInt); break; 
	case AOUT_QUALITY: SETVALUECMP(p->Quality,int,UpdateInput(p),EqInt); break; 
	case AOUT_MODE: SETVALUE(p->BufferMode,bool_t,UpdateBufferTime(p)); break;

	case FLOW_FLUSH:
		Reset(p);
		p->FillLastTime = TIME_UNKNOWN;
		p->VolumeRamp = 0;
		Result = ERR_NONE;
		break;

	case NODE_SETTINGSCHANGED:
		p->ForcePriority = QueryAdvanced(ADVANCED_WAVEOUTPRIORITY);
		break;

	case NODE_HIBERNATE:
		assert(Size == sizeof(int));
		Result = Hibernate(p,*(int*)Data);
		break;
	}
	return Result;
}

static int Create(waveout* p)
{
	WAVEOUTCAPS Caps;

	if (waveOutGetNumDevs()==0)
		return ERR_NOT_SUPPORTED;

	waveOutGetDevCaps(WAVE_MAPPER,&Caps,sizeof(Caps));

	p->Node.Get = (nodeget)Get;
	p->Node.Set = (nodeset)Set;

	p->Timer.Class = TIMER_CLASS;
	p->Timer.Enum = TimerEnum;
	p->Timer.Get = TimerGet;
	p->Timer.Set = TimerSet;

	p->VolumeDev = 70; //default when device is muted
	p->VolumeSoftLog = 256;
	p->Quality = 2;
	p->Speed.Den = p->Speed.Num = 1;
	p->SpeedTime.Num = TICKSPERSEC;
	p->SpeedTime.Den = GetTimeFreq();
	p->MonoVol = (Caps.dwSupport & WAVECAPS_LRVOLUME) == 0;

	InitializeCriticalSection(&p->Section);
	return ERR_NONE;
}

static void Delete(waveout* p)
{
	PacketFormatClear(&p->Input);
	PCMRelease(p->PCM);
	DeleteCriticalSection(&p->Section);
}

static const nodedef WaveOut =
{
	sizeof(waveout)|CF_GLOBAL,
	WAVEOUT_ID,
	AOUT_CLASS,
	PRI_DEFAULT,
	(nodecreate)Create,
	(nodedelete)Delete,
};

void WaveOut_Init()
{
	NodeRegisterClass(&WaveOut);
}

void WaveOut_Done()
{
	NodeUnRegisterClass(WAVEOUT_ID);
}

#endif

⌨️ 快捷键说明

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