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

📄 waveout_palmos.c

📁 大名鼎鼎的CE下播放软件,TCPPMP的源代码!!!2410下可以流畅的解QVGA的H264,MPEG4等格式.
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * * $Id: waveout_palmos.c 623 2006-02-01 13:19:15Z picard $ * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/#include "../common.h"#if defined(TARGET_PALMOS)
#define DRVBUFFER		4096
#define BUFFER_MIN		4*DRVBUFFER
#define BUFFER_MUSIC	65536*8
#define BUFFER_VIDEO	65536
#define VOLLIMIT		(16384-64)
#include "pace.h"
typedef struct waveout_palm
{
	waveout_base Base;
	SndStreamRef Stream;

	sysregs SysRegs;
	void* PCMCopy;
	int CopySpeed;
	bool_t Mute;
	int Volume;
	int PreAmp;
	int Pan;
	bool_t Play;
	bool_t Started;
	fraction Speed;
	fraction SpeedTime;
	
	buffer Buffer;
	bool_t BufferMode;
	int VolumeRamp;
	int BytePerSample; // output bytes per sample
	int BytePerSec; // output bytes per seconds (before speed adjustment)
	int SpeedBytePerSec; // speed adjusted BytePerSec
	int Ratio; //input to output bytepersec (8.8 fixed point)
	int Skip;
	int DrvBufferSize;
	tick_t DrvBufferDelay;
	tick_t BufferTick;
	tick_t Tick;
	int TimeRef;
	int BenchSpeed;
	int BenchLeft;
	bool_t AlwaysClose;
	bool_t Force16Bits;
	int Vol;

	Boolean Native;
	m68kcallback CallBack;

} waveout_palm;

#define WAVEOUT(p) ((waveout_palm*)((char*)(p)-OFS(waveout_palm,Base.Timer)))

static void ManualSleep(int MSec)
{
	int t0 = GetTimeTick();
	int Wait = (GetTimeFreq()*MSec)/1024;
	if (Wait==0) Wait=1;
	while (GetTimeTick()-t0<Wait);
}

static int Stop(waveout_palm* p)
{
	if (p->Started)
	{
		p->Started = 0;
		SndStreamStop(p->Stream);
		ManualSleep(50); // try to make sure callback exited
		if (p->AlwaysClose)
		{
			SndStreamDelete(p->Stream);
			p->Stream = 0;
		}
		p->DrvBufferSize = 0;
		p->DrvBufferDelay = 0;
	}
	return ERR_NONE;
}

static int CreateStream(waveout_palm* p);

static void Start(waveout_palm* p,tick_t CurrTime)
{
	if (p->Play && !p->Started && p->Buffer.WritePos != p->Buffer.ReadPos &&
		(CurrTime<0 || p->BufferTick <= CurrTime+SHOWAHEAD) &&
		(p->Stream || CreateStream(p)==ERR_NONE))
	{
		p->Started = 1;
		SndStreamStart(p->Stream);
	}
}

static int UpdateBufferMode(waveout_palm* p)
{
	int Size;

	if (p->Started)
		return ERR_NONE;

	BufferPack(&p->Buffer,0);

	Size = p->BufferMode ? BUFFER_VIDEO : BUFFER_MUSIC;
	if (Context()->LowMemory)
		Size >>= 1;
	
	if (Size < BUFFER_MIN)
		Size = BUFFER_MIN;
	Size = ALIGN16(Size);

	DisableOutOfMemory();
	for (;Size >= BUFFER_MIN;Size >>= 1)
		if (BufferAlloc(&p->Buffer,Size,1))
		{
			EnableOutOfMemory();
			if (p->Buffer.WritePos >= p->Buffer.Allocated)
				p->Buffer.WritePos = 0;
			return ERR_NONE;
		}

	EnableOutOfMemory();
	ShowOutOfMemory();
	return ERR_OUT_OF_MEMORY;
}

static Err Callback(waveout_palm* p,SndStreamRef Stream,void *Buffer,uint32_t Frames)
{
	// as a general rule we don't call any OS callbacks here, because
	// we only have one emulstate structure and if both threads
	// call an m68k syscall this could mean problems...

	constplanes SrcPlanes;
	planes DstPlanes;
	int SrcLength,DstLength;
	int WritePos,ReadPos,Length,Speed;

	LoadSysRegs(&p->SysRegs);

	Length = Frames * p->BytePerSample;
	DstPlanes[0] = Buffer;

	if (p->Started)
	{
		WritePos = p->Buffer.WritePos;
		ReadPos = p->Buffer.ReadPos;

		if (p->DrvBufferSize != Length)
		{
			//assuming double buffering
			p->DrvBufferSize = Length;
			p->DrvBufferDelay = Scale(2*Length,TICKSPERSEC,p->SpeedBytePerSec); 
		}

		Speed = p->CopySpeed;
		if (Speed <= 0) 
		{
/*			int Middle = p->Buffer.Allocated >> 1;
			int Left = ReadPos - WritePos;
			if (Left<0)
				Left += p->Buffer.Allocated;

			Speed = p->BenchSpeed;
			
			if (Left > Middle && p->BenchLeft < Left)
			{
				Speed -= Left - p->BenchLeft;
				if (Speed < SPEED_ONE/8)
					Speed = SPEED_ONE/8;
			}

			if (Left < Middle && p->BenchLeft > Left)
				Speed -= Left - p->BenchLeft;

			p->BenchSpeed = Speed;
			p->BenchLeft = Left;
*/
			Speed = SPEED_ONE;
		}

		while (Length>0)
		{
			if (WritePos < ReadPos)
				SrcLength = p->Buffer.Allocated - ReadPos;
			else
				SrcLength = WritePos - ReadPos;
			SrcPlanes[0] = p->Buffer.Data + ReadPos;
			DstLength = Length;

			PCMConvert(p->PCMCopy,DstPlanes,SrcPlanes,&DstLength,&SrcLength,Speed,256);

			DstPlanes[0] = (uint8_t*)DstPlanes[0] + DstLength;
			Length -= DstLength;

			ReadPos += SrcLength;
			if (ReadPos == p->Buffer.Allocated)
				ReadPos = 0;

			if (!DstLength)
				break;
		}

		p->Buffer.ReadPos = ReadPos;
	}

	if (Length)
		memset(DstPlanes[0],(p->Base.Output.Format.Audio.Flags & PCM_UNSIGNED)?0x80:0x00,Length);
	
	return errNone;
}

DLLEXPORT unsigned long WaveOutCallBack(const void *emulStateP, void *userData68KP, Call68KFuncType *call68KFuncP)
{
	UInt32 Param[4];
	memcpy(Param,userData68KP,16);
	return Callback((waveout_palm*)SWAP32(Param[0]),(SndStreamRef)SWAP32(Param[1]),
					(void*)SWAP32(Param[2]),SWAP32(Param[3]));
}

static int Process(waveout_palm* p,const packet* Packet,const flowstate* State)
{
	constplanes SrcPlanes;
	planes DstPlanes;
	int Length,SrcLength,DstLength,Left,ReadPos,WritePos;
	
	ReadPos = p->Buffer.ReadPos;
	WritePos = p->Buffer.WritePos;

	if (!Packet)
	{
		if (State->DropLevel)
			++p->Base.Dropped;
		return (!p->Started || !p->Speed.Num || WritePos==ReadPos) ? ERR_NONE : ERR_BUFFER_FULL;
	}

	DstLength = (Packet->Length * p->Ratio + 255) >> 8; // it may give little larger as needed length

	if (DstLength > p->Buffer.Allocated - DRVBUFFER*2)
	{
		++p->Base.Dropped;
		return ERR_NONE; // drop large packets
	}

	// avoid filling the buffer full (it would mean buffer is empty)
	ReadPos -= p->BytePerSample;
	if (ReadPos < 0)
		ReadPos += p->Buffer.Allocated;

	// check if there is enough free space in buffer
	Left = ReadPos - WritePos;
	if (Left<0)
		Left += p->Buffer.Allocated;

	if (DstLength > Left)
	{
		if (!p->Started)
			Start(p,State->CurrTime);

		if (p->Speed.Num)
			return ERR_BUFFER_FULL;

		// in benchmark mode we need the package to 
		// be processed to measure real performance

		WritePos = ReadPos - DstLength;
		WritePos &= ~3; // align to dword (DstLength is just an approx)
		if (WritePos<0)
			WritePos += p->Buffer.Allocated;

		Left = ReadPos - WritePos;
		if (Left<0)
			Left += p->Buffer.Allocated;
	}

	// process packet
	SrcPlanes[0] = Packet->Data[0];
	SrcPlanes[1] = Packet->Data[1];
	Length = Packet->Length;
	p->Base.Total += Length;

	if (Packet->RefTime >= 0)
	{
		int Diff = p->Buffer.Allocated - Left; // bytes already in the buffer (with 100% speed)
		p->BufferTick = Packet->RefTime - Scale(Diff,TICKSPERSEC,p->BytePerSec) - p->DrvBufferDelay;
		if (p->BufferTick < 0)
			p->BufferTick = 0;

		if (p->Started)
		{
			// adjust timer if it's already running
			int Time = GetTimeTick();
			tick_t Tick = Scale(Time-p->TimeRef,p->SpeedTime.Num,p->SpeedTime.Den);
			tick_t Old = p->Tick + Tick;

			// if difference is little then just adjust (because GetTimeTick() is more linear)
			if (abs(Old - p->BufferTick) < TICKSPERSEC/2)
				p->BufferTick = Old + ((p->BufferTick - Old) >> 2);

			p->Tick = p->BufferTick;
			p->TimeRef = Time;
		}
	}

	if (p->Skip)
	{
		SrcLength = min(p->Skip,Length);
		SrcPlanes[0] = (uint8_t*)SrcPlanes[0] + SrcLength;
		SrcPlanes[1] = (uint8_t*)SrcPlanes[1] + SrcLength;
		Length -= SrcLength;
		p->Skip -= SrcLength;
	}

	while (Length>0)
	{
		if (ReadPos < WritePos)
			DstLength = p->Buffer.Allocated - WritePos;
		else
			DstLength = ReadPos - WritePos;
		DstPlanes[0] = p->Buffer.Data + WritePos;
		SrcLength = Length;

		PCMConvert(p->Base.PCM,DstPlanes,SrcPlanes,&DstLength,&SrcLength,SPEED_ONE,p->Vol/4); //volume needed only for lifedrive fix

		if (p->VolumeRamp < RAMPLIMIT)
			p->VolumeRamp = VolumeRamp(p->VolumeRamp,DstPlanes[0],DstLength,&p->Base.Output.Format.Audio);

		SrcPlanes[0] = (uint8_t*)SrcPlanes[0] + SrcLength;
		SrcPlanes[1] = (uint8_t*)SrcPlanes[1] + SrcLength;
		Length -= SrcLength;

		WritePos += DstLength;
		if (WritePos == p->Buffer.Allocated)
			WritePos = 0;

		if (!SrcLength) // unaligned input (not supported)
			break;
	}

	p->Buffer.WritePos = WritePos;

	if (Length>0 && p->Base.Input.Format.Audio.BlockAlign>0)
		p->Skip = p->Base.Input.Format.Audio.BlockAlign - Length % p->Base.Input.Format.Audio.BlockAlign;

	if (!p->Started)
		Start(p,State->CurrTime);

	return ERR_NONE;
}

static int Flush(waveout_palm* p)
{
	Stop(p);
	p->Skip = 0;
	p->VolumeRamp = 0;

⌨️ 快捷键说明

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