Create a gist now

Instantly share code, notes, and snippets.

@moriyoshi /charfb.c
Last active Dec 17, 2015

What would you like to do?
#include <stdio.h>
#include <stdlib.h>
#include "charfb.h"
static int block_char_map[] = {
0x0020,
0x2598,
0x259d,
0x2580,
0x2596,
0x258c,
0x259e,
0x259b,
0x2597,
0x259a,
0x2590,
0x259c,
0x2584,
0x2599,
0x259f,
0x2593
};
void charfb_pixbuf_fini(charfb_pixbuf_t *buf)
{
free(buf->buf);
buf->buf = NULL;
}
int charfb_pixbuf_init(charfb_pixbuf_t *buf, int width, int height)
{
unsigned int *b;
if (!(b = malloc(width * height * sizeof(int)))) {
return 1;
}
buf->width = width;
buf->height = height;
buf->buf = b;
return 0;
}
void charfb_fini(charfb_t *self)
{
charfb_pixbuf_fini(&self->fb);
}
static unsigned int to_lightness(unsigned int argb)
{
unsigned int b = argb & 0xff, g = (argb >> 8) & 0xff, r = (argb >> 16) & 0xff;
const unsigned int M = (g > b ? (r > g ? r: g): (r > b ? r: b)),
m = (g < b ? (r < g ? r: g): (r < b ? r: b));
return (M + m) / 2;
}
static int charfb_determine_character(unsigned int p0, unsigned int p1, unsigned int p2, unsigned int p3)
{
return block_char_map[
((to_lightness(p0) > 180) ? 1: 0) |
((to_lightness(p1) > 180) ? 2: 0) |
((to_lightness(p2) > 180) ? 4: 0) |
((to_lightness(p3) > 180) ? 8: 0)
];
}
int charfb_render(charfb_t *self)
{
int err;
int x, y;
if ((err = self->odrv->clear(self->odrv))) {
return err;
}
for (y = 0; y < self->cheight; y++) {
for (x = 0; x < self->cwidth; x++) {
int ch = charfb_determine_character(
self->fb.buf[y * 2 * self->fb.width + x * 2],
self->fb.buf[y * 2 * self->fb.width + x * 2 + 1],
self->fb.buf[(y * 2 + 1) * self->fb.width + x * 2],
self->fb.buf[(y * 2 + 1) * self->fb.width + x * 2 + 1]
);
if ((err = self->odrv->put(self->odrv, ch, 7)))
return err;
}
if ((err = self->odrv->cr(self->odrv)))
return err;
if ((err = self->odrv->lf(self->odrv)))
return err;
}
return self->odrv->vsync(self->odrv);
}
int charfb_init(charfb_t *self, charfb_output_driver_t *odrv, int mode, int cwidth, int cheight)
{
int err;
int fbwidth, fbheight;
self->odrv = odrv;
self->mode = mode;
self->cwidth = cwidth;
self->cheight = cheight;
if ((err = charfb_pixbuf_init(&self->fb, cwidth * 2, cheight * 2))) {
return err;
}
}
#ifndef CHARFB_H
#define CHARFB_H
typedef struct charfb_output_driver_t charfb_output_driver_t;
struct charfb_output_driver_t {
void (*fini)(charfb_output_driver_t *);
int (*getsize)(charfb_output_driver_t *, int *width, int *height);
int (*put)(charfb_output_driver_t *, int ch, int color);
int (*move)(charfb_output_driver_t *, int x, int y);
int (*cr)(charfb_output_driver_t *);
int (*lf)(charfb_output_driver_t *);
int (*clear)(charfb_output_driver_t *);
int (*vsync)(charfb_output_driver_t *);
};
/* ARGB */
typedef struct charfb_pixbuf_t {
int width, height;
unsigned int *buf;
} charfb_pixbuf_t;
typedef struct charfb_t {
charfb_output_driver_t *odrv;
int mode;
int cwidth, cheight;
charfb_pixbuf_t fb;
} charfb_t;
extern charfb_output_driver_t *(*default_output_driver_factory)();
int charfb_pixbuf_init(charfb_pixbuf_t *buf, int width, int height);
void charfb_pixbuf_fini(charfb_pixbuf_t *buf);
int charfb_init(charfb_t *, charfb_output_driver_t *odrv, int mode, int cwidth, int cheight);
void charfb_fini(charfb_t *);
int charfb_render(charfb_t *);
#endif /* CHARFB_H */
#include <stdio.h>
#include <stdlib.h>
#include <iconv.h>
#include <locale.h>
#include <langinfo.h>
#include "charfb.h"
typedef struct stdio_output_driver_t {
charfb_output_driver_t super;
FILE *fp;
iconv_t cd;
} stdio_output_driver_t;
static void stdio_drv_fini(charfb_output_driver_t *self)
{
iconv_close(((stdio_output_driver_t *)self)->cd);
free(self);
}
static int stdio_drv_getsize(charfb_output_driver_t *self, int *width, int *height)
{
return -1;
}
static int stdio_drv_put(charfb_output_driver_t *self, int ch, int color)
{
stdio_output_driver_t *_self = (stdio_output_driver_t *)self;
unsigned char in[4] = { ch >> 24, ch >> 16, ch >> 8, ch };
char *pi = (char *)in;
char out[32];
char *po = out;
size_t ni = sizeof(in), no = sizeof(out);
if (iconv(_self->cd, &pi, &ni, &po, &no) == (size_t)-1) {
return 1;
}
{
const char *p = out;
for (; p < po; p++)
fputc(*p, _self->fp);
}
return 0;
}
static int stdio_drv_move(charfb_output_driver_t *self, int x, int y)
{
return -1;
}
static int stdio_drv_cr(charfb_output_driver_t *self)
{
stdio_output_driver_t *_self = (stdio_output_driver_t *)self;
fputc(0x0d, _self->fp);
return 0;
}
static int stdio_drv_lf(charfb_output_driver_t *self)
{
stdio_output_driver_t *_self = (stdio_output_driver_t *)self;
fputc(0x0a, _self->fp);
return 0;
}
static int stdio_drv_clear(charfb_output_driver_t *self)
{
stdio_output_driver_t *_self = (stdio_output_driver_t *)self;
fputc(0x1b, _self->fp);
fputc('[', _self->fp);
fputc('1', _self->fp);
fputc(';', _self->fp);
fputc('1', _self->fp);
fputc('H', _self->fp);
return 0;
}
static int stdio_drv_vsync(charfb_output_driver_t *self)
{
stdio_output_driver_t *_self = (stdio_output_driver_t *)self;
fflush(_self->fp);
return 0;
}
static charfb_output_driver_t stdio_output_driver = {
&stdio_drv_fini,
&stdio_drv_getsize,
&stdio_drv_put,
&stdio_drv_move,
&stdio_drv_cr,
&stdio_drv_lf,
&stdio_drv_clear,
&stdio_drv_vsync
};
charfb_output_driver_t *new_stdio_drv()
{
const char *charset;
setlocale(0, "");
charset = nl_langinfo(CODESET);
{
stdio_output_driver_t *drv = malloc(sizeof(stdio_output_driver_t));
if (!drv)
return NULL;
drv->super = stdio_output_driver;
drv->fp = stdout;
if (!(drv->cd = iconv_open(charset, "UCS-4BE"))) {
free(drv);
return NULL;
}
return (charfb_output_driver_t *)drv;
}
}
charfb_output_driver_t *(*default_output_driver_factory)() = new_stdio_drv;
#include <stdio.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include "charfb.h"
int main(int argc, char **argv)
{
int err;
int status = 0;
AVFormatContext *ictx = NULL;
AVCodec *dec;
int stream_index;
charfb_t charfb;
charfb_output_driver_t *drv;
if (argc < 2) {
fprintf(stderr, "too few arguments\n");
return 255;
}
avcodec_register_all();
av_register_all();
drv = default_output_driver_factory();
charfb_init(&charfb, drv, 0, 160, 50);
if ((err = avformat_open_input(&ictx, argv[1], NULL, NULL)) < 0) {
fprintf(stderr, "failed to open %s (%d)\n", argv[1], err);
status = 1;
goto out;
}
stream_index = av_find_best_stream(ictx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
if (stream_index < 0) {
fprintf(stderr, "failed to find a valid stream in %s\n", argv[1]);
status = 1;
goto out;
}
{
AVStream *stream = ictx->streams[stream_index];
if ((err = avcodec_open2(stream->codec, dec, NULL)) < 0) {
fprintf(stderr, "failed to open the codec (%d)\n", err);
}
for (;;) {
AVFrame *frame;
AVPacket pkt;
int got_picture = 0;
err = av_read_frame(ictx, &pkt);
if (err == AVERROR(EAGAIN))
continue;
else if (err < 0)
break;
if (pkt.stream_index != stream_index) {
av_free_packet(&pkt);
continue;
}
if (!(frame = avcodec_alloc_frame())) {
status = 3;
goto out;
}
if (avcodec_decode_video2(stream->codec, frame, &got_picture, &pkt) < 0) {
av_free_packet(&pkt);
av_free(frame);
status = 2;
goto out;
}
if (got_picture) {
AVPicture pict;
struct SwsContext *swsctx;
avpicture_fill(&pict, (uint8_t *)charfb.fb.buf, PIX_FMT_ARGB, charfb.fb.width, charfb.fb.height);
swsctx = sws_getContext(
frame->width, frame->height, frame->format,
charfb.fb.width, charfb.fb.height, PIX_FMT_ARGB,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(swsctx, frame->data, frame->linesize, 0, frame->height, pict.data, pict.linesize);
sws_freeContext(swsctx);
}
av_free_packet(&pkt);
av_free(frame);
charfb_render(&charfb);
}
}
out:
if (ictx) {
av_close_input_file(ictx);
}
charfb_fini(&charfb);
drv->fini(drv);
return status;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment