Fplay source code.
git-svn-id: svn://kolibrios.org@1696 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
137b1fee08
commit
4f80db8269
|
@ -0,0 +1,240 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sound.h"
|
||||
#include "fplay.h"
|
||||
|
||||
|
||||
astream_t astream;
|
||||
|
||||
static SNDBUF hBuff;
|
||||
|
||||
extern volatile uint32_t status;
|
||||
|
||||
void audio_thread(void *param);
|
||||
|
||||
void spinlock_lock(volatile uint32_t *val)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"0:\n\t"
|
||||
"mov %0, %1\n\t"
|
||||
"testl %1, %1\n\t"
|
||||
"jz 1f\n\t"
|
||||
|
||||
"movl $68, %%eax\n\t"
|
||||
"movl $1, %%ebx\n\t"
|
||||
"int $0x40\n\t"
|
||||
"jmp 0b\n\t"
|
||||
"1:\n\t"
|
||||
"incl %1\n\t"
|
||||
"xchgl %0, %1\n\t"
|
||||
"testl %1, %1\n\t"
|
||||
"jnz 0b\n"
|
||||
: "+m" (*val), "=&r"(tmp)
|
||||
::"eax","ebx" );
|
||||
}
|
||||
|
||||
static int snd_format;
|
||||
int sample_rate;
|
||||
|
||||
int init_audio(int format)
|
||||
{
|
||||
int err;
|
||||
int version =-1;
|
||||
char *errstr;
|
||||
|
||||
if((err = InitSound(&version)) !=0 )
|
||||
{
|
||||
errstr = "Sound service not installed\n\r";
|
||||
goto exit_whith_error;
|
||||
}
|
||||
printf("sound version 0x%x\n", version);
|
||||
|
||||
if( (SOUND_VERSION>(version&0xFFFF)) ||
|
||||
(SOUND_VERSION<(version >> 16)))
|
||||
{
|
||||
errstr = "Sound service version mismatch\n\r";
|
||||
goto exit_whith_error;
|
||||
}
|
||||
|
||||
snd_format = format;
|
||||
|
||||
asm volatile ( "xchgw %bx, %bx");
|
||||
|
||||
create_thread(audio_thread, 0, 163840);
|
||||
|
||||
return 1;
|
||||
|
||||
exit_whith_error:
|
||||
|
||||
printf(errstr);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static uint64_t samples_lost;
|
||||
static double audio_delta;
|
||||
|
||||
double get_master_clock()
|
||||
{
|
||||
double tstamp;
|
||||
|
||||
GetTimeStamp(hBuff, &tstamp);
|
||||
return tstamp - audio_delta;
|
||||
};
|
||||
|
||||
|
||||
void audio_thread(void *param)
|
||||
{
|
||||
SND_EVENT evnt;
|
||||
int buffsize;
|
||||
int samples;
|
||||
int err;
|
||||
char *errstr;
|
||||
|
||||
|
||||
if((err = CreateBuffer(snd_format|PCM_RING,0, &hBuff)) != 0)
|
||||
{
|
||||
errstr = "Cannot create sound buffer\n\r";
|
||||
goto exit_whith_error;
|
||||
};
|
||||
|
||||
SetVolume(hBuff,-1000,-1000);
|
||||
|
||||
if((err = GetBufferSize(hBuff, &buffsize)) != 0)
|
||||
{
|
||||
errstr = "Cannot get buffer size\n\r";
|
||||
goto exit_whith_error;
|
||||
};
|
||||
|
||||
buffsize = buffsize/2;
|
||||
|
||||
samples = buffsize/4;
|
||||
|
||||
while( (astream.count < buffsize*2) &&
|
||||
(status != 0) )
|
||||
yield();
|
||||
|
||||
spinlock_lock(&astream.lock);
|
||||
{
|
||||
SetBuffer(hBuff, astream.buffer, 0, buffsize);
|
||||
astream.count -= buffsize;
|
||||
if(astream.count)
|
||||
memcpy(astream.buffer, astream.buffer+buffsize, astream.count);
|
||||
spinlock_unlock(&astream.lock);
|
||||
};
|
||||
|
||||
if((err = PlayBuffer(hBuff, 0)) !=0 )
|
||||
{
|
||||
errstr = "Cannot play buffer\n\r";
|
||||
goto exit_whith_error;
|
||||
};
|
||||
|
||||
|
||||
#ifdef BLACK_MAGIC_SOUND
|
||||
|
||||
while( status != 0)
|
||||
{
|
||||
uint32_t offset;
|
||||
|
||||
GetNotify(&evnt);
|
||||
|
||||
if(evnt.code != 0xFF000001)
|
||||
{
|
||||
printf("invalid event code %d\n\r", evnt.code);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(evnt.stream != hBuff)
|
||||
{
|
||||
printf("invalid stream %x hBuff= %x\n\r",
|
||||
evnt.stream, hBuff);
|
||||
continue;
|
||||
}
|
||||
|
||||
GetTimeStamp(hBuff, &audio_delta);
|
||||
samples_lost = audio_delta*sample_rate/1000;
|
||||
|
||||
offset = evnt.offset;
|
||||
|
||||
spinlock_lock(&astream.lock);
|
||||
{
|
||||
SetBuffer(hBuff, astream.buffer, offset, buffsize);
|
||||
astream.count -= buffsize;
|
||||
if(astream.count)
|
||||
memcpy(astream.buffer, astream.buffer+buffsize, astream.count);
|
||||
spinlock_unlock(&astream.lock);
|
||||
};
|
||||
break;
|
||||
};
|
||||
#endif
|
||||
|
||||
printf("initial audio delta %f\n", audio_delta);
|
||||
|
||||
while( status != 0)
|
||||
{
|
||||
uint32_t offset;
|
||||
double event_stamp, wait_stamp;
|
||||
int too_late = 0;
|
||||
|
||||
GetNotify(&evnt);
|
||||
|
||||
if(evnt.code != 0xFF000001)
|
||||
{
|
||||
printf("invalid event code %d\n\r", evnt.code);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(evnt.stream != hBuff)
|
||||
{
|
||||
printf("invalid stream %x hBuff= %x\n\r",
|
||||
evnt.stream, hBuff);
|
||||
continue;
|
||||
};
|
||||
|
||||
GetTimeStamp(hBuff, &event_stamp);
|
||||
|
||||
offset = evnt.offset;
|
||||
|
||||
while( (astream.count < buffsize) &&
|
||||
(status != 0) )
|
||||
{
|
||||
yield();
|
||||
GetTimeStamp(hBuff, &wait_stamp);
|
||||
if( (wait_stamp - event_stamp) >
|
||||
samples*1500/sample_rate )
|
||||
{
|
||||
samples_lost+= samples;
|
||||
audio_delta = (double)samples_lost*1000/sample_rate;
|
||||
// printf("audio delta %f\n", audio_delta);
|
||||
too_late = 1;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if((too_late == 1) || (status == 0))
|
||||
continue;
|
||||
|
||||
spinlock_lock(&astream.lock);
|
||||
SetBuffer(hBuff, astream.buffer, offset, buffsize);
|
||||
astream.count -= buffsize;
|
||||
if(astream.count)
|
||||
memcpy(astream.buffer, astream.buffer+buffsize, astream.count);
|
||||
spinlock_unlock(&astream.lock);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
exit_whith_error:
|
||||
|
||||
printf(errstr);
|
||||
return ;
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavdevice/avdevice.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include "sound.h"
|
||||
#include "fplay.h"
|
||||
|
||||
volatile uint32_t status = 1;
|
||||
|
||||
uint32_t win_width, win_height;
|
||||
|
||||
void decoder();
|
||||
|
||||
AVFormatContext *pFormatCtx;
|
||||
AVCodecContext *pCodecCtx;
|
||||
AVCodecContext *aCodecCtx;
|
||||
AVCodec *pCodec;
|
||||
AVCodec *aCodec;
|
||||
AVFrame *pFrame;
|
||||
int videoStream;
|
||||
int audioStream;
|
||||
|
||||
int have_sound = 0;
|
||||
|
||||
|
||||
uint8_t *decoder_buffer;
|
||||
extern int sample_rate;
|
||||
|
||||
int main( int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please provide a movie file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* register all codecs, demux and protocols */
|
||||
|
||||
avcodec_register_all();
|
||||
avdevice_register_all();
|
||||
av_register_all();
|
||||
|
||||
|
||||
// Open video file
|
||||
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
|
||||
{
|
||||
printf("Cannot open file %s\n\r", argv[1]);
|
||||
return -1; // Couldn't open file
|
||||
};
|
||||
|
||||
// __asm__ __volatile__("int3");
|
||||
|
||||
// Retrieve stream information
|
||||
if(av_find_stream_info(pFormatCtx)<0)
|
||||
{
|
||||
printf("Cannot find streams\n\r");
|
||||
return -1;
|
||||
};
|
||||
|
||||
// __asm__ __volatile__("int3");
|
||||
|
||||
// dump_format(pFormatCtx, 0, argv[1], 0);
|
||||
|
||||
// Find the first video stream
|
||||
videoStream=-1;
|
||||
audioStream=-1;
|
||||
for(i=0; i < pFormatCtx->nb_streams; i++)
|
||||
{
|
||||
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO
|
||||
&& videoStream < 0)
|
||||
{
|
||||
videoStream=i;
|
||||
video_time_base = pFormatCtx->streams[i]->time_base;
|
||||
|
||||
}
|
||||
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO &&
|
||||
audioStream < 0)
|
||||
{
|
||||
audioStream=i;
|
||||
}
|
||||
}
|
||||
|
||||
if(videoStream==-1)
|
||||
{
|
||||
printf("Video stream not detected\n\r");
|
||||
return -1; // Didn't find a video stream
|
||||
}
|
||||
|
||||
|
||||
// Get a pointer to the codec context for the video stream
|
||||
pCodecCtx=pFormatCtx->streams[videoStream]->codec;
|
||||
|
||||
aCodecCtx=pFormatCtx->streams[audioStream]->codec;
|
||||
|
||||
// Find the decoder for the video stream
|
||||
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
|
||||
if(pCodec==NULL) {
|
||||
printf("Unsupported video codec!\n");
|
||||
return -1; // Codec not found
|
||||
}
|
||||
// Open codec
|
||||
if(avcodec_open(pCodecCtx, pCodec) < 0)
|
||||
{
|
||||
printf("Cannot open video codec\n\r");
|
||||
return -1; // Could not open codec
|
||||
};
|
||||
|
||||
if (aCodecCtx->channels > 0)
|
||||
aCodecCtx->request_channels = FFMIN(2, aCodecCtx->channels);
|
||||
else
|
||||
aCodecCtx->request_channels = 2;
|
||||
|
||||
aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
|
||||
|
||||
if(aCodec)
|
||||
{
|
||||
if(avcodec_open(aCodecCtx, aCodec) >= 0 )
|
||||
{
|
||||
WAVEHEADER whdr;
|
||||
int fmt;
|
||||
|
||||
printf("audio stream rate %d channels %d\n",
|
||||
aCodecCtx->sample_rate, aCodecCtx->channels);
|
||||
|
||||
whdr.riff_id = 0x46464952;
|
||||
whdr.riff_format = 0x45564157;
|
||||
whdr.wFormatTag = 0x01;
|
||||
whdr.nSamplesPerSec = aCodecCtx->sample_rate;
|
||||
whdr.nChannels = aCodecCtx->channels;
|
||||
whdr.wBitsPerSample = 16;
|
||||
|
||||
sample_rate = aCodecCtx->sample_rate;
|
||||
|
||||
fmt = test_wav(&whdr);
|
||||
|
||||
if( init_audio(fmt) )
|
||||
{
|
||||
decoder_buffer = (uint8_t*)av_mallocz(AVCODEC_MAX_AUDIO_FRAME_SIZE);
|
||||
if( decoder_buffer != NULL )
|
||||
{
|
||||
astream.lock = 0;
|
||||
astream.count = 0;
|
||||
astream.buffer = (char *)av_mallocz(AVCODEC_MAX_AUDIO_FRAME_SIZE*8);
|
||||
if( astream.buffer != NULL )
|
||||
have_sound = 1;
|
||||
else
|
||||
av_free(decoder_buffer);
|
||||
}
|
||||
if( have_sound == 0)
|
||||
{
|
||||
printf("Not enough memory for audio buffers\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else printf("Cannot open audio codec\n\r");
|
||||
}
|
||||
else printf("Unsupported audio codec!\n");
|
||||
|
||||
if( !init_video(pCodecCtx))
|
||||
return 0;
|
||||
|
||||
// Assign appropriate parts of buffer to image planes in pFrameRGB
|
||||
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
|
||||
// of AVPicture
|
||||
|
||||
// __asm__ __volatile__("int3");
|
||||
|
||||
decoder();
|
||||
|
||||
status = 0;
|
||||
|
||||
|
||||
// Free the YUV frame
|
||||
av_free(pFrame);
|
||||
|
||||
//__asm__ __volatile__("int3");
|
||||
|
||||
// Close the codec
|
||||
// avcodec_close(pCodecCtx);
|
||||
|
||||
// Close the video file
|
||||
// av_close_input_file(pFormatCtx);
|
||||
|
||||
//__asm__ __volatile__("int3");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void decoder()
|
||||
{
|
||||
AVPacket packet;
|
||||
|
||||
while(av_read_frame(pFormatCtx, &packet) >=0 )
|
||||
{
|
||||
if(packet.stream_index==videoStream)
|
||||
{
|
||||
decode_video(pCodecCtx, &packet);
|
||||
}
|
||||
else if( (packet.stream_index == audioStream) &&
|
||||
(have_sound != 0) )
|
||||
{
|
||||
uint8_t *audio_data;
|
||||
int audio_size;
|
||||
int len;
|
||||
int data_size=0;
|
||||
|
||||
audio_data = packet.data;
|
||||
audio_size = packet.size;
|
||||
|
||||
while(audio_size > 0)
|
||||
{
|
||||
data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
|
||||
|
||||
len = avcodec_decode_audio2(aCodecCtx,(int16_t*)decoder_buffer,
|
||||
&data_size, audio_data, audio_size);
|
||||
|
||||
if(len >= 0)
|
||||
{
|
||||
audio_data += len;
|
||||
audio_size -= len;
|
||||
|
||||
while((astream.count + data_size) >
|
||||
AVCODEC_MAX_AUDIO_FRAME_SIZE*8)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
spinlock_lock(&astream.lock);
|
||||
memcpy(astream.buffer+astream.count, decoder_buffer, data_size);
|
||||
astream.count += data_size;
|
||||
spinlock_unlock(&astream.lock);
|
||||
}
|
||||
else audio_size = 0;
|
||||
}
|
||||
}
|
||||
// Free the packet that was allocated by av_read_frame
|
||||
av_free_packet(&packet);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
__int64 _lseeki64(int fd, __int64 offset, int origin )
|
||||
{
|
||||
int off = offset;
|
||||
return lseek(fd, off, origin);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
#define BLACK_MAGIC_SOUND
|
||||
#define BLACK_MAGIC_VIDEO
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t lock;
|
||||
char *buffer;
|
||||
volatile uint32_t count;
|
||||
}astream_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int code;
|
||||
unsigned int sender;
|
||||
unsigned int stream;
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
unsigned int unused[2];
|
||||
}SND_EVENT;
|
||||
|
||||
extern astream_t astream;
|
||||
extern AVRational video_time_base;
|
||||
|
||||
int init_audio(int format);
|
||||
int init_video(AVCodecContext *ctx);
|
||||
int decode_video(AVCodecContext *ctx, AVPacket *pkt);
|
||||
double get_master_clock();
|
||||
|
||||
|
||||
int create_thread(void (*proc)(void *param), void *param, int stack_size);
|
||||
|
||||
void spinlock_lock(volatile uint32_t *val);
|
||||
|
||||
static inline void spinlock_unlock(volatile uint32_t *val)
|
||||
{
|
||||
*val = 0;
|
||||
}
|
||||
|
||||
static inline void GetNotify(void *event)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
"int $0x40"
|
||||
::"a"(68),"b"(14),"c"(event));
|
||||
}
|
||||
|
||||
static inline uint32_t check_os_event()
|
||||
{
|
||||
uint32_t val;
|
||||
__asm__ __volatile__(
|
||||
"int $0x40"
|
||||
:"=a"(val)
|
||||
:"a"(11));
|
||||
return val;
|
||||
};
|
||||
|
||||
static inline uint32_t get_os_button()
|
||||
{
|
||||
uint32_t val;
|
||||
__asm__ __volatile__(
|
||||
"int $0x40"
|
||||
:"=a"(val)
|
||||
:"a"(17));
|
||||
return val>>8;
|
||||
};
|
||||
|
||||
static inline void yield(void)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"int $0x40"
|
||||
::"a"(68), "b"(1));
|
||||
};
|
||||
|
||||
static inline void delay(uint32_t time)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"int $0x40"
|
||||
::"a"(5), "b"(time));
|
||||
};
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
#ifndef _SOUND_H_
|
||||
#define _SOUND_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define SOUND_VERSION 0x0101
|
||||
#define PCM_ALL 0
|
||||
|
||||
#define PCM_OUT 0x08000000
|
||||
#define PCM_RING 0x10000000
|
||||
#define PCM_STATIC 0x20000000
|
||||
#define PCM_FLOAT 0x40000000
|
||||
#define PCM_FILTER 0x80000000
|
||||
|
||||
#define PCM_2_16_48 1
|
||||
#define PCM_1_16_48 2
|
||||
#define PCM_2_16_44 3
|
||||
#define PCM_1_16_44 4
|
||||
#define PCM_2_16_32 5
|
||||
#define PCM_1_16_32 6
|
||||
#define PCM_2_16_24 7
|
||||
#define PCM_1_16_24 8
|
||||
#define PCM_2_16_22 9
|
||||
#define PCM_1_16_22 10
|
||||
#define PCM_2_16_16 11
|
||||
#define PCM_1_16_16 12
|
||||
#define PCM_2_16_12 13
|
||||
#define PCM_1_16_12 14
|
||||
#define PCM_2_16_11 15
|
||||
#define PCM_1_16_11 16
|
||||
#define PCM_2_16_8 17
|
||||
#define PCM_1_16_8 18
|
||||
#define PCM_2_8_48 19
|
||||
#define PCM_1_8_48 20
|
||||
#define PCM_2_8_44 21
|
||||
#define PCM_1_8_44 22
|
||||
#define PCM_2_8_32 23
|
||||
#define PCM_1_8_32 24
|
||||
#define PCM_2_8_24 25
|
||||
#define PCM_1_8_24 26
|
||||
#define PCM_2_8_22 27
|
||||
#define PCM_1_8_22 28
|
||||
#define PCM_2_8_16 29
|
||||
#define PCM_1_8_16 30
|
||||
#define PCM_2_8_12 31
|
||||
#define PCM_1_8_12 32
|
||||
#define PCM_2_8_11 33
|
||||
#define PCM_1_8_11 34
|
||||
#define PCM_2_8_8 35
|
||||
#define PCM_1_8_8 36
|
||||
|
||||
#define SRV_GETVERSION 0
|
||||
#define SND_CREATE_BUFF 1
|
||||
#define SND_DESTROY_BUFF 2
|
||||
#define SND_SETFORMAT 3
|
||||
#define SND_GETFORMAT 4
|
||||
#define SND_RESET 5
|
||||
#define SND_SETPOS 6
|
||||
#define SND_GETPOS 7
|
||||
#define SND_SETBUFF 8
|
||||
#define SND_OUT 9
|
||||
#define SND_PLAY 10
|
||||
#define SND_STOP 11
|
||||
#define SND_SETVOLUME 12
|
||||
#define SND_GETVOLUME 13
|
||||
#define SND_SETPAN 14
|
||||
#define SND_GETPAN 15
|
||||
#define SND_GETBUFFSIZE 16
|
||||
#define SND_GETFREESPACE 17
|
||||
#define SND_SETTIMEBASE 18
|
||||
#define SND_GETTIMESTAMP 19
|
||||
|
||||
#define PLAY_SYNC 0x80000000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int riff_id;
|
||||
unsigned int riff_size;
|
||||
unsigned int riff_format;
|
||||
|
||||
unsigned int fmt_id;
|
||||
unsigned int fmt_size;
|
||||
|
||||
unsigned short int wFormatTag;
|
||||
unsigned short int nChannels;
|
||||
unsigned int nSamplesPerSec;
|
||||
unsigned int nAvgBytesPerSec;
|
||||
unsigned short int nBlockAlign;
|
||||
unsigned short int wBitsPerSample;
|
||||
unsigned int data_id;
|
||||
unsigned int data_size;
|
||||
} WAVEHEADER;
|
||||
|
||||
typedef unsigned int SNDBUF;
|
||||
|
||||
int _stdcall InitSound(int *version);
|
||||
|
||||
int _stdcall CreateBuffer(unsigned int format,int size,SNDBUF *buf);
|
||||
int _stdcall DestroyBuffer(SNDBUF hBuff);
|
||||
|
||||
int _stdcall SetFormat(SNDBUF hBuff, unsigned int format);
|
||||
int _stdcall GetFormat(SNDBUF hBuff, unsigned int *format);
|
||||
|
||||
int _stdcall ResetBuffer(SNDBUF hBuff, unsigned int flags);
|
||||
int _stdcall SetBufferPos(SNDBUF hBuff, int offset);
|
||||
int _stdcall GetBufferPos(SNDBUF hBuff, int *offset);
|
||||
int _stdcall GetBufferSize(SNDBUF hBuff, int *size);
|
||||
int _stdcall GetBufferFree(SNDBUF hBuff, int *free);
|
||||
|
||||
int _stdcall SetBuffer(SNDBUF hBuff,void* buff,
|
||||
int offs, int size);
|
||||
int _stdcall WaveOut(SNDBUF hBuff,void *buff, int size);
|
||||
int _stdcall PlayBuffer(SNDBUF hBuff,unsigned int flags);
|
||||
int _stdcall StopBuffer(SNDBUF hBuff);
|
||||
|
||||
int _stdcall SetVolume(SNDBUF hBuff, int left, int right);
|
||||
int _stdcall GetVolume(SNDBUF hBuff, int *left, int *right);
|
||||
int _stdcall SetPan(SNDBUF hBuff, int pan);
|
||||
int _stdcall GetPan(SNDBUF hBuff, int *pan);
|
||||
|
||||
int _stdcall GetMasterVol(int* vol);
|
||||
int _stdcall SetMasterVol(int vol);
|
||||
|
||||
int _stdcall SetTimeBase(SNDBUF hBuff, double base);
|
||||
int _stdcall GetTimeStamp(SNDBUF hBuff, double *stamp);
|
||||
|
||||
unsigned int _stdcall test_wav(WAVEHEADER *hdr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //_SOUND_H_
|
|
@ -0,0 +1,272 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include "fplay.h"
|
||||
|
||||
void video_thread(void *param);
|
||||
|
||||
void draw_bitmap(void *bitmap, int x, int y, int w, int h)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"int $0x40"
|
||||
::"a"(7), "b"(bitmap),
|
||||
"c"((w << 16) | h),
|
||||
"d"((x << 16) | y));
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AVFrame *frame;
|
||||
uint8_t *buffer;
|
||||
double pts;
|
||||
volatile int ready;
|
||||
}vframe_t;
|
||||
|
||||
vframe_t frames[8];
|
||||
|
||||
struct SwsContext *cvt_ctx;
|
||||
|
||||
int vfx = 0;
|
||||
int dfx = 0;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
AVRational video_time_base;
|
||||
AVFrame *Frame;
|
||||
|
||||
int init_video(AVCodecContext *ctx)
|
||||
{
|
||||
uint32_t size;
|
||||
int i;
|
||||
|
||||
width = ctx->width;
|
||||
height = ctx->height;
|
||||
|
||||
printf("w = %d h = %d\n\r", width, height);
|
||||
|
||||
Frame = avcodec_alloc_frame();
|
||||
if ( Frame == NULL )
|
||||
{
|
||||
printf("Cannot alloc video buffer\n\r");
|
||||
return 0;
|
||||
};
|
||||
|
||||
cvt_ctx = sws_getContext(
|
||||
ctx->width,
|
||||
ctx->height,
|
||||
ctx->pix_fmt,
|
||||
ctx->width,
|
||||
ctx->height,
|
||||
PIX_FMT_BGR24,
|
||||
SWS_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
if(cvt_ctx == NULL)
|
||||
{
|
||||
printf("Cannot initialize the conversion context!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = avpicture_get_size(PIX_FMT_RGB24, ctx->width, ctx->height);
|
||||
|
||||
for( i=0; i < 8; i++)
|
||||
{
|
||||
AVFrame *frame;
|
||||
|
||||
frame = avcodec_alloc_frame();
|
||||
|
||||
if( frame )
|
||||
{
|
||||
uint8_t *buffer = (uint8_t*)av_malloc(size);
|
||||
|
||||
if( buffer )
|
||||
{
|
||||
avpicture_fill((AVPicture *)frame, buffer, PIX_FMT_BGR24,
|
||||
ctx->width, ctx->height);
|
||||
|
||||
frames[i].frame = frame;
|
||||
frames[i].buffer = buffer;
|
||||
frames[i].pts = 0;
|
||||
frames[i].ready = 0;
|
||||
continue;
|
||||
};
|
||||
};
|
||||
printf("Cannot alloc frame buffer\n\r");
|
||||
return 0;
|
||||
};
|
||||
|
||||
create_thread(video_thread, 0, 163840);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
int frameFinished=0;
|
||||
|
||||
int decode_video(AVCodecContext *ctx, AVPacket *pkt)
|
||||
{
|
||||
double pts;
|
||||
AVPicture pict;
|
||||
const uint8_t *data[4];
|
||||
double av_time;
|
||||
|
||||
// __asm__("int3");
|
||||
|
||||
if(avcodec_decode_video(ctx, Frame, &frameFinished,
|
||||
pkt->data, pkt->size) <= 0)
|
||||
printf("decode error\n");
|
||||
|
||||
if( pkt->dts == AV_NOPTS_VALUE &&
|
||||
Frame->reordered_opaque != AV_NOPTS_VALUE)
|
||||
pts= Frame->reordered_opaque;
|
||||
else if(pkt->dts != AV_NOPTS_VALUE)
|
||||
pts= pkt->dts;
|
||||
else
|
||||
pts= 0;
|
||||
|
||||
pts *= av_q2d(video_time_base);
|
||||
|
||||
if(frameFinished)
|
||||
{
|
||||
while( frames[dfx].ready != 0 )
|
||||
yield();
|
||||
|
||||
pict.data[0] = frames[dfx].frame->data[0];
|
||||
pict.data[1] = frames[dfx].frame->data[1];
|
||||
pict.data[2] = frames[dfx].frame->data[2];
|
||||
pict.data[3] = NULL;
|
||||
|
||||
pict.linesize[0] = frames[dfx].frame->linesize[0];
|
||||
pict.linesize[1] = frames[dfx].frame->linesize[1];
|
||||
pict.linesize[2] = frames[dfx].frame->linesize[2];
|
||||
pict.linesize[3] = 0;
|
||||
|
||||
data[0] = Frame->data[0];
|
||||
data[1] = Frame->data[1];
|
||||
data[2] = Frame->data[2];
|
||||
data[3] = NULL;
|
||||
|
||||
sws_scale(cvt_ctx, data, Frame->linesize, 0, ctx->height,
|
||||
pict.data, pict.linesize);
|
||||
|
||||
frames[dfx].pts = pts*1000.0;
|
||||
frames[dfx].ready = 1;
|
||||
|
||||
dfx++;
|
||||
dfx&= 7;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern volatile uint32_t status;
|
||||
|
||||
typedef unsigned int color_t;
|
||||
typedef unsigned int count_t;
|
||||
typedef unsigned int u32_t;
|
||||
|
||||
static void DrawWindow(int x, int y, int w, int h, char *name,
|
||||
color_t workcolor, u32_t style)
|
||||
{
|
||||
|
||||
__asm__ __volatile__(
|
||||
"int $0x40"
|
||||
::"a"(0),
|
||||
"b"((x << 16) | (w & 0xFFFF)),
|
||||
"c"((y << 16) | (h & 0xFFFF)),
|
||||
"d"((style << 24) | (workcolor & 0xFFFFFF)),
|
||||
"D"(name));
|
||||
};
|
||||
|
||||
|
||||
static int check_events()
|
||||
{
|
||||
int ev;
|
||||
|
||||
ev = check_os_event();
|
||||
|
||||
switch(ev)
|
||||
{
|
||||
case 1:
|
||||
DrawWindow(10, 10, width+9, height+26, NULL, 0x000000,0x74);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if(get_os_button()==1)
|
||||
status = 0;
|
||||
break;
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
extern char __cmdline[];
|
||||
|
||||
void video_thread(void *param)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = strrchr(__cmdline,'/')+1;
|
||||
|
||||
DrawWindow(10, 10, width+9, height+26, path, 0x000000,0x74);
|
||||
|
||||
while( status != 0)
|
||||
{
|
||||
double ctime;
|
||||
double fdelay;
|
||||
|
||||
check_events();
|
||||
|
||||
if(frames[vfx].ready == 1 )
|
||||
{
|
||||
ctime = get_master_clock();
|
||||
fdelay = (frames[vfx].pts - ctime);
|
||||
// printf("ctime %f pts %f delay %f\n",
|
||||
// ctime, frames[vfx].pts, fdelay);
|
||||
|
||||
if(fdelay < 0.0 )
|
||||
{
|
||||
int next_vfx;
|
||||
fdelay = 0;
|
||||
next_vfx = (vfx+1) & 7;
|
||||
if( frames[next_vfx].ready == 1 )
|
||||
{
|
||||
if(frames[next_vfx].pts <= ctime)
|
||||
{
|
||||
frames[vfx].ready = 0; // skip this frame
|
||||
vfx++;
|
||||
vfx&= 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (frames[next_vfx].pts - ctime) <
|
||||
( ctime - frames[vfx].pts) )
|
||||
{
|
||||
frames[vfx].ready = 0; // skip this frame
|
||||
vfx++;
|
||||
vfx&= 7;
|
||||
fdelay = (frames[next_vfx].pts - ctime);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if(fdelay > 10.0)
|
||||
{
|
||||
delay( (uint32_t)(fdelay/10.0));
|
||||
};
|
||||
|
||||
draw_bitmap(frames[vfx].buffer, 0, 0, width, height);
|
||||
frames[vfx].ready = 0;
|
||||
vfx++;
|
||||
vfx&= 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue