From f5ad13b8ec04b28644b9cc6a674b5b897316c6e1 Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Sat, 19 Sep 2009 15:29:24 +0430 Subject: [PATCH] fbff started --- Makefile | 11 ++++ draw.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++ draw.h | 16 ++++++ fbff.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 371 insertions(+) create mode 100644 Makefile create mode 100644 draw.c create mode 100644 draw.h create mode 100644 fbff.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bfb3b4f --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +CC = cc +CFLAGS = -std=gnu99 -pedantic -Wall -O2 +LDFLAGS = -lavutil -lavformat -lavcodec -lavutil -lswscale -lasound -lz -lm + +all: fbff +.c.o: + $(CC) -c $(CFLAGS) $< +fbff: fbff.o draw.o + $(CC) $(LDFLAGS) -o $@ $^ +clean: + rm -f *.o fbff diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..c6daf6b --- /dev/null +++ b/draw.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "draw.h" + +#define MAXFBWIDTH (1 << 12) +#define BPP sizeof(fbval_t) +#define NLEVELS (1 << 8) + +static int fd; +static unsigned char *fb; +static struct fb_var_screeninfo vinfo; +static struct fb_fix_screeninfo finfo; +static int rl, rr, gl, gr, bl, br; +static int nr, ng, nb; + +static int fb_len() +{ + return vinfo.xres_virtual * vinfo.yres_virtual * BPP; +} + +static void fb_cmap_save(int save) +{ + static unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS]; + struct fb_cmap cmap; + if (finfo.visual == FB_VISUAL_TRUECOLOR) + return; + cmap.start = 0; + cmap.len = MAX(nr, MAX(ng, nb)); + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = 0; + ioctl(fd, save ? FBIOGETCMAP : FBIOPUTCMAP, &cmap); +} + +void fb_cmap(void) +{ + unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS]; + struct fb_cmap cmap; + int i; + if (finfo.visual == FB_VISUAL_TRUECOLOR) + return; + + for (i = 0; i < nr; i++) + red[i] = (65535 / (nr - 1)) * i; + for (i = 0; i < ng; i++) + green[i] = (65535 / (ng - 1)) * i; + for (i = 0; i < nb; i++) + blue[i] = (65535 / (nb - 1)) * i; + + cmap.start = 0; + cmap.len = MAX(nr, MAX(ng, nb)); + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = 0; + + ioctl(fd, FBIOPUTCMAP, &cmap); +} + +static void xerror(char *msg) +{ + perror(msg); + exit(1); +} + +static void xdie(char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +static void init_colors(void) +{ + nr = 1 << vinfo.red.length; + ng = 1 << vinfo.green.length; + nb = 1 << vinfo.blue.length; + rr = 8 - vinfo.red.length; + rl = vinfo.red.offset; + gr = 8 - vinfo.green.length; + gl = vinfo.green.offset; + br = 8 - vinfo.blue.length; + bl = vinfo.blue.offset; +} + +void fb_init(void) +{ + fd = open(FBDEV_PATH, O_RDWR); + if (fd == -1) + xerror("can't open " FBDEV_PATH); + if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) + xerror("ioctl failed"); + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + xerror("ioctl failed"); + if ((vinfo.bits_per_pixel + 7) >> 3 != BPP) + xdie("fbval_t does not match framebuffer depth"); + init_colors(); + fb = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (fb == MAP_FAILED) + xerror("can't map the framebuffer"); + fb_cmap_save(1); + fb_cmap(); +} + +void fb_set(int r, int c, fbval_t *mem, int len) +{ + long loc = (c + vinfo.xoffset) * BPP + + (r + vinfo.yoffset) * finfo.line_length; + memcpy(fb + loc, mem, len * BPP); +} + +void fb_free() +{ + fb_cmap_save(0); + munmap(fb, fb_len()); + close(fd); +} + +fbval_t fb_color(unsigned char r, unsigned char g, unsigned char b) +{ + return ((r >> rr) << rl) | ((g >> gr) << gl) | ((b >> br) << bl); +} + +int fb_rows(void) +{ + return vinfo.yres; +} + +int fb_cols(void) +{ + return vinfo.xres; +} + +static unsigned char *rowaddr(int r) +{ + return fb + (r + vinfo.yoffset) * finfo.line_length; +} + +static unsigned long cache[MAXFBWIDTH]; +void fb_box(int sr, int sc, int er, int ec, fbval_t val) +{ + int i; + int pc = sizeof(cache[0]) / sizeof(val); + int cn = MIN((ec - sc) / pc + 1, MAXFBWIDTH); + unsigned long nv = val; + for (i = 1; i < pc; i++) + nv = (nv << (sizeof(val) * 8)) | val; + for (i = 0; i < cn; i++) + cache[i] = nv; + for (i = sr; i < er; i++) + memcpy(rowaddr(i) + sc * BPP, cache, (ec - sc) * BPP); +} diff --git a/draw.h b/draw.h new file mode 100644 index 0000000..a13328b --- /dev/null +++ b/draw.h @@ -0,0 +1,16 @@ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +/* framebuffer device */ +#define FBDEV_PATH "/dev/fb0" +/* framebuffer depth */ +typedef unsigned short fbval_t; + +void fb_init(void); +void fb_free(void); +fbval_t fb_color(unsigned char r, unsigned char g, unsigned char b); +void fb_set(int r, int c, fbval_t *mem, int len); +int fb_rows(void); +int fb_cols(void); +void fb_box(int sr, int sc, int er, int ec, fbval_t val); +void fb_cmap(void); diff --git a/fbff.c b/fbff.c new file mode 100644 index 0000000..af5693e --- /dev/null +++ b/fbff.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include +#include "draw.h" + +#define ZOOM 1 +#define ZOOM2 1 + +static AVFormatContext *fc; +static AVFrame *frame; +static struct SwsContext *swsc; + +static int vsi = -1; /* video stream index */ +static AVCodecContext *vcc; /* video codec context */ +static AVCodec *vc; /* video codec */ + +static int asi = -1; /* audio stream index */ +static AVCodecContext *acc; /* audio codec context */ +static AVCodec *ac; /* audio codec */ + +static snd_pcm_t *alsa; +static int bps; /* bytes per sample */ +static int goalbr; + +static void init_streams(void) +{ + int i; + for (i = 0; i < fc->nb_streams; i++) { + if (fc->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) + vsi = i; + if (fc->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) + asi = i; + } + if (vsi != -1) { + vcc = fc->streams[vsi]->codec; + vc = avcodec_find_decoder(vcc->codec_id); + avcodec_open(vcc, vc); + } + if (asi != -1) { + acc = fc->streams[asi]->codec; + ac = avcodec_find_decoder(acc->codec_id); + avcodec_open(acc, ac); + } +} + +static void draw_frame(void) +{ + fbval_t buf[1 << 14]; + int r, c; + int nr = MIN(vcc->height * ZOOM, fb_rows() / ZOOM2); + int nc = MIN(vcc->width * ZOOM, fb_cols() / ZOOM2); + int i; + for (r = 0; r < nr; r++) { + unsigned char *row = frame->data[0] + r * frame->linesize[0]; + for (c = 0; c < nc; c++) { + fbval_t v = fb_color(row[c * 3], + row[c * 3 + 1], + row[c * 3 + 2]); + for (i = 0; i < ZOOM2; i++) + buf[c * ZOOM2 + i] = v; + } + for (i = 0; i < ZOOM2; i++) + fb_set(r * ZOOM2 + i, 0, buf, nc * ZOOM2); + } +} + +static void decode_video_frame(AVFrame *main_frame, AVPacket *packet) +{ + int fine = 0; + avcodec_decode_video2(vcc, main_frame, &fine, packet); + if (fine) { + sws_scale(swsc, main_frame->data, main_frame->linesize, + 0, vcc->height, frame->data, frame->linesize); + draw_frame(); + } +} + +#define AUDIOBUFSIZE (1 << 20) + +static void decode_audio_frame(AVPacket *pkt) +{ + char buf[AUDIOBUFSIZE]; + AVPacket tmppkt; + tmppkt.size = pkt->size; + tmppkt.data = pkt->data; + while (tmppkt.size > 0) { + int size = sizeof(buf); + int len = avcodec_decode_audio3(acc, (int16_t *) buf, + &size, &tmppkt); + if (len < 0) + break; + if (size <= 0) + continue; + if (snd_pcm_writei(alsa, buf, size / bps) < 0) + snd_pcm_prepare(alsa); + tmppkt.size -= len; + tmppkt.data += len; + } +} + +static void read_frames(void) +{ + AVFrame *main_frame = avcodec_alloc_frame(); + AVPacket pkt; + uint8_t *buf; + int n = AUDIOBUFSIZE; + if (vcc) + n = avpicture_get_size(PIX_FMT_RGB24, vcc->width * ZOOM, + vcc->height * ZOOM); + buf = av_malloc(n * sizeof(uint8_t)); + if (vcc) + avpicture_fill((AVPicture *) frame, buf, PIX_FMT_RGB24, + vcc->width * ZOOM, vcc->height * ZOOM); + while (av_read_frame(fc, &pkt) >= 0) { + if (vcc && pkt.stream_index == vsi) + decode_video_frame(main_frame, &pkt); + if (acc && pkt.stream_index == asi) + decode_audio_frame(&pkt); + av_free_packet(&pkt); + } + av_free(buf); + av_free(main_frame); +} + +#define ALSADEV "default" + +static void alsa_init(void) +{ + int format = SND_PCM_FORMAT_S16_LE; + if (snd_pcm_open(&alsa, ALSADEV, SND_PCM_STREAM_PLAYBACK, 0) < 0) + return; + snd_pcm_set_params(alsa, format, SND_PCM_ACCESS_RW_INTERLEAVED, + acc->channels, acc->sample_rate, 1, 500000); + bps = acc->channels * snd_pcm_format_physical_width(format) / 8; + goalbr = acc->sample_rate * bps; + snd_pcm_prepare(alsa); +} + +static void alsa_close(void) +{ + snd_pcm_close(alsa); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + printf("usage: %s filename\n", argv[0]); + return 1; + } + av_register_all(); + if (av_open_input_file(&fc, argv[1], NULL, 0, NULL)) + return 1; + if (av_find_stream_info(fc) < 0) + return 1; + dump_format(fc, 0, "input", 0); + init_streams(); + frame = avcodec_alloc_frame(); + if (acc) + alsa_init(); + if (vcc) { + swsc = sws_getContext(vcc->width, vcc->height, vcc->pix_fmt, + vcc->width * ZOOM, vcc->height * ZOOM, + PIX_FMT_RGB24, SWS_FAST_BILINEAR | SWS_CPU_CAPS_MMX2, + NULL, NULL, NULL); + fb_init(); + } + + read_frames(); + + if (vcc) { + fb_free(); + sws_freeContext(swsc); + avcodec_close(vcc); + } + if (acc) { + alsa_close(); + avcodec_close(acc); + } + av_free(frame); + av_close_input_file(fc); + return 0; +} -- 2.11.4.GIT