'=========================================================================== ' Subject: OPENAVI VERSION 0.3 Date: 11-01-98 (05:17) ' Author: Yousuf Philips Code: QB, QBasic, PDS ' Origin: philipz@emirates.net.ae Packet: GRAPHICS.ABC '=========================================================================== '''''''''''''''''''''''''''''''''''''' ' Program : Plays AVI Files ' ' Name : OPENAVI Version 0.3 ' ' Programmer : Yousuf Philips ' ' Company : Y P I ' ' Updated On : 25th of Oct. 1998 ' ' Email - [philipz85@hotmail.com] ' ' [http://members.xoom.com/Philipz/] ' '''''''''''''''''''''''''''''''''''''' '/* Do not edit this file if you distribute it. */' '/* (c) Copyrighted by YPI in 1998 | All Rights Reserved | Public Domain */' '/* This program has been created by YPI (Basic Programming Incorporation) */' '/* as a utility to play AVI files in QBASIC. */' '/* */' '/* What's New - */' '/* * 24-BIT uncompressed AVIs won't play */' '/* * Only plays 8-BIT AVIs which are smaller than (321 X 201) */' '/* * AVI image is not converted to BSAVE file */' '/* * Smartdrv is no longer needed */' '/* * Interrupts have been added to blast the display of AVI */' '/* */' '/* What's Great - */' '/* * Delay Function will work perfectly on any PC */' '/* * AVI displays very fast (even on a 486) */' '/* */' '/* Some Notes - */' '/* In the file format of the AVI there is a value which tells */' '/* how many miliseconds should be delayed after each frame, so */' '/* the FUNCTION Delay was created to delay the required time */' '/* after each frame (It will work the same on any computer). */' '/* If you don't want to run the delay after each frame, then */' '/* you should comment (') out line 165. */' '/* An original program created by the professional programmers at YPI. */' '/* If you use any of this code in your program then you must credit YPI, */' '/* it would be appreciated if you sent us a copy of your program also. */' '/* Please send your comments and suggestions to */' '/* YPI has also created a BMP loader, PCX loader and an FLI player. The */' '/* source can be gotten from our website */' '/* The YPI Website has programs for beginners, tutorials and utilities. */' DECLARE SUB GetSpeed () DECLARE SUB ShowAVI (FileName$) DECLARE SUB Delay (MiliSeconds%) '/* 4 Added functions to use interrupt &H21 */' DECLARE SUB Close21 (Handle%) DECLARE SUB Seek21 (Handle%, Offset!) DECLARE SUB Open21 (FileName$, Handle%) DECLARE SUB Get21 (Handle%, NoOfBytesToRead%, VariableSegment%, VariableOffset%) '/* 2 Added functions to call interrupts in QBASIC 1.0 */' DECLARE SUB NewInterrupt (intnum AS INTEGER, Regs AS ANY) DECLARE SUB InitInterrupt () TYPE RIFFHeaderType ValidID AS STRING * 4 '/* Must be = 'RIFF' SizeOfFile AS LONG '/* Size of AVI file in bytes RIFFFileType AS STRING * 4 '/* RIFF file type - Must be = 'AVI ' END TYPE TYPE AVIHeader ValidID AS STRING * 4 '/* Must be = 'avih' BytesInHeader AS LONG '/* Bytes in AVI Header MicrosecPerFrame AS LONG '/* Number of Milliseconds between each Frame MaximumBytesPerSec AS LONG '/* Number of bytes the system must handle '/* per second for the avi to run smoothly Reserved1 AS LONG '/* Reserved must be 0 BitFlags AS LONG '/* Bit Flags TotalFrames AS LONG '/* Total Number of Frames InitialFrame AS LONG '/* Not Understood NoOfStreams AS LONG '/* Number of Streams BufferSize AS LONG '/* Buffer size to read a frame Widthz AS LONG '/* Width of AVI Heightz AS LONG '/* Height of AVI Scale AS LONG '/* Not Understood (Not Important) Rate AS LONG '/* Not Understood (Not Important) Start AS LONG '/* Not Understood (Not Important) Length AS LONG '/* Not Understood (Not Important) END TYPE TYPE StreamHeader HeaderID AS STRING * 4 '/* Must be = 'strh' BytesInHeader AS LONG '/* Bytes in Stream Header Typez AS STRING * 4 '/* Type of Stream Header '/* vids - For Video Stream '/* auds - For Audio Stream Handle AS STRING * 4 '/* Name of Compressor BitFlags AS LONG '/* Not Understood (Not Important) Reserved1 AS LONG '/* Not Understood (Not Important) InitialFrames AS LONG '/* Not Understood (Not Important) Scale AS LONG '/* Not Understood (Not Important) Rate AS LONG '/* Not Understood (Not Important) Start AS LONG '/* Not Understood (Not Important) Length AS LONG '/* Not Understood (Not Important) BufferSize AS LONG '/* Not Understood (Not Important) Quality AS LONG '/* Not Understood (Not Important) SampleSize AS LONG '/* Not Understood (Not Important) END TYPE TYPE StreamFormat StreamFormatID AS STRING * 4 '/* Must be = 'strf' BytesInFormat AS LONG '/* Number of Bytes in Stream Format END TYPE TYPE BMPInfoHeader '/* Windows 3.x BMP Information Header SizeOfHeader AS LONG '/* Number of Bytes of Header = 40 ImageWidth AS LONG '/* Width of AVI ImageHeight AS LONG '/* Height of AVI Planes AS INTEGER '/* Planes - Must be 1 BitsPerPixel AS INTEGER '/* Bits Per Pixel - 8 or 24 CompressMethod AS LONG '/* Compression Method '/* 0 - Uncompressed '/* 1 - 8-BIT RLE '/* 2 - 4-BIT RLE (Impossible) ImageSizeInBytes AS LONG '/* Number of bytes in every image HorizontalRatio AS LONG '/* Not Important VerticalRatio AS LONG '/* Not Important ColorsUsed AS LONG '/* Number of used colors ImportantColors AS LONG '/* Number of Important colors END TYPE TYPE JunkChunk '/* Junk Chunk - Used for padding ChunkID AS STRING * 4 '/* Must be = 'JUNK' EmptyCharacters AS LONG '/* Number of empty bytes END TYPE TYPE ImageData '/* Image Data - Specifies type of Image Data ChunkID AS STRING * 4 '/* Type of image data '/* db - Bitmap Uncompressed data '/* dc - Bitmap Compressed data '/* wb - Sound data '/* pc - Palette Change NumberOfBytes AS LONG '/* Number of Bytes of data END TYPE TYPE ChangingPalette '/* Changing Palette for different colors FirstColor AS STRING * 1 NumberOfColorsToChange AS STRING * 1 BitFlags AS INTEGER END TYPE TYPE RegType '/* Registers for Interrupts ax AS INTEGER bx AS INTEGER cx AS INTEGER dx AS INTEGER bp AS INTEGER si AS INTEGER di AS INTEGER flags AS INTEGER ds AS INTEGER es AS INTEGER END TYPE COMMON SHARED Regs AS RegType, Speed& DIM SHARED Intrpt(1 TO 50) AS INTEGER '/* Initializes Interrupt Functions (Very Important, don't touch) */' InitInterrupt CLS '/* Comment out GetSpeed if you don't want to have a delay between frames */' GetSpeed PRINT PRINT " 1st QBASIC AVI Player (ver 0.3) - By YPI (BASIC Programming Incorporation)" PRINT " Press Any Key When You Want The AVI To Stop Playing (Don't press Ctrl-Break)" INPUT " Enter File Name - ", FileName$ IF LEN(LTRIM$(FileName$)) = 0 THEN END ELSEIF INSTR(FileName$, ".") = 0 THEN FileName$ = FileName$ + ".avi" END IF CALL ShowAVI(FileName$) Wait$ = INPUT$(1) WHILE INKEY$ <> "": WEND '/* Some ending statements for those how didn't read the comments at the */' '/* beginning of the program. */' SCREEN 2: SCREEN 0 PRINT " 1st QBASIC AVI Player (ver 0.3) - By YPI (BASIC Programming Incorporation)" PRINT " Program is Public Domain, (c) Copyrighted by YPI, All Rights Reserved" PRINT " Programmed By Yousuf Philips in 1998" PRINT " Send suggestions and comments to philipz85@hotmail.com" PRINT " If you have any information of AVI compression algorithms, please contact me" PRINT " Visit the YPI Website at http://members.xoom.com/Philipz/" Wait$ = INPUT$(1) DEFINT A-Z SUB Close21 (Handle) '/* Don't edit this SUB if you don't have any knowledge of Interrupts */' Regs.ax = &H3E00 Regs.bx = Handle CALL NewInterrupt(&H21, Regs) END SUB DEFSNG A-Z SUB Delay (MiliSeconds%) '/* This function slows down the program for the given amount of Miliseconds */' DelayTime = (Speed& * 5) * (MiliSeconds% / 1000) FOR Speed = 1 TO DelayTime NEXT Speed END SUB DEFINT A-Z SUB Get21 (Handle, NoOfBytesToRead, VariableSegment, VariableOffset) '/* Don't edit this SUB if you don't have any knowledge of Interrupts */' Regs.ax = &H3F00 Regs.bx = Handle Regs.cx = NoOfBytesToRead Regs.ds = VariableSegment Regs.dx = VariableOffset CALL NewInterrupt(&H21, Regs) END SUB DEFSNG A-Z SUB GetSpeed '/* This function finds out the proper delay period needed for the current PC*/' PRINT " Calculating delay for Delay Function according to your PC" Time& = TIMER: Time& = Time& + 1: Speed& = 0 DO LOOP UNTIL TIMER >= Time& DO Speed& = Speed& + 1 LOOP UNTIL TIMER >= Time& + 1 '/* Testing the calculated delay period with the Delay FUNCTION */' Time! = TIMER Delay 1000 Time! = TIMER - Time! '/* If the Delay FUNCTION was not accurate then it is adjusted */' IF Time! < 1 THEN Speed& = INT(Speed& * (1 / Time!)) END IF END SUB DEFINT A-Z SUB InitInterrupt '/* Don't edit this SUB period. */' InterruptData$ = CHR$(85) + CHR$(139) + CHR$(236) + CHR$(86) + CHR$(87) + CHR$(30) + CHR$(139) + CHR$(118) + CHR$(6) + CHR$(139) + CHR$(4) + CHR$(139) + CHR$(92) + CHR$(2) InterruptData$ = InterruptData$ + CHR$(139) + CHR$(76) + CHR$(4) + CHR$(139) + CHR$(84) + CHR$(6) + CHR$(139) + CHR$(108) + CHR$(8) + CHR$(139) + CHR$(124) + CHR$(12) + CHR$(142) + CHR$(68) + CHR$(18) InterruptData$ = InterruptData$ + CHR$(255) + CHR$(116) + CHR$(10) + CHR$(131) + CHR$(124) + CHR$(18) + CHR$(255) + CHR$(117) + CHR$(2) + CHR$(30) + CHR$(7) + CHR$(131) + CHR$(124) + CHR$(16) + CHR$(255) InterruptData$ = InterruptData$ + CHR$(116) + CHR$(3) + CHR$(142) + CHR$(92) + CHR$(16) + CHR$(94) + CHR$(205) + CHR$(33) + CHR$(85) + CHR$(139) + CHR$(236) + CHR$(30) + CHR$(86) + CHR$(142) + CHR$(94) + CHR$(2) + CHR$(139) + CHR$(118) + CHR$(14) InterruptData$ = InterruptData$ + CHR$(137) + CHR$(4) + CHR$(137) + CHR$(92) + CHR$(2) + CHR$(137) + CHR$(76) + CHR$(4) + CHR$(137) + CHR$(84) + CHR$(6) + CHR$(143) + CHR$(68) + CHR$(10) + CHR$(143) + CHR$(68) + CHR$(16) InterruptData$ = InterruptData$ + CHR$(143) + CHR$(68) + CHR$(8) + CHR$(137) + CHR$(124) + CHR$(12) + CHR$(140) + CHR$(68) + CHR$(18) + CHR$(156) + CHR$(143) + CHR$(68) + CHR$(14) InterruptData$ = InterruptData$ + CHR$(95) + CHR$(95) + CHR$(94) + CHR$(93) + CHR$(202) + CHR$(2) + CHR$(0) DEF SEG = VARSEG(Intrpt(1)) address = VARPTR(Intrpt(1)) FOR I = 0 TO 99 POKE address + I, ASC(MID$(InterruptData$, I + 1, 1)) NEXT END SUB SUB NewInterrupt (intnum AS INTEGER, Regs AS RegType) '/* Don't edit this SUB period. */' DEF SEG = VARSEG(Intrpt(1)) address = VARPTR(Intrpt(1)) POKE address + 51, intnum CALL ABSOLUTE(Regs, address) END SUB SUB Open21 (FileName$, Handle) '/* Don't edit this SUB if you don't have any knowledge of Interrupts */' FileName$ = FileName$ + CHR$(0) Regs.ax = &H3D00 Regs.ds = VARSEG(FileName$) Regs.dx = SADD(FileName$) CALL NewInterrupt(&H21, Regs) FileName$ = LEFT$(FileName$, LEN(FileName$) - 1) Handle = Regs.ax END SUB SUB Seek21 (Handle, Offset!) '/* Don't edit this SUB if you don't have any knowledge of Interrupts */' Regs.ax = &H4200 Regs.bx = Handle Regs.cx = Offset! \ 65536 Regs.dx = (Offset! AND 32767) - (Offset! AND 32768) CALL NewInterrupt(&H21, Regs) END SUB SUB ShowAVI (FileName$) OPEN FileName$ FOR BINARY AS #255 IF LOF(255) = 0 THEN PRINT " FILE IS EMPTY" CLOSE #255 KILL FileName$ EXIT SUB END IF '/* Creates the necessary structure types for easy extraction of data */' DIM RIFFHeaderType AS RIFFHeaderType DIM AVIHead AS AVIHeader DIM StreamHead AS StreamHeader DIM StreamForm AS StreamFormat DIM BMPInfoHead AS BMPInfoHeader DIM ImageDataz AS ImageData GET #255, , RIFFHeaderType '/* Checks if the opened file is an AVI file */' IF RIFFHeaderType.RIFFFileType <> "AVI " THEN PRINT " INVALID AVI FILE" END END IF GET #255, 25, AVIHead IF AVIHead.ValidID <> "avih" THEN PRINT " Invalid AVI File Header" EXIT SUB ELSEIF AVIHead.Widthz > 320 OR AVIHead.Heightz > 200 THEN PRINT " AVI Image Is To Large" EXIT SUB END IF '/* Adjusting the delay extracted from the file so that it will work well */' '/* with the FUNCTION Delay */' AVIHead.MicrosecPerFrame = AVIHead.MicrosecPerFrame / 1000 '/* Search through file to find 'LIST', which indicates the starting of a */' '/* stream data area */' Search1: Position& = LOC(255) + 1: DWord$ = SPACE$(4) DO GET #255, Position&, DWord$ Position& = Position& + 4 LOOP UNTIL DWord$ = "LIST" GET #255, , DWord$ GET #255, , DWord$ '/* If the characters 'strl' are encounted then it indicates the beginning of*/' '/* a stream data area */' IF DWord$ = "strl" THEN Position& = LOC(255) + 1 GET #255, , StreamHead '/* Checks if the stream is a video stream indicated by the characters */' '/* 'vids', audio stream is indicated by the characters 'auds' */' IF StreamHead.Typez <> "vids" THEN Searchz = Searchz + 1 IF Searchz > 2 THEN PRINT " Not Possible For AVI To Have More Than 2 Streams" PRINT " Please Send This AVI To " EXIT SUB END IF GOTO Search1 END IF SEEK #255, Position& + StreamHead.BytesInHeader + 8 GET #255, , StreamForm GET #255, , BMPInfoHead IF BMPInfoHead.BitsPerPixel <> 8 THEN PRINT " Only 8-BIT AVIs Can Be Played" EXIT SUB ELSEIF BMPInfoHead.CompressMethod <> 0 THEN PRINT " Only Uncompressed AVIs Can Be Played" EXIT SUB END IF '/* Changes graphix screen to SCREEN 13 and changes the color palettes */' SCREEN 13 Palette$ = SPACE$(1024) GET #255, , Palette$ FOR Loops = 0 TO 255 OUT &H3C8, Loops OUT &H3C9, INT(ASC(MID$(Palette$, (Loops * 4) + 3, 1)) / 4) OUT &H3C9, INT(ASC(MID$(Palette$, (Loops * 4) + 2, 1)) / 4) OUT &H3C9, INT(ASC(MID$(Palette$, (Loops * 4) + 1, 1)) / 4) NEXT Loops ELSE PRINT " UNABLE TO USE AVI FILE" EXIT SUB END IF '/* Calculate the number of bytes to extract for each image line */' IF 4 - (BMPInfoHead.ImageWidth MOD 4) = 4 THEN BytesToExtract = BMPInfoHead.ImageWidth ELSE BytesToExtract = BMPInfoHead.ImageWidth + (4 - (BMPInfoHead.ImageWidth MOD 4)) END IF '/* Search through file to find 'MOVI', which indicates the beginning of AVI */' '/* image area */' Search: Position& = LOC(255) + 1 DO GET #255, Position&, DWord$ Position& = Position& + 4 IF Position& >= LOF(255) THEN PRINT " Movie Chunk Not Found" EXIT SUB END IF LOOP UNTIL DWord$ = "LIST" GET #255, , DWord$ GET #255, , DWord$ IF DWord$ <> "movi" THEN GOTO Search RealCurrentLocation! = LOC(255) HeightAdjust = (200 - BMPInfoHead.ImageHeight) \ 2 WidthAdjust = (320 - BMPInfoHead.ImageWidth) \ 2 IF HeightAdjust < 0 THEN HeightAdjust = 0 IF WidthAdjust < 0 THEN WidthAdjust = 0 CLOSE '/* Reopen the AVI file */' CALL Open21(FileName$, AVIHandle) Repeat: CurrentLocation! = RealCurrentLocation! CALL Seek21(AVIHandle, CurrentLocation!) IF DWord$ = "movi" THEN FOR FrameNumber = 1 TO AVIHead.TotalFrames CALL Get21(AVIHandle, LEN(ImageDataz), VARSEG(ImageDataz), VARPTR(ImageDataz)) IF RIGHT$(ImageDataz.ChunkID, 2) = "db" THEN FOR YHeight = BMPInfoHead.ImageHeight - 1 TO 0 STEP -1 IF YHeight + HeightAdjust < 100 THEN CALL Get21(AVIHandle, BytesToExtract, &HA000, (YHeight + HeightAdjust) * 320 + WidthAdjust) ELSE CALL Get21(AVIHandle, BytesToExtract, &HA7D0, (YHeight + HeightAdjust - 100) * 320 + WidthAdjust) END IF NEXT YHeight ELSEIF RIGHT$(ImageDataz.ChunkID, 2) = "pc" THEN '/* Skipping the color changing */' ELSEIF RIGHT$(ImageDataz.ChunkID, 2) = "wb" THEN '/* Skipping the sound part of the avi if there is. */' FrameNumber = FrameNumber - 1 ELSEIF RIGHT$(ImageDataz.ChunkID, 2) = "dc" THEN '/* Ending program because compressed data was encountered */' CALL Close21(AVIHandle) SCREEN 2: SCREEN 0 PRINT " Only Uncompressed AVIs Can Be Played" EXIT SUB ELSE CALL Close21(AVIHandle) SCREEN 2: SCREEN 0 PRINT " Something Went Wrong" PRINT " Please Send This AVI To " EXIT SUB END IF '/* Delay FUNCTION - slows down display according to speed given from*/' '/* AVI file */' Delay (AVIHead.MicrosecPerFrame) '/* Checks if the user presses a key */' IF INKEY$ <> "" THEN CALL Close21(AVIHandle) EXIT SUB END IF CurrentLocation! = CurrentLocation! + ImageDataz.NumberOfBytes + 8 CALL Seek21(Handle, CurrentLocation!) NEXT FrameNumber END IF GOTO Repeat END SUB