Author Topic: ASCII AVI  (Read 5870 times)

0 Members and 1 Guest are viewing this topic.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
ASCII AVI
« on: July 11, 2006 »
http://members.iinet.net.au/~jimshaw/ascii.zip
Run ascii.exe and point it at an avi file (some xvids don't work, sorry).
Might take a few seconds (a minute?) to pre-compute some stuff after you've picked the file.
Have fun!
Jim

Here's the source (C++).  If you try to use it with devc++ you need to link with winmm.lib and vfw32.lib.
Code: [Select]
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <mmsystem.h>
#include <vfw.h>
#include <wincon.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <assert.h>

#define SCREEN_WIDTH 80
#define SCREEN_HEIGHT 25

#define FIRST_CHAR 32
#define LAST_CHAR 255
//#define FIRST_CHAR '0'
//#define LAST_CHAR '9'
#define NUM_CHARS (LAST_CHAR-FIRST_CHAR)

CHAR_INFO screen[SCREEN_WIDTH*SCREEN_HEIGHT];

void Sprite(int xx, int yy, unsigned int *spr, unsigned int w, unsigned int h);

struct
{
unsigned int rgb;
unsigned int h,s,v;
} colourtable[NUM_CHARS][256];

struct
{
unsigned int fg;
unsigned int bg;
unsigned int rf,gf,bf;
unsigned int rb,gb,bb;
} colours[256];

struct
{
unsigned char ch;
unsigned char col;
} lookup[32768];

unsigned int myabs(int x)
{
return x>=0?x:-x;
}

void loadimage(const char *fname, unsigned int **buffer)
{
struct
{
BITMAPINFOHEADER bmih;
RGBQUAD bmic[4];
} bmp={0};
HBITMAP hbm;
HDC hdc;
hbm = (HBITMAP)LoadImage(NULL, fname, IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
hdc = GetDC(NULL);
bmp.bmih.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hdc, hbm, 0,0, NULL, (BITMAPINFO *)&bmp, 0);
bmp.bmih.biBitCount = 32;
*buffer = new unsigned int [myabs(bmp.bmih.biHeight)*bmp.bmih.biWidth];
GetDIBits(hdc, hbm, 0, bmp.bmih.biHeight, *buffer, (BITMAPINFO *)&bmp, DIB_RGB_COLORS);
ReleaseDC(NULL, hdc);
DeleteObject((HGDIOBJ)hbm);

int w = bmp.bmih.biWidth;
int h = myabs(bmp.bmih.biHeight);
unsigned int tmp[2048];
unsigned int *src = *buffer;
unsigned int *dst = *buffer+(h-1)*w;
int y;
for (y = 0; y < h/2; y++)
{
memcpy(tmp, src, w*sizeof *src);
memcpy(src, dst, w*sizeof *src);
memcpy(dst, tmp, w*sizeof *src);
src += w;
dst -= w;
}

}

void freeimage(unsigned int *buffer)
{
delete [] buffer;
}

PAVISTREAM avistream;
HDC avihdc;
HBITMAP avibmp;
unsigned int currframe;
PGETFRAME frame;
unsigned int fps;

bool openavi(const char *fname)
{
AVISTREAMINFO info;

if (AVIStreamOpenFromFile(&avistream, fname, streamtypeVIDEO, 0, OF_READ, NULL))
return false;
if ((frame = AVIStreamGetFrameOpen(avistream, NULL))==NULL)
return false;
AVIStreamLength(avistream);
AVIStreamInfo(avistream, &info, sizeof info);
fps = info.dwRate/info.dwScale;

currframe = 0;

HDC hdc = GetDC(NULL);
avihdc = CreateCompatibleDC(hdc);
avibmp = CreateCompatibleBitmap(hdc, SCREEN_WIDTH, SCREEN_HEIGHT);
SetStretchBltMode(avihdc, HALFTONE);
SetBrushOrgEx(avihdc, 0,0, NULL);
SelectObject(avihdc, avibmp);

ReleaseDC(NULL, hdc);
return true;
}

bool avigetframe(void)
{
BITMAPINFOHEADER *bmi;
unsigned int avispr[SCREEN_WIDTH*SCREEN_HEIGHT];
struct
{
BITMAPINFOHEADER bmih;
RGBQUAD bmic[4];
} bmp={0};

bmp.bmih.biSize = sizeof(BITMAPINFOHEADER);

bmi = (BITMAPINFOHEADER *)AVIStreamGetFrame(frame, currframe++);
if (bmi == NULL)
return false;

StretchDIBits(avihdc, 0,0, SCREEN_WIDTH,SCREEN_HEIGHT, 0,0, bmi->biWidth,bmi->biHeight, (void *)(bmi+1), (BITMAPINFO *)bmi, DIB_RGB_COLORS, SRCCOPY);
GetDIBits(avihdc, avibmp, 0,0, NULL, (BITMAPINFO *)&bmp, 0);
GetDIBits(avihdc, avibmp, 0,SCREEN_HEIGHT, avispr, (BITMAPINFO *)&bmp, DIB_RGB_COLORS);

int w = bmp.bmih.biWidth;
int h = myabs(bmp.bmih.biHeight);
unsigned int tmp[2048];
unsigned int *src = avispr;
unsigned int *dst = avispr+(h-1)*w;
int y;
for (y = 0; y < h/2; y++)
{
memcpy(tmp, src, w*sizeof *src);
memcpy(src, dst, w*sizeof *src);
memcpy(dst, tmp, w*sizeof *src);
src += w;
dst -= w;
}

Sprite(0,0,avispr,SCREEN_WIDTH, SCREEN_HEIGHT);
return true;
}

void avirestart(void)
{
currframe = 0;
}

void closeavi(void)
{
DeleteObject(avibmp);
DeleteDC(avihdc);

AVIStreamGetFrameClose(frame);
AVIStreamRelease(avistream);
}

void rgb2hsv(unsigned int r, unsigned int g, unsigned int b, unsigned int *h, unsigned int *s, unsigned int *v)
{
unsigned int mn, mx;
int d;
int ht;

if (r <= g && r <= b)
mn = r;
else if (g <= r && g <= b)
mn = g;
else
mn = b;

if (r >= g && r >= b)
mx = r;
else if (g >= r && g >= b)
mx = g;
else
mx = b;

d = mx - mn;
*v = mx;

if (mx == 0 || (mx-mn) == 0)
{
*s = 0;
*h = 0;
}
else
{
*s = (d<<8)/mx;
if (mx == r)
ht = (int)((g-b)<<8)/d;
else if (mx == g)
ht = 512+(int)((b-r)<<8)/d;
else
ht = 1024+(int)((r-g)<<8)/d;
ht = (ht*60)>>8;
if (ht < 0)
ht += 360;
*h = ht;
}
}

void buildcolourtable(void)
{
unsigned int rf,gf,bf;
unsigned int rb,gb,bb;
unsigned int x;

for (x = 0; x < 256; x++)
{
if (x&FOREGROUND_BLUE)
bf = 127;
else
bf = 0;
if (x&FOREGROUND_GREEN)
gf = 127;
else
gf = 0;
if (x&FOREGROUND_RED)
rf = 127;
else
rf = 0;
if (x&FOREGROUND_INTENSITY)
{
bf<<=1;
gf<<=1;
rf<<=1;
}
if (x&BACKGROUND_BLUE)
bb = 127;
else
bb = 0;
if (x&BACKGROUND_GREEN)
gb = 127;
else
gb = 0;
if (x&BACKGROUND_RED)
rb = 127;
else
rb = 0;
if (x&BACKGROUND_INTENSITY)
{
bb<<=1;
gb<<=1;
rb<<=1;
}
colours[x].fg = (rf<<16)|(gf<<8)|bf;
colours[x].rf = rf;
colours[x].gf = gf;
colours[x].bf = bf;
colours[x].bg = (rb<<16)|(gb<<8)|bb;
colours[x].rb = rb;
colours[x].gb = gb;
colours[x].bb = bb;
}
}

unsigned char colourmatch(unsigned int rgb, unsigned char *ch)
{
unsigned int r,g,b;
unsigned int h,s,v;
int dh,ds,dv;
unsigned int x;
unsigned int dist, d;
unsigned int fx,fz;
r = rgb&0xff0000;
g = rgb&0x00ff00;
b = rgb&0x0000ff;

rgb2hsv(r>>16,g>>8,b,&h,&s,&v);

dist = UINT_MAX;
fx=fz=0;
for (x = 0; x < NUM_CHARS; x++)
{
for (int z = 0; z < 256; z++)
{
//dh=ds=dv=0;
dh = h - colourtable[x][z].h;
ds = s - colourtable[x][z].s;
dv = v - colourtable[x][z].v;
d = dh*dh + ds*ds + dv*dv;
if (d < dist)
{
dist = d;
fz = z;
fx = x;
}
}
}
*ch = (unsigned char)(FIRST_CHAR+fx);
return (unsigned char)fz;
}

unsigned char lookupcolourmatch(unsigned int rgb, unsigned char *ch)
{
rgb = ((rgb>>3)&0x001f)|((rgb>>6)&0x3e0)|((rgb>>9)&0x7c00);
*ch = lookup[rgb].ch;
return lookup[rgb].col;
}


void createlookup(void)
{
unsigned int r,g,b,rgb;
unsigned int x;

for (x = 0; x < 32768; x++)
{
r = x&0x7C00;
g = x&0x3E0;
b = x&0x1F;

rgb = (r<<9)|(g<<6)|(b<<3);
rgb |= (rgb>>5)&0x070707;

lookup[x].col = colourmatch(rgb, &lookup[x].ch);
}
}

void create_colours(unsigned int c, unsigned int *bmp, unsigned int w, unsigned int h, unsigned int bg, unsigned fg)
{
unsigned int scale = w*h;
unsigned int r,g,b;
int x;
bmp;
for (x = 0; x < 256; x++)
{
r = (bg*colours[x].rb + fg*colours[x].rf)/scale;
g = (bg*colours[x].gb + fg*colours[x].gf)/scale;
b = (bg*colours[x].bb + fg*colours[x].bf)/scale;

if (r>255) r = 255;
if (g>255) g = 255;
if (b>255) b = 255;

colourtable[c-FIRST_CHAR][x].rgb = (r<<16)|(g<<8)|b;
rgb2hsv(r,g,b,&colourtable[c-FIRST_CHAR][x].h, &colourtable[c-FIRST_CHAR][x].s, &colourtable[c-FIRST_CHAR][x].v);
}
}

void compute_colours(HFONT font, unsigned int w, unsigned int h)
{
HDC hdc,hdc2;
HBITMAP memBM;

hdc = GetDC(NULL);
hdc2 = CreateCompatibleDC(hdc);
memBM = CreateCompatibleBitmap(hdc,w,h);
ReleaseDC(NULL, hdc);

  Â  SelectObject(hdc2, memBM);
SelectObject(hdc2, font);

unsigned int *letter = new unsigned int[w*h];

buildcolourtable();

unsigned int x,d,a;
for (x = FIRST_CHAR; x <= LAST_CHAR; x++)
{
char xstr[1];
xstr[0]=(char)x;
TextOut(hdc2, 0,0, xstr, 1);
unsigned int bg,fg;
bg=fg=0;
for (d = 0; d < h; d++)
{
for (a = 0; a < w; a++)
{
letter[a+d*w] = (unsigned int)GetPixel(hdc2, a,d);
if (letter[a+d*w]==0xffffff)
bg++;
else
fg++;
}
}
create_colours(x,letter,w,h,bg,fg);
}
delete [] letter;
DeleteObject(memBM);
DeleteDC(hdc2);

createlookup();
}

void Print(int xx, int yy, const char *string, unsigned char colour)
{
size_t len;
len = strlen(string);
CHAR_INFO *dst;

dst = &screen[xx+yy*SCREEN_WIDTH];
while (len--)
{
dst->Char.AsciiChar = *string++;
dst->Attributes = colour;
dst++;
}
}

void Plot(int x, int y, unsigned int colour)
{
CHAR_INFO *dst;

dst = &screen[x+y*SCREEN_WIDTH];
dst->Attributes = lookupcolourmatch(colour, (unsigned char *)&dst->Char.AsciiChar);
}

void Sprite(int xx, int yy, unsigned int *spr, unsigned int w, unsigned int h)
{
int x, y;
CHAR_INFO *dst;

dst = &screen[xx+yy*SCREEN_WIDTH];

for (y = yy; y < (int)(yy+h); y++)
{
for (x = xx; x < (int)(xx+w); x++)
{
dst->Attributes = lookupcolourmatch(*spr++, (unsigned char *)&dst->Char.AsciiChar);
dst++;
}
dst += SCREEN_WIDTH-w;
}
}

int main(void)
{
HANDLE output;
COORD size = {SCREEN_WIDTH,SCREEN_HEIGHT};
COORD origin = {0,0};
SMALL_RECT dim = {0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1};
CONSOLE_FONT_INFO fonti;
COORD fontsize;
HFONT font;

timeBeginPeriod(1);
AVIFileInit();

//create the console
output = CreateConsoleScreenBuffer(GENERIC_WRITE|GENERIC_READ , 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleActiveScreenBuffer(output);
SetConsoleScreenBufferSize(output, size);
GetCurrentConsoleFont(output, TRUE, &fonti);
fontsize = GetConsoleFontSize(output, fonti.nFont);

//unsigned int *bee;
//loadimage(NULL, &bee);
OPENFILENAME op;
char filename[_MAX_PATH];
char *load_ext=".avi";
BOOL res;

filename[0] = '\0';

op.lStructSize = sizeof(OPENFILENAME);
op.hwndOwner = NULL;
op.hInstance = 0;
op.lpstrFilter = "AVI Files\0*.avi\0All Files\0*\0";
op.lpstrCustomFilter = NULL;
op.nMaxCustFilter = 0;
op.nFilterIndex = 0;//curr_file_ext;
op.lpstrFile = filename;// <- default file name
op.nMaxFile = _MAX_PATH;
op.lpstrFileTitle = NULL;
op.nMaxFileTitle = 0;
op.lpstrInitialDir = NULL;// <- default dir
op.lpstrTitle = "Select File to Load";
op.Flags = OFN_ENABLESIZING|OFN_FILEMUSTEXIST|OFN_EXPLORER|OFN_LONGNAMES|OFN_NOREADONLYRETURN|OFN_PATHMUSTEXIST;
op.nFileOffset = 0;
op.nFileExtension = 0;
op.lpstrDefExt = load_ext;
op.lCustData = 0;
op.lpfnHook = NULL;
op.lpTemplateName = NULL;

res = GetOpenFileName(&op);

if (!res)
goto novid;

if (!openavi(filename))
{
MessageBox(NULL, "Sorry, that AVI file can't be played.", "Video Error", MB_ICONERROR|MB_OK);
goto novid;
}

//graphics version of console font
font = CreateFont(
-fontsize.Y,
fontsize.X,
0,0,
FW_DONTCARE,
0,0,0,
OEM_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
NONANTIALIASED_QUALITY,
FIXED_PITCH|FF_DONTCARE,
"Terminal"
);
compute_colours(font, fontsize.X, fontsize.Y);
DeleteObject(font);

LARGE_INTEGER pc,fq,ti;
QueryPerformanceFrequency(&fq);
QueryPerformanceCounter(&pc);

for (;;)
{
if (!avigetframe())
{
avirestart();
avigetframe();
}

//Sprite(0,0,bee,80,25);
QueryPerformanceCounter(&ti);
char tmp[256];
sprintf(tmp, "%3.2f", (double)fq.QuadPart/(ti.QuadPart-pc.QuadPart));
Print(0,0,tmp,FOREGROUND_RED|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY|FOREGROUND_INTENSITY);
pc = ti;

WriteConsoleOutput(output, screen, size, origin, &dim);

if (GetAsyncKeyState(VK_ESCAPE))
break;
Sleep(1000/fps);
}
closeavi();

novid:
CloseHandle(output);
AVIFileExit();
timeEndPeriod(1);

return 0;
}
« Last Edit: July 11, 2006 by Jim »
Challenge Trophies Won:

Offline Tetra

  • DBF Aficionado
  • ******
  • Posts: 2532
  • Karma: 83
  • Pirate Monkey!
    • View Profile
Re: ASCII AVI
« Reply #1 on: July 11, 2006 »
Thats pretty cool, I didnt really know what to expect and was fairly supprised. Nice one Jim  8)
Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17394
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: ASCII AVI
« Reply #2 on: July 11, 2006 »
Had lots of fun lololm8! :)

Most of the stuff I pointed it at didn't work, but then found a file called clock.avi and it worked really well! Nice one Jim.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Deleter

  • C= 64
  • **
  • Posts: 73
  • Karma: 11
    • View Profile
    • Deleter's Rants
Re: ASCII AVI
« Reply #3 on: July 11, 2006 »
bah, i guess I wont submit my much less functional version of pretty much the same thing...(you had to extract the frames and then use a program to convert them to 'asciivid' format.)

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17394
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: ASCII AVI
« Reply #4 on: July 11, 2006 »
The more the merrier dude! Or perhaps you could adapt your program to do something else?
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Clyde

  • A Little Fuzzy Wuzzy
  • DBF Aficionado
  • ******
  • Posts: 7271
  • Karma: 71
    • View Profile
Re: ASCII AVI
« Reply #5 on: July 11, 2006 »
@Jim, Im heading to find some avi's and try this out. Cool idea.
@Deleter please post it dude.

Cheers and all the best,
Clyde.
Still Putting The IT Into Gravy
If Only I Knew Then What I Know Now.

Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: ASCII AVI
« Reply #6 on: July 11, 2006 »
Use virtualdubmod to convert almost anything to AVI format (pick Indeo or Intel or uncompressed formats using the 'Change' button on the Save As menu) http://virtualdubmod.sourceforge.net/.

Also, Alt-Enter goes fullscreen.  You need to squint through your eyelashes to see the effect best.

Thanks for the comments. :)

@Deleter - please post!  I'm really interested to see how you do the conversion to ascii, I don't think my way is particularly good.

Jim
Challenge Trophies Won:

Offline Ghost^BHT

  • Clueless and Happy
  • ^GVY
  • Pentium
  • ******
  • Posts: 931
  • Karma: 49
  • BYTE ME!
    • View Profile
Re: ASCII AVI
« Reply #7 on: July 11, 2006 »
Cool program :) well done :cheers:

Offline Clyde

  • A Little Fuzzy Wuzzy
  • DBF Aficionado
  • ******
  • Posts: 7271
  • Karma: 71
    • View Profile
Re: ASCII AVI
« Reply #8 on: July 11, 2006 »
Thats pretty cool Jim :)
Still Putting The IT Into Gravy
If Only I Knew Then What I Know Now.

Challenge Trophies Won: