Last active
December 17, 2015 23:59
-
-
Save moriyoshi/5693011 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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