Ooops
October 29, 2020, 01:17:03 AM

Author Topic: [bb] Save AVI with Sound by jfk EO-11110 [ 1+ years ago ]  (Read 1277 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bb] Save AVI with Sound by jfk EO-11110 [ 1+ years ago ]
« on: June 29, 2017, 12:28:42 AM »
Title : Save AVI with Sound
Author : jfk EO-11110
Posted : 1+ years ago

Description : 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. ;)


Code :
Code: BlitzBasic
  1. ; Save Avi with sound. Provided by Dieter Marfurt aka jfk 11110
  2.  
  3. ; userlibs:
  4.  
  5. ; avifil32.decls:
  6.  
  7. ;.lib "avifil32.dll"
  8. ;AVIFileInit%()
  9. ;AVIFileOpen%(ppfile*,szFile$,uMode%,lpHandler%)
  10. ;AVIFileRelease%(pfile%)
  11. ;AVIFileInfo%(pfile%,pfi*,lSize%)
  12. ;AVIFileGetStream%(pfile%,ppavi*,fccType%,lParam%)
  13. ;AVIFileExit%()
  14. ;AVIFileCreateStream%(pfile%, ppavi*, psi*)
  15. ;AVIStreamInfo%(pStream%,pfi*,lSize%)
  16. ;AVIStreamStart%(pavi%)
  17. ;AVIStreamRelease%(pavi%)
  18. ;AVIStreamLength%(pavi%)
  19. ;AVIStreamGetFrameOpen%(pavi%,lpbiWanted%)
  20. ;AVIStreamGetFrame%(pFrame%,index%)
  21. ;AVIStreamGetFrameClose%(pFrame%)
  22. ;AVIStreamReadFormat%(pavi%, lPos%, lpFormat%, lpcbFormat*)
  23. ;AVIStreamSetFormat%(pavi%, lPos%, lpFormat*, cbFormat%)
  24. ;AVIStreamRead%(pavi%, lStart%, lSamples%, lpBuffer%, cbBuffer%, plBytes*, plSamples*)
  25. ;AVIStreamWrite%(pavi%, lStart%, lSamples%, lpBuffer*, cbBuffer%, dwflags%, plSampWritten%, plBytesWritten%)
  26. ;AVISaveOptions%(hwnd%, uiFlags%, nStreams%, ppavi*, plpOptions*)
  27. ;AVISaveOptionsFree%(nstreams%, plpOptions*)
  28. ;AVIMakeCompressedStream%(ppsCompressed*, psSource%, lpOptions%, pclsidHandler%)
  29.  
  30. ; kernel32.decls:
  31.  
  32. ;.lib "kernel32.dll"
  33. ;RtlMoveMemory2%(Destination*,Source,Length) : "RtlMoveMemory"
  34.  
  35.  
  36.  
  37. Graphics 800,600,32,2
  38. SetBuffer BackBuffer()
  39.  
  40. Const streamtypeAUDIO = 1935963489
  41. Const streamtypeVIDEO = 1935960438
  42. Const ICMF_CHOOSE_KEYFRAME=1
  43. Const ICMF_CHOOSE_DATARATE=2
  44. Const ICMF_CHOOSE_ALLCOMPRESSORS=8
  45.  
  46. Const AVIERR_OK=0
  47. Const AVIERR_NOCOMPRESSOR=$80000000 Or $40000 Or ($4000 + 113)
  48. Const AVIERR_MEMORY=      $80000000 Or $40000 Or ($4000 + 103)
  49. Const AVIERR_UNSUPPORTED= $80000000 Or $40000 Or ($4000 + 101)
  50.  
  51. Const AVIIF_KEYFRAME=$10
  52. Const Lib = 0
  53.  
  54. Const OF_READ=$0
  55. Const OF_WRITE=$1
  56. Const OF_SHARE_DENY_WRITE=$20
  57. Const OF_CREATE=$1000
  58.  
  59. Global hwnd=SystemProperty$("AppHWND")
  60.  
  61.  
  62.  
  63. ; demo:
  64.  
  65. file$="test_save.avi"
  66. target_width=640
  67. target_height=480
  68. target_rate=25
  69.  
  70.  
  71.  
  72.  
  73. AVIFileInit(); this needs to be called before any other Avifil32.dll function call
  74.  
  75. ; open avi for writing...
  76. 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)
  77. If my_handle=0: CloseWriteAvi(my_handle): AVIFileExit(): End: EndIf
  78.  
  79.  
  80.  ; write 11 frames to the avi
  81.  For i=0 To 10
  82.   Cls
  83.   Color 0,255,0
  84.   Rect 0,0,640,480,0
  85.   For r=0 To 100
  86.    Color Rand(255),Rand(255),Rand(255)
  87.    Text (Rand(target_width) And $FFF0),Rand(target_height),i+"*+*"
  88.   Next
  89.   Flip
  90.   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
  91.  Next
  92.  
  93. CloseWriteAvi(my_handle)
  94. AVIFileExit()
  95.  
  96. Print "ok!"
  97. WaitKey()
  98. End
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107. Function OpenWriteAvi(file$,target_width,target_height,target_rate,soundfile$="")
  108.  Local i ; probalby you better make all variables explicit locals (?), I'm too lazy for now
  109.  
  110.  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.
  111.  PokeInt AviControlBank,36,target_width
  112.  PokeInt AviControlBank,40,target_height
  113.  PokeInt AviControlBank,44,target_rate
  114.  
  115.  PokeInt AviControlBank,128,Len(soundfile$)
  116.  For i=1 To Len(soundfile$)
  117.   PokeByte AviControlBank,132+i-1,Asc(Mid$(soundfile$,i,1))
  118.  Next
  119.  
  120.  ret=CreateBank($128) ; will hold the avifileopen handle
  121.  PokeInt AviControlBank, 8,ret
  122.  If AVIFileOpen(ret,file$,OF_WRITE Or OF_CREATE,0)=0
  123.   avi_handle=PeekInt(ret,0)
  124.   PokeInt AviControlBank, 0,avi_handle
  125.  
  126.   AVISTREAMINFO_bank=CreateBank($ffff)
  127.   PokeInt AviControlBank,12,AVISTREAMINFO_bank
  128.  
  129.   ; possible flags:
  130.   avisf_disabled=$1
  131.   avisf_video_palchanges=$10000
  132.   avisf_knownflags=$10001
  133.   loc_fccType=streamtypeVIDEO
  134.   loc_fccHandler=(Asc("c") Shl 24)Or(Asc("v") Shl 16)Or(Asc("s") Shl 8)Or(Asc("m"))
  135.  
  136.   For i=0 To 511 Step 4
  137.    PokeInt AVISTREAMINFO_bank,i,0
  138.   Next
  139.  
  140.   PokeInt AVISTREAMINFO_bank, 0,loc_fccType
  141.   PokeInt AVISTREAMINFO_bank, 4,loc_fccHandler
  142.   PokeInt AVISTREAMINFO_bank,20,1000/target_rate; eg 1000/25= 40...
  143.   PokeInt AVISTREAMINFO_bank,24,1000;loc_dwRate ;    1000/40= 25 fps    (typical M$ :) )
  144.   PokeInt AVISTREAMINFO_bank,40,40+(target_width*target_height*3) ;loc_dwSuggestedBufferSize ; 0
  145.  
  146.   If AVIFileCreateStream(avi_handle,ret,AVISTREAMINFO_bank)=0
  147.    stream_Handle=PeekInt(ret,0)
  148.    PokeInt AviControlBank, 4,stream_handle
  149.  
  150.    ; required by AviStreamSetFormat (seems to be the same as the header of DIBHEADER)
  151.    BITMAPINFOHEADER=CreateBank(40)
  152.    PokeInt AviControlBank,16,BITMAPINFOHEADER
  153.    PokeInt BITMAPINFOHEADER, 0,40 ; size of header
  154.    PokeInt BITMAPINFOHEADER, 4,target_width ; width
  155.    PokeInt BITMAPINFOHEADER, 8,target_height ; height
  156.    PokeShort BITMAPINFOHEADER,12,1 ; planes
  157.    PokeShort BITMAPINFOHEADER,14,24  ; bitCount
  158.    PokeInt BITMAPINFOHEADER,16,0 ; compression (0=no compression in DIB)
  159.    PokeInt BITMAPINFOHEADER,20,(target_width*target_height*3);0 ; size in bytes (may be 0 for non compressed)
  160.    PokeInt BITMAPINFOHEADER,24,3600 ; horiz pixel per meter
  161.    PokeInt BITMAPINFOHEADER,28,3600 ; vert pixel per meter
  162.    PokeInt BITMAPINFOHEADER,32,0;$FFFFFF ; Colors used (for palette)
  163.    PokeInt BITMAPINFOHEADER,36,0;$FFFFFF ; number of important colors (lol)
  164.  
  165.    ; this bank will be used to write our frame data to, so avifil32 can grab it from there
  166.    DIBHEADER=CreateBank(40+(target_width*target_height*3)+1000)
  167.    PokeInt AviControlBank,20,DIBHEADER
  168.    For i=0 To 36 ; we simply reuse BITMAPINFOHEADER
  169.     PokeInt DIBHEADER,i,PeekInt(BITMAPINFOHEADER,i)
  170.    Next
  171.  
  172.    ; A pointer to space for AVICOMPRESSOPTIONS: first Int of bank points to itself (offset 8)
  173.    plpo=8
  174.    plpOptionsList=CreateBank(8000) ; req. size guessed, but hey...
  175.    PokeInt AviControlBank,24,plpOptionsList
  176.    compression_handle=CreateBank(8000)
  177.    PokeInt AviControlBank,28,compression_handle
  178.    dumm_bank=CreateBank(8)
  179.    PokeInt AviControlBank,32,dumm_bank
  180.    RtlMoveMemory2(dumm_bank,plpOptionsList+4,4)
  181.    PokeInt plpOptionsList,0,PeekInt(dumm_bank,0)+plpo
  182.    PokeInt plpOptionsList,4,PeekInt(dumm_bank,0)+plpo+4000
  183.  
  184.    If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 ;=0
  185.     res=AVIMakeCompressedStream(compression_handle, stream_handle, PeekInt(plpOptionsList,0), 0)
  186.     If res=0
  187.      ;If res= AVIERR_OK Then Print "ok!!!"
  188.      ;If res= AVIERR_NOCOMPRESSOR Then Print "nocompressor"
  189.      ;If res= AVIERR_MEMORY       Then Print "memory"
  190.      ;If res= AVIERR_UNSUPPORTED  Then Print "unsupported"
  191.      If AVIStreamSetFormat(PeekInt(compression_handle,0), 0, BITMAPINFOHEADER,40)=0
  192.       Return AviControlBank ; ok ready to rumble
  193.      EndIf
  194.     EndIf
  195.    EndIf
  196.   EndIf
  197.  EndIf
  198.  Return 0 ; bah, failure
  199. End Function
  200.  
  201.  
  202.  
  203. Function CloseWriteAvi(AviControlBank)
  204.  Local i
  205.  If AviControlBank<>0
  206.    avi_handle=PeekInt(AviControlBank, 0)
  207.    stream_handle=PeekInt(AviControlBank, 4)
  208.    ret=PeekInt(AviControlBank, 8)
  209.    AVISTREAMINFO_bank=PeekInt(AviControlBank,12)
  210.    BITMAPINFOHEADER=PeekInt(AviControlBank,16)
  211.    DIBHEADER=PeekInt(AviControlBank,20)
  212.    plpOptionsList=PeekInt(AviControlBank,24)
  213.    compression_handle=PeekInt(AviControlBank,28)
  214.    dumm_bank=PeekInt(AviControlBank,32)
  215.    len_wav=PeekInt(AviControlBank,128)
  216.    wav_to_add$=""
  217.    For i=1 To len_wav
  218.     a=PeekByte(AviControlBank,132+i-1)
  219.     If a=0 Then Exit
  220.     wav_to_add$=wav_to_add$+Chr$(a)
  221.    Next
  222.    ; close all
  223.    If compression_handle<>0
  224.     AVIStreamRelease(PeekInt(compression_handle,0))
  225.    EndIf
  226.    If plpOptionsList<>0
  227.     AVISaveOptionsFree(1,plpOptionsList)
  228.    EndIf
  229.    If stream_Handle<>0
  230.     AVIStreamRelease(stream_Handle)
  231.    EndIf
  232.    ; multiplex Audio stream, if any
  233.    If (wav_to_add$<>"") And (FileType(wav_to_add$)=1)
  234.     AddWavWriteAvi(wav_to_add$,avi_handle)
  235.    EndIf
  236.    If avi_handle<>0
  237.     AVIFileRelease(avi_handle)
  238.    EndIf
  239.    ;free banks...
  240.    If ret<>0 Then FreeBank ret
  241.    If AVISTREAMINFO_bank<>0 Then FreeBank AVISTREAMINFO_bank
  242.    If nullBank<>0 Then FreeBank nullBank
  243.    If BITMAPINFOHEADER<>0 Then FreeBank BITMAPINFOHEADER
  244.    If DIBHEADER<>0 Then FreeBank DIBHEADER
  245.    If plpOptionsList<>0 Then FreeBank plpOptionsList
  246.    If compression_handle<>0 Then FreeBank compression_handle
  247.    If dumm_bank<>0 Then FreeBank dumm_bank
  248.    FreeBank AviControlBank
  249.    ; i really hope I released everything, otherwise there would be a memoryleak
  250.  EndIf
  251. End Function
  252.  
  253.  
  254. Function AddFrameWriteAvi(AviControlBank, index, buffer=0)
  255.  If AviControlBank<>0
  256.   width=PeekInt(AviControlBank,36)
  257.   height=PeekInt(AviControlBank,40)
  258.   If buffer=0 Then buffer = BackBuffer()
  259.   DIBHEADER=PeekInt(AviControlBank,20)
  260.   If DIBHEADER<>0
  261.    compression_handle=PeekInt(AviControlBank,28)
  262.    If compression_handle<>0
  263.     Buffer2Dib(width,height,DIBHEADER,buffer)
  264.     AVIStreamWrite(PeekInt(compression_handle,0), index, 1,  DIBHEADER ,40+(width * height *3) , AVIIF_KEYFRAME, 0,0)
  265.    EndIf
  266.   EndIf
  267.  EndIf
  268. End Function
  269.  
  270.  
  271.  
  272.  
  273. Function Buffer2Dib(w,h,bank,buffer=0)
  274.  Local x,y,count,rgb
  275.  If buffer=0 Then buffer=BackBuffer()
  276.  count=0
  277.  SetBuffer Buffer
  278.  LockBuffer Buffer
  279.  For y=0 To h-1
  280.   For x=0 To w-1
  281.    rgb=ReadPixelFast(x,(h-1)-y) And $FFFFFF
  282.    PokeByte bank,count+2,(rgb Shr 16) And $FF
  283.    PokeByte bank,count+1,(rgb Shr 8) And $FF
  284.    PokeByte bank,count+0, rgb And $FF
  285.    count=count+3
  286.   Next
  287.  Next
  288.  UnlockBuffer Buffer
  289. End Function
  290.  
  291.  
  292.  
  293.  
  294.  
  295. Function AddWavWriteAvi(file$,avi_handle)
  296.  Local b=0
  297.  wav_handle=CreateBank(8)
  298.  If AVIFileOpen(wav_handle,file$, OF_READ, 0)=0
  299. ;  Print "opened wav"
  300.   wavstream_handle=CreateBank(8)
  301.   If AVIFileGetStream(PeekInt(wav_handle,0), wavstream_handle, streamtypeAUDIO, 0) =0
  302. ;   Print "openened wav read stream"
  303.    avi_info_bank=CreateBank(256);140
  304.    If AVIStreamInfo(PeekInt(wavstream_handle,0), avi_info_bank,140) =0;140
  305. ;    Print "retrievend wav read stream info"
  306.     lfmtSize=CreateBank(2560)
  307.     lpFormat=CreateBank(256)
  308.     If AVIStreamReadFormat(PeekInt(wavstream_handle,0), 0, 0, lfmtSize) =0
  309. ;     Print "used to read format of read stream"
  310.      If PeekInt(lfmtSize,0)>0
  311.       fmtWav=CreateBank(256)
  312.       dummy=CreateBank(8)
  313.       RtlMoveMemory2(dummy,fmtWav+4,4)
  314.       If AVIStreamReadFormat(PeekInt(wavstream_handle,0), 0, PeekInt(dummy,0), lfmtSize)=0
  315. ;       Print "read format 2"
  316.        lStreamLength = AVIStreamLength(PeekInt(wavstream_handle,0))
  317. ;       Print "got wav lenght"
  318.        If lStreamLength <>0
  319.         nullBank=CreateBank(lStreamLength)
  320.         lpbData = CreateBank(lStreamLength+100000)
  321.         RtlMoveMemory2(dummy,lpbData+4,4)
  322.         If AVIStreamRead(PeekInt(wavstream_handle,0), 0, lStreamLength, PeekInt(dummy,0), lStreamLength, nullbank, nullbank)=0
  323. ;         Print "avistreamread wav data"
  324.          psAvi=CreateBank(256)
  325.          siWav=CreateBank(256)
  326.          If AVIFileCreateStream(avi_handle, psAvi, avi_info_bank)=0
  327. ;          Print "created avi streat for writing audio"
  328.           If AVIStreamSetFormat(PeekInt(psAvi,0), 0, fmtWav, PeekInt(lfmtSize,0))=0
  329. ;           Print "used to set format for audio write stream"
  330.            If AVIStreamWrite (PeekInt(psAvi,0), 0, lStreamLength, lpbData, lStreamLength, AVIIF_KEYFRAME, 0, 0)=0
  331. ;            Print "AviWriteStream: written wav data to stream"
  332.             b=1
  333.            EndIf
  334.           EndIf
  335.           AVIStreamRelease(PeekInt(psAvi,0))
  336.          EndIf
  337.         EndIf
  338.         FreeBank lpbData
  339.         lpbData=0
  340.        EndIf
  341.       EndIf
  342.      EndIf  
  343.     EndIf
  344.    EndIf
  345.    AVIStreamRelease(PeekInt(wavstream_handle,0))
  346.   EndIf
  347.   AVIFileRelease(PeekInt(wav_handle,0))
  348.  EndIf
  349.  If wav_handle          <>0 Then FreeBank wav_handle
  350.  If wavstream_handle    <>0 Then FreeBank wavstream_handle
  351.  If avi_info_bank       <>0 Then FreeBank avi_info_bank
  352.  If lfmtSize            <>0 Then FreeBank lfmtSize
  353.  If lpFormat            <>0 Then FreeBank lpFormat
  354.  If fmtWav              <>0 Then FreeBank fmtWav
  355.  If dummy               <>0 Then FreeBank dummy
  356.  If lpbData             <>0 Then FreeBank lpbData
  357.  If psAvi               <>0 Then FreeBank psAvi
  358.  If siWav               <>0 Then FreeBank siWav
  359.  If nullbank    <>0 Then FreeBank nullbank
  360.  Return b
  361. End Function


Comments :


John Blackledge(Posted 1+ years ago)

 Memoey Access Violation on RtlMoveMemory2


Hambone(Posted 1+ years ago)

 MAke sure you read the comments and put the decls in the right place:avifil32.decls and kernel32.decls are in the comments.Allan


John Blackledge(Posted 1+ years ago)

 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?


CS_TBL(Posted 1+ years ago)

 also important: can we expect a bmax port? :P


RGR(Posted 1+ years ago)

 @ JohnRTLMoveMemory is indeed a critical functionThere 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 ;-)


jfk EO-11110(Posted 1+ years 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.<div class="quote"> also important: can we expect a bmax port? :P </div>Maybe you should do that, all your contributions to the community are welcome. However, they sell those tongue cleaners ;).


Matty(Posted 1+ years ago)

 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)
Code: [Select]
If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 ;=0




Matty(Posted 1+ years ago)

 anyone?


Warner(Posted 1+ years ago)

 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:
Code: [Select]
;;;If AVISaveOptions(hwnd, 3, 1, ret, plpOptionsList)=1 ;=0
res=AVIMakeCompressedStream(compression_handle, stream_handle, 0, 0)



Matty(Posted 1+ years ago)

 Thanks Warner I'll give it a try, I'm on XP though.


Matty(Posted 1+ years ago)

 Sorry, still didn't work, no debugging errors either.  I'll give up on this one I think...


Gladclef - Ben B(Posted 1+ years ago)

 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


jfk EO-11110(Posted 1+ years ago)

 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 [/i]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal