1
0
kolibrios/programs/media/Fplay/video.c
Sergey Semyonov (Serge) 4f80db8269 Fplay source code.
git-svn-id: svn://kolibrios.org@1696 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-11-10 05:51:05 +00:00

273 lines
6.4 KiB
C

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