Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
ASCIIMoviePlayerSample.c
/* |
File: ASCIIMoviePlayerSample.c |
Description: ASCII art QuickTime Movie Player |
Author: QuickTime Engineering, DTS |
Copyright: © Copyright 2002-2009 Apple Computer, Inc. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
<5> 04/21/09 DTS dont try and get a path to the file if none was supplied |
<4> 07/19/05 DTS added universal binary compatibility for macintosh |
<3> 04/01/05 DTS dos console goodness (crossplatform file) |
<2> 03/31/05 DTS use data reference APIs |
<1> 05/21/02 QTEngineering first file |
*/ |
/* Top X Tips for better ASCII QuickTime Movie Viewing |
11) Remember Tom Dowdy, he originally wrote this and is missed by all of us |
10) Grow your terminal/console to fit the Movie |
9) Ask marketing folks if you can incorporate this code into your latest QuickTime product |
and see if they think you're serious, then do it behind their back anyway |
8) Set your terminal to White on Black for optimal look |
7) Download your favorite movie trailer |
6) While you're at it, download some Graphics Importer sample code (why not?) |
5) Jedi mind trick your manager "...you want to send me to WWDC" |
4) Order the pizza. |
3) Dim the lights and turn up the audio |
2) Turn off terminal transparancy for fastest performance |
1a) Usage [smelltheglove:/Volumes/Spock] moof% ASCIIMoviePlayer sillymovie.mov |
1b) Usage C:\ ASCIIMoviePlayer.exe sillymovie.mov |
*/ |
#if TARGET_OS_WIN32 |
#include "stdafx.h" |
#define pascal |
#define USE_QD_ACCESSORS 1 |
#else |
#include <stdio.h> |
#include <QuickTime/QuickTime.h> |
#define ESC 27 |
#endif |
#if TARGET_OS_WIN32 |
HANDLE hStdOut = NULL; |
#if USE_QD_ACCESSORS |
Rect * GetPixBounds(PixMapHandle pixMap, Rect *bounds) |
{ |
*bounds = (**pixMap).bounds; |
return bounds; |
} |
#endif |
void GoHome(void) |
{ |
COORD coord = {0, 0}; |
SetConsoleCursorPosition(hStdOut, coord); |
} |
void ClearScreen(void) |
{ |
COORD coord = {0, 0}; |
DWORD count; |
CONSOLE_SCREEN_BUFFER_INFO csbi; |
GetConsoleScreenBufferInfo(hStdOut, &csbi); |
FillConsoleOutputCharacter(hStdOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, coord, &count); |
GoHome(); |
} |
#endif |
// ASCII pixel value array |
char convert[256]; |
// DrawCompleteProc - After the frame has been drawn QuickTime calls us to do some work |
static pascal OSErr DrawCompleteProc(Movie theMovie, long refCon) |
{ |
#define SCALE (2.25) |
#if 0 |
// 16x9 |
#define WIDTH ((float)(80*SCALE)) |
#define HEIGHT ((float)(17*SCALE)) |
#else |
// 4x3 |
#define WIDTH ((float)(80*SCALE)) |
#define HEIGHT ((float)(24*SCALE)) |
#endif |
int y, x; |
GWorldPtr offWorld = (GWorldPtr)refCon; |
Rect bounds; |
Ptr baseAddr; |
long rowBytes; |
// get the information we need from the GWorld |
GetPixBounds(GetGWorldPixMap(offWorld), &bounds); |
baseAddr = GetPixBaseAddr(GetGWorldPixMap(offWorld)); |
rowBytes = QTGetPixMapHandleRowBytes(GetGWorldPixMap(offWorld)); |
#if TARGET_OS_WIN32 |
GoHome(); |
#else |
// goto home |
printf("%c[0;0H", ESC); |
#endif |
// for each row |
for (y = 0; y < HEIGHT; ++y) { |
long *p; |
// for each pixel |
p = (long*)(baseAddr + rowBytes * (long)(y * ((bounds.bottom - bounds.top) / HEIGHT))); |
for (x = 0; x < WIDTH; ++x) { |
UInt32 color; |
long Y; |
long R; |
long G; |
long B; |
color = *(long *)((long)p + 4 * (long)(x*(bounds.right - bounds.left) / WIDTH)); |
R = (color & 0x00FF0000) >> 16; |
G = (color & 0x0000FF00) >> 8; |
B = (color & 0x000000FF) >> 0; |
// convert to YUV for comparison |
// 5 * R + 9 * G + 2 * B |
Y = (R + (R << 2) + G + (G << 3) + (B + B)) >> 4; |
// draw it |
putchar(convert[Y]); |
} |
// next line |
putchar('\n'); |
} |
return noErr; |
} |
#if TARGET_OS_WIN32 |
int _tmain(int argc, _TCHAR* argv[]) |
#else |
int main(int argc, char *argv[]) |
#endif |
{ |
MovieController thePlayer = NULL; |
Movie theMovie = NULL; |
GWorldPtr offWorld; |
Rect bounds; |
short actualResId = DoTheRightThing; |
int i; |
OSErr result = 0; |
MovieDrawingCompleteUPP myDrawCompleteProc = NewMovieDrawingCompleteUPP(DrawCompleteProc); |
#if TARGET_OS_WIN32 |
FSSpec theFSSpec; |
short resRefNum = -1; |
#else |
// Using Data Reference calls now |
OSType myDataRefType; |
Handle myDataRef = NULL; |
CFStringRef inPath; |
#endif |
/* build the luminance value to ASCII value conversion table |
Y ASCII |
0 - 30 space |
31 - 40 . |
41 - 51 , |
52 - 61 : |
62 - 71 ! |
72 - 81 - |
82 - 92 + |
93 - 102 = |
103 - 112 ; |
113 - 122 i |
123 - 133 o |
134 - 143 t |
144 - 153 7 |
154 - 163 6 |
164 - 174 x |
175 - 184 0 |
185 - 194 s |
195 - 204 & |
205 - 215 8 |
216 - 225 % |
226 - 235 # |
236 - 245 @ |
246 - 255 $ |
*/ |
for (i = 0; i < 256; ++i) { |
char *table = " .,:!-+=;iot76x0s&8%#@$"; |
convert[i] = table[i * strlen(table) / 256]; |
} |
#if TARGET_OS_WIN32 |
InitializeQTML(0); |
EnterMovies(); |
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); |
if (NULL == hStdOut) return -1; |
ClearScreen(); |
result = NativePathNameToFSSpec(argv[1], &theFSSpec, 0 /* flags */); |
if (result) {printf("NativePathNameToFSSpec failed %d\n", result); goto bail; } |
result = OpenMovieFile(&theFSSpec, &resRefNum, 0); |
if (result) {printf("OpenMovieFile failed %d\n", result); goto bail; } |
result = NewMovieFromFile(&theMovie, resRefNum, &actualResId, (unsigned char *) 0, 0, (Boolean *) 0); |
if (result) {printf("NewMovieFromFile failed %d\n", result); goto bail; } |
if (resRefNum != -1) |
CloseMovieFile(resRefNum); |
#else |
EnterMovies(); |
// home |
printf("%c[0;0H", ESC); |
// erase to end of display |
printf("%c[0J", ESC); |
// Convert movie path to CFString |
if (argc > 1) { |
inPath = CFStringCreateWithCString(NULL, argv[1], CFStringGetSystemEncoding()); |
if (!inPath) { printf("Could not get CFString\n"); goto bail; } |
} else { printf("You need to at least type a path to a .mov file!\n"); goto bail; } |
// create the data reference |
result = QTNewDataReferenceFromFullPathCFString(inPath, kQTNativeDefaultPathStyle, |
0, &myDataRef, &myDataRefType); |
if (result) { printf("Could not get DataRef %d\n", result); goto bail; } |
// get the Movie |
result = NewMovieFromDataRef(&theMovie, newMovieActive, |
&actualResId, myDataRef, myDataRefType); |
if (result) { printf("Could not get Movie from DataRef %d\n", result); goto bail; } |
// dispose the data reference handle - we no longer need it |
DisposeHandle(myDataRef); |
#endif |
GetMovieBox(theMovie, &bounds); |
// use kNativeEndianPixMap flag so we do the right thing on Intel-based macs |
QTNewGWorld(&offWorld, k32ARGBPixelFormat, &bounds, NULL, NULL, kNativeEndianPixMap); |
LockPixels(GetGWorldPixMap(offWorld)); |
SetGWorld(offWorld, NULL); |
thePlayer = NewMovieController(theMovie, &bounds, mcTopLeftMovie | mcNotVisible); |
SetMovieGWorld(theMovie, offWorld, NULL); |
SetMovieActive(theMovie, true); |
SetMovieDrawingCompleteProc(theMovie, movieDrawingCallWhenChanged, myDrawCompleteProc, (long)offWorld); |
MCDoAction(thePlayer, mcActionPrerollAndPlay, (void *)Long2Fix(1)); |
do { |
MCIdle(thePlayer); |
} while (!IsMovieDone(theMovie)); |
bail: |
if (thePlayer) DisposeMovieController(thePlayer); |
if (theMovie) DisposeMovie(theMovie); |
if (myDrawCompleteProc) DisposeMovieDrawingCompleteUPP(myDrawCompleteProc); |
return result; |
} |
Copyright © 2009 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2009-04-21