Code archives/User Libs/Save AVI with Sound
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| Like the framegrabber this one is using AviFil32.dll and some of the codecs listed in the codec selection box won't work. I also guess MP3 won't work for the sound, better use a standard WAV file. Some things may be not implemented 100% correctly, although it worked on my machine. Thanks to the PB Community where I have found most of the infos needed for this. Have fun, Mr. Next-Industrial-Light-and-Magic. ;) | |||||
; Save Avi with sound. Provided by Dieter Marfurt aka jfk 11110
; userlibs:
; avifil32.decls:
;.lib "avifil32.dll"
;AVIFileInit%()
;AVIFileOpen%(ppfile*,szFile$,uMode%,lpHandler%)
;AVIFileRelease%(pfile%)
;AVIFileInfo%(pfile%,pfi*,lSize%)
;AVIFileGetStream%(pfile%,ppavi*,fccType%,lParam%)
;AVIFileExit%()
;AVIFileCreateStream%(pfile%, ppavi*, psi*)
;AVIStreamInfo%(pStream%,pfi*,lSize%)
;AVIStreamStart%(pavi%)
;AVIStreamRelease%(pavi%)
;AVIStreamLength%(pavi%)
;AVIStreamGetFrameOpen%(pavi%,lpbiWanted%)
;AVIStreamGetFrame%(pFrame%,index%)
;AVIStreamGetFrameClose%(pFrame%)
;AVIStreamReadFormat%(pavi%, lPos%, lpFormat%, lpcbFormat*)
;AVIStreamSetFormat%(pavi%, lPos%, lpFormat*, cbFormat%)
;AVIStreamRead%(pavi%, lStart%, lSamples%, lpBuffer%, cbBuffer%, plBytes*, plSamples*)
;AVIStreamWrite%(pavi%, lStart%, lSamples%, lpBuffer*, cbBuffer%, dwflags%, plSampWritten%, plBytesWritten%)
;AVISaveOptions%(hwnd%, uiFlags%, nStreams%, ppavi*, plpOptions*)
;AVISaveOptionsFree%(nstreams%, plpOptions*)
;AVIMakeCompressedStream%(ppsCompressed*, psSource%, lpOptions%, pclsidHandler%)
; kernel32.decls:
;.lib "kernel32.dll"
;RtlMoveMemory2%(Destination*,Source,Length) : "RtlMoveMemory"
Graphics 800,600,32,2
SetBuffer BackBuffer()
Const streamtypeAUDIO = 1935963489
Const streamtypeVIDEO = 1935960438
Const ICMF_CHOOSE_KEYFRAME=1
Const ICMF_CHOOSE_DATARATE=2
Const ICMF_CHOOSE_ALLCOMPRESSORS=8
Const AVIERR_OK=0
Const AVIERR_NOCOMPRESSOR=$80000000 Or $40000 Or ($4000 + 113)
Const AVIERR_MEMORY= $80000000 Or $40000 Or ($4000 + 103)
Const AVIERR_UNSUPPORTED= $80000000 Or $40000 Or ($4000 + 101)
Const AVIIF_KEYFRAME=$10
Const Lib = 0
Const OF_READ=$0
Const OF_WRITE=$1
Const OF_SHARE_DENY_WRITE=$20
Const OF_CREATE=$1000
Global hwnd=SystemProperty$("AppHWND")
; demo:
file$="test_save.avi"
target_width=640
target_height=480
target_rate=25
AVIFileInit(); this needs to be called before any other Avifil32.dll function call
; open avi for writing...
my_handle=OpenWriteAvi(file$,target_width,target_height,target_rate,"test.wav") ; optional last parameter is wav file to be added (will be muxed in the CloseWriteAvi function)
If my_handle=0: CloseWriteAvi(my_handle): AVIFileExit(): End: EndIf
; write 11 frames to the avi
For i=0 To 10
Cls
Color 0,255,0
Rect 0,0,640,480,0
For r=0 To 100
Color Rand(255),Rand(255),Rand(255)
Text (Rand(target_width) And $FFF0),Rand(target_height),i+"*+*"
Next
Flip
AddFrameWriteAvi(my_handle, i); third (optional) parameter may be an image handle (make sure it's big enought), if omitted, the frame content will be grabbed from backbuffer
Next
CloseWriteAvi(my_handle)
AVIFileExit()
Print "ok!"
WaitKey()
End
Function OpenWriteAvi(file$,target_width,target_height,target_rate,soundfile$="")
Local i ; probalby you better make all variables explicit locals (?), I'm too lazy for now
AviControlBank=CreateBank(1024+128) ; this bank will be used to store several bank handles, variables etc. that are required in other functions, especially for closing/releasing things and writing frames to.
PokeInt AviControlBank,36,target_width
PokeInt AviControlBank,40,target_height
PokeInt AviControlBank,44,target_rate
PokeInt AviControlBank,128,Len(soundfile$)
For i=1 To Len(soundfile$)
PokeByte AviControlBank,132+i-1,Asc(Mid$(soundfile$,i,1))
Next
ret=CreateBank($128) ; will hold the avifileopen handle
PokeInt AviControlBank, 8,ret
If AVIFileOpen(ret,file$,OF_WRITE Or OF_CREATE,0)=0
avi_handle=PeekInt(ret,0)
PokeInt AviControlBank, 0,avi_handle
AVISTREAMINFO_bank=CreateBank($ffff)
PokeInt AviControlBank,12,AVISTREAMINFO_bank
; possible flags:
avisf_disabled=$1
avisf_video_palchanges=$10000
avisf_knownflags=$10001
loc_fccType=streamtypeVIDEO
loc_fccHandler=(Asc("c") Shl 24)Or(Asc("v") Shl 16)Or(Asc("s") Shl 8)Or(Asc("m"))
For i=0 To 511 Step 4
PokeInt AVISTREAMINFO_bank,i,0
Next
PokeInt AVISTREAMINFO_bank, 0,loc_fccType
PokeInt AVISTREAMINFO_bank, 4,loc_fccHandler
PokeInt AVISTREAMINFO_bank,20,1000/target_rate; eg 1000/25= 40...
PokeInt AVISTREAMINFO_bank,24,1000;loc_dwRate ; 1000/40= 25 fps (typical M$ :) )
PokeInt AVISTREAMINFO_bank,40,40+(target_width*target_height*3) ;loc_dwSuggestedBufferSize ; 0
If AVIFileCreateStream(avi_handle,ret,AVISTREAMINFO_bank)=0
stream_Handle=PeekInt(ret,0)
PokeInt AviControlBank, 4,stream_handle
; required by AviStreamSetFormat (seems to be the same as the header of DIBHEADER)
BITMAPINFOHEADER=CreateBank(40)
PokeInt AviControlBank,16,BITMAPINFOHEADER
PokeInt BITMAPINFOHEADER, 0,40 ; size of header
PokeInt BITMAPINFOHEADER, 4,target_width ; width
PokeInt BITMAPINFOHEADER, 8,target_height ; height
PokeShort BITMAPINFOHEADER,12,1 ; planes
PokeShort BITMAPINFOHEADER,14,24 ; bitCount
PokeInt BITMAPINFOHEADER,16,0 ; compression (0=no compression in DIB)
PokeInt BITMAPINFOHEADER,20,(target_width*target_height*3);0 ; size in bytes (may be 0 for non compressed)
PokeInt BITMAPINFOHEADER,24,3600 ; horiz pixel per meter
PokeInt BITMAPINFOHEADER,28,3600 ; vert pixel per meter
PokeInt BITMAPINFOHEADER,32,0;$FFFFFF ; Colors used (for palette)
PokeInt BITMAPINFOHEADER,36,0;$FFFFFF ; number of important colors (lol)
; this bank will be used to write our frame data to, so avifil32 can grab it from there
DIBHEADER=CreateBank(40+(target_width*target_height*3)+1000)
PokeInt AviControlBank,20,DIBHEADER
For i=0 To 36 ; we simply reuse BITMAPINFOHEADER
PokeInt DIBHEADER,i,PeekInt(BITMAPINFOHEADER,i)
Next
; A pointer to space for AVICOMPRESSOPTIONS: first Int of bank points to itself (offset 8)
plpo=8
plpOptionsList=CreateBank(8000) ; req. size guessed, but hey...
PokeInt AviControlBank,24,plpOptionsList
compression_handle=CreateBank(8000)
PokeInt AviControlBank,28,compression_handle
dumm_bank=CreateBank(8)
PokeInt AviControlBank,32,dumm_bank
RtlMoveMemory2(dumm_bank,plpOptionsList+4,4)
PokeInt plpOptionsList,0,PeekInt(dumm_bank,0)+plpo
PokeInt plpOptionsList,4,PeekInt(dumm_bank,0)+plpo+4000
If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 ;=0
res=AVIMakeCompressedStream(compression_handle, stream_handle, PeekInt(plpOptionsList,0), 0)
If res=0
;If res= AVIERR_OK Then Print "ok!!!"
;If res= AVIERR_NOCOMPRESSOR Then Print "nocompressor"
;If res= AVIERR_MEMORY Then Print "memory"
;If res= AVIERR_UNSUPPORTED Then Print "unsupported"
If AVIStreamSetFormat(PeekInt(compression_handle,0), 0, BITMAPINFOHEADER,40)=0
Return AviControlBank ; ok ready to rumble
EndIf
EndIf
EndIf
EndIf
EndIf
Return 0 ; bah, failure
End Function
Function CloseWriteAvi(AviControlBank)
Local i
If AviControlBank<>0
avi_handle=PeekInt(AviControlBank, 0)
stream_handle=PeekInt(AviControlBank, 4)
ret=PeekInt(AviControlBank, 8)
AVISTREAMINFO_bank=PeekInt(AviControlBank,12)
BITMAPINFOHEADER=PeekInt(AviControlBank,16)
DIBHEADER=PeekInt(AviControlBank,20)
plpOptionsList=PeekInt(AviControlBank,24)
compression_handle=PeekInt(AviControlBank,28)
dumm_bank=PeekInt(AviControlBank,32)
len_wav=PeekInt(AviControlBank,128)
wav_to_add$=""
For i=1 To len_wav
a=PeekByte(AviControlBank,132+i-1)
If a=0 Then Exit
wav_to_add$=wav_to_add$+Chr$(a)
Next
; close all
If compression_handle<>0
AVIStreamRelease(PeekInt(compression_handle,0))
EndIf
If plpOptionsList<>0
AVISaveOptionsFree(1,plpOptionsList)
EndIf
If stream_Handle<>0
AVIStreamRelease(stream_Handle)
EndIf
; multiplex Audio stream, if any
If (wav_to_add$<>"") And (FileType(wav_to_add$)=1)
AddWavWriteAvi(wav_to_add$,avi_handle)
EndIf
If avi_handle<>0
AVIFileRelease(avi_handle)
EndIf
;free banks...
If ret<>0 Then FreeBank ret
If AVISTREAMINFO_bank<>0 Then FreeBank AVISTREAMINFO_bank
If nullBank<>0 Then FreeBank nullBank
If BITMAPINFOHEADER<>0 Then FreeBank BITMAPINFOHEADER
If DIBHEADER<>0 Then FreeBank DIBHEADER
If plpOptionsList<>0 Then FreeBank plpOptionsList
If compression_handle<>0 Then FreeBank compression_handle
If dumm_bank<>0 Then FreeBank dumm_bank
FreeBank AviControlBank
; i really hope I released everything, otherwise there would be a memoryleak
EndIf
End Function
Function AddFrameWriteAvi(AviControlBank, index, buffer=0)
If AviControlBank<>0
width=PeekInt(AviControlBank,36)
height=PeekInt(AviControlBank,40)
If buffer=0 Then buffer = BackBuffer()
DIBHEADER=PeekInt(AviControlBank,20)
If DIBHEADER<>0
compression_handle=PeekInt(AviControlBank,28)
If compression_handle<>0
Buffer2Dib(width,height,DIBHEADER,buffer)
AVIStreamWrite(PeekInt(compression_handle,0), index, 1, DIBHEADER ,40+(width * height *3) , AVIIF_KEYFRAME, 0,0)
EndIf
EndIf
EndIf
End Function
Function Buffer2Dib(w,h,bank,buffer=0)
Local x,y,count,rgb
If buffer=0 Then buffer=BackBuffer()
count=0
SetBuffer Buffer
LockBuffer Buffer
For y=0 To h-1
For x=0 To w-1
rgb=ReadPixelFast(x,(h-1)-y) And $FFFFFF
PokeByte bank,count+2,(rgb Shr 16) And $FF
PokeByte bank,count+1,(rgb Shr 8) And $FF
PokeByte bank,count+0, rgb And $FF
count=count+3
Next
Next
UnlockBuffer Buffer
End Function
Function AddWavWriteAvi(file$,avi_handle)
Local b=0
wav_handle=CreateBank(8)
If AVIFileOpen(wav_handle,file$, OF_READ, 0)=0
; Print "opened wav"
wavstream_handle=CreateBank(8)
If AVIFileGetStream(PeekInt(wav_handle,0), wavstream_handle, streamtypeAUDIO, 0) =0
; Print "openened wav read stream"
avi_info_bank=CreateBank(256);140
If AVIStreamInfo(PeekInt(wavstream_handle,0), avi_info_bank,140) =0;140
; Print "retrievend wav read stream info"
lfmtSize=CreateBank(2560)
lpFormat=CreateBank(256)
If AVIStreamReadFormat(PeekInt(wavstream_handle,0), 0, 0, lfmtSize) =0
; Print "used to read format of read stream"
If PeekInt(lfmtSize,0)>0
fmtWav=CreateBank(256)
dummy=CreateBank(8)
RtlMoveMemory2(dummy,fmtWav+4,4)
If AVIStreamReadFormat(PeekInt(wavstream_handle,0), 0, PeekInt(dummy,0), lfmtSize)=0
; Print "read format 2"
lStreamLength = AVIStreamLength(PeekInt(wavstream_handle,0))
; Print "got wav lenght"
If lStreamLength <>0
nullBank=CreateBank(lStreamLength)
lpbData = CreateBank(lStreamLength+100000)
RtlMoveMemory2(dummy,lpbData+4,4)
If AVIStreamRead(PeekInt(wavstream_handle,0), 0, lStreamLength, PeekInt(dummy,0), lStreamLength, nullbank, nullbank)=0
; Print "avistreamread wav data"
psAvi=CreateBank(256)
siWav=CreateBank(256)
If AVIFileCreateStream(avi_handle, psAvi, avi_info_bank)=0
; Print "created avi streat for writing audio"
If AVIStreamSetFormat(PeekInt(psAvi,0), 0, fmtWav, PeekInt(lfmtSize,0))=0
; Print "used to set format for audio write stream"
If AVIStreamWrite (PeekInt(psAvi,0), 0, lStreamLength, lpbData, lStreamLength, AVIIF_KEYFRAME, 0, 0)=0
; Print "AviWriteStream: written wav data to stream"
b=1
EndIf
EndIf
AVIStreamRelease(PeekInt(psAvi,0))
EndIf
EndIf
FreeBank lpbData
lpbData=0
EndIf
EndIf
EndIf
EndIf
EndIf
AVIStreamRelease(PeekInt(wavstream_handle,0))
EndIf
AVIFileRelease(PeekInt(wav_handle,0))
EndIf
If wav_handle <>0 Then FreeBank wav_handle
If wavstream_handle <>0 Then FreeBank wavstream_handle
If avi_info_bank <>0 Then FreeBank avi_info_bank
If lfmtSize <>0 Then FreeBank lfmtSize
If lpFormat <>0 Then FreeBank lpFormat
If fmtWav <>0 Then FreeBank fmtWav
If dummy <>0 Then FreeBank dummy
If lpbData <>0 Then FreeBank lpbData
If psAvi <>0 Then FreeBank psAvi
If siWav <>0 Then FreeBank siWav
If nullbank <>0 Then FreeBank nullbank
Return b
End Function |
Comments
| ||
| Memoey Access Violation on RtlMoveMemory2 |
| ||
| MAke sure you read the comments and put the decls in the right place: avifil32.decls and kernel32.decls are in the comments. Allan |
| ||
| Yes, I did. Then had to comment out RtlMoveMemory2 because it was already in another lib <sigh>, So does that mean that the other RtlMoveMemory2 definition is different from yours? |
| ||
| also important: can we expect a bmax port? :P |
| ||
| @ John RTLMoveMemory is indeed a critical function There are 3 of them "on the market" (_from _to _ex) They differ only in the way the parameters are provided (Pointers and/or Variables). I just looked it up a minute ago because I had a MAV using the FreeImage.dll that was mentioned here 1 month ago ;-) |
| ||
| the only diffrence is: if you use a bank pointer (a*) or a plain int (a). So blitz will decide how it's handled. In kernel32.dll it's the same function. If this RtlMoveMemory2 isn't compatible with the one that is already in use by one of your userlibs, then off course you only have to rename it in the source and the kernel32.decls userlib mentioned in the code. Or you may use one of your existing declarations. Only make sure the pointers are used correctly: RtlMoveMemoryWhatever%( bank* ,source_adr,len) : "RtlMoveMemory" The star (*) is important. also important: can we expect a bmax port? :P Maybe you should do that, all your contributions to the community are welcome. However, they sell those tongue cleaners ;). |
| ||
| I realise this is an old code archive entry, but I am seeking some assistance in how to get it to work. I've put the decls in place, yet when I try to run the program (the small included demo in the listing above), I get an MAV (no extra info supplied even in Debug mode) on the following line: (line 184) If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 ;=0 |
| ||
| anyone? |
| ||
| Here the code runs fine. Are you on Vista? I believe that line executes a dialog in which the user can select what compressor should be used. Maybe you can omit this problem by changing these lines to: ;;;If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 ;=0 res=AVIMakeCompressedStream(compression_handle, stream_handle, 0, 0) |
| ||
| Thanks Warner I'll give it a try, I'm on XP though. |
| ||
| Sorry, still didn't work, no debugging errors either. I'll give up on this one I think... |
| ||
| Well, I don't know if anyone's paying attention to this anymore, but I'm having difficulties with this line: If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 |
| ||
| I just see this, sorry ppl. Tho I don't know what your problem is with the code, there yould be several reasons: -Microsofts Implementation of AviFile Api lacks of compatibility (rather unlikely) -Security Management prevent it from working (eg. DEP) -Incompatible with other DECLS files (likely). To test this, save all decls in a backup folder, then delete everything but the ones used by this code. Also: there is the bank plpOptionsList, try to make it bigger for debugging purpose: plpOptionsList=CreateBank(80000) ; req. size guessed, but hey... Seems like I didn't know exactly what I'm doing there :) Finally, try not to compare it against 1, but agains <>0 instead: If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)<>0 |
Code Archives Forum