Fplay source code.

git-svn-id: svn://kolibrios.org@1696 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2010-11-10 05:51:05 +00:00
parent 137b1fee08
commit 4f80db8269
5 changed files with 985 additions and 0 deletions

View File

@ -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 ;
};

View File

@ -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);
}

View File

@ -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));
};

View File

@ -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_

View File

@ -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();
};
};
};