Skip to content

Instantly share code, notes, and snippets.

@kuenishi
Forked from moriyoshi/charfb.c
Created June 8, 2013 13:01
Show Gist options
  • Save kuenishi/5735114 to your computer and use it in GitHub Desktop.
Save kuenishi/5735114 to your computer and use it in GitHub Desktop.
#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;
}
Copy link

ghost commented Jan 11, 2016

Thank you for sharing this implementation, it will be useful for making it in elisp.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment