Author Topic: Working on a Audio+Video file format to use.  (Read 4006 times)

0 Members and 1 Guest are viewing this topic.

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Working on a Audio+Video file format to use.
« Reply #30 on: May 17, 2020, 11:46:47 am »
Nice work Dav! This could possibly be very useful for the game I'm working on for cutscenes and some graphics effects.
Is there is way to capture graphics animation of a program itself directly?
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Working on a Audio+Video file format to use.
« Reply #31 on: May 17, 2020, 04:00:16 pm »
Hi Ashish :)

What you think about?  :)  Try Dav's player to this file:

* ForDav.qbv (Filesize: 4.16 MB, Downloads: 197)
« Last Edit: May 17, 2020, 04:19:38 pm by Petr »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Working on a Audio+Video file format to use.
« Reply #32 on: May 17, 2020, 04:16:50 pm »
Here is the source code that will create it all. It makes both an audio track and individual images, which then form a video. To do this, I used Steve's SaveImage library v. 2.0. The only thing I needed as third-party software for was a WAV to OGG converter, so I'm attaching OGG, but you can compare the two audio files (the included OGG and the one that makes the program) that they are the same. :)

Warning: I highly recommend trying this program in a new empty folder

Next is the attached audio source file, from which a background track is then created and files needed to work the SaveImage library.

Code: QB64: [Select]
  1.  'example how record program screen to Dav's videoformat directly
  2. 'and greetings to Dav!
  3.  
  4. '$include:'saveimage.bi'
  5.  
  6. TYPE Snd
  7.     Left AS SINGLE
  8.     Right AS SINGLE
  9. REDIM SHARED OutputSound(-1) AS Snd
  10.  
  11. TYPE OtpSndHelper
  12.     Offset_Start AS LONG
  13.     Offset_End AS LONG
  14. REDIM SHARED OTP(1) AS OtpSndHelper
  15. DIM SHARED FrameCount AS LONG
  16.  
  17.  
  18. REM GOTO DOQBV
  19.  
  20.  
  21.  
  22. explo = WAVtoRAW("explosion.wav")
  23.  
  24.  
  25.  
  26.  
  27. SCREEN _NEWIMAGE(800, 600, 32)
  28. path$ = ENVIRON$("SYSTEMROOT") + "\Fonts\arialn.ttf"
  29. F = _LOADFONT(path$, 60, "monospace")
  30. s$ = "Nice work, Dav!"
  31. Sy = 300 - _FONTHEIGHT(F) / 2
  32. Sx = 400 - _PRINTWIDTH(s$) / 2
  33. Cx = _PRINTWIDTH(s$) / LEN(s$)
  34. REDIM VideoSoundTrack(0) AS Snd
  35. ScreenScanner = 1 / 15 '15 FPS
  36.  
  37.  
  38. Control = TIMER
  39. ON TIMER(ScreenScanner) GOSUB SaveScreen
  40. TimePos = 0
  41. FOR p = 1 TO LEN(s$)
  42.     COLOR _RGB32(RND * 255, RND * 255, RND * 127)
  43.     _PRINTSTRING (Sx + Cx * (p - 1), Sy), MID$(s$, p, 1)
  44.     IF MID$(s$, p, 1) <> CHR$(32) THEN
  45.         RAWCOPY explo, VideoSoundTrack(), TimePos
  46.         RAWPLAY explo
  47.         TimePos = TimePos + RAWLEN(explo) 'rawlen return sound lenght in seconds
  48.     END IF
  49.     DO UNTIL _SNDRAWLEN = 0: LOOP
  50.  
  51. PRINT "Total time:"; TIMER - Control; "15 FPS>>>>"; INT(15 * (TIMER - Control)); " frames"
  52. PRINT "Saving video sound track..."
  53.  
  54. SAVESOUND16S VideoSoundTrack(), "ForDav.wav" 'sound track for video is done (now just convert it to OGG)
  55.  
  56. PRINT "Converting BMPs to JPGs"
  57. FOR c = 0 TO FrameCount - 1
  58.     i = _LOADIMAGE(STR$(c) + ".bmp", 32)
  59.     Result = SaveImage(STR$(c) + ".jpg", i, 0, 0, _WIDTH(i), _HEIGHT(i))
  60.     LOCATE 4
  61.     PRINT "["; INT(c / (FrameCount - 1) * 100); "%]"
  62.     _FREEIMAGE i
  63.     KILL STR$(c) + ".bmp"
  64.  
  65.  
  66.  
  67. DOQBV:
  68. PRINT "Creating QBV"
  69.  
  70. 'here continue Dav's source:
  71.  
  72.  
  73.  
  74.  
  75. '===========
  76. 'QBVMAKE.BAS v0.10
  77. '===========
  78. 'Makes .QBV Audio/Video files for QB64.
  79. 'Uses .jpg image sequences and .ogg sound files.
  80. 'Coded by Dav, MAY/2020
  81.  
  82. 'QBVMAKE makes a .QBV audio/video file using a sequence
  83. 'of .jpg images and uses an .OGG sound file to add audio.
  84. 'This way you can make and use video files in you projects.
  85.  
  86. 'This demo builds a video called BIRD.QBV in the current
  87. 'directory.  It will then play the video.  This is only an
  88. 'example so you can see how to make your own .QBV video.
  89.  
  90. 'NOTE: YOU WILL HAVE TO ADAPT THIS CODE FOR YOUR FILES
  91.  
  92. '===========================================================
  93.  
  94. ' SET YOUR OWN QBV INFORMATION IN THIS AREA.....
  95. ' The following are my demo file settings.
  96. ' You will need to replace them with your own.
  97.  
  98. QBV$ = "ForDav.qbv" '<<<--- NAME OF YOUR QBV TO MAKE
  99.  
  100. 'Point to your image sequence location below and prefix
  101. 'My images are saved like, bird000.jpg.....
  102. source$ = _CWD$ '<<<---- YOUR IMAGE DIRECTORY
  103.  
  104. OGG$ = "ForDav.ogg" '<<<--- Name of you .OGG file
  105.  
  106. '------
  107.  
  108. 'NOW SET YOUR VIDEO INFO BELOW...
  109.  
  110. Audio = 1 '<<<--- SET TO 1 IF ADDING AUDIO, 0 IF NO AUDIO
  111. fps = 15 'My demo video has 15 frames per second
  112. frames = FrameCount - 1
  113. vidwidth = 801 'The width of my video image files
  114. vidheight = 601 'The height of my video image files
  115.  
  116. '==============================================================
  117.  
  118. 'Now here we start making the QBV file....
  119.  
  120. OPEN QBV$ FOR OUTPUT AS #1
  121.  
  122. 'If adding audio, copy it first...
  123. IF Audio = 1 THEN
  124.     OPEN OGG$ FOR BINARY AS #3
  125.     SL = LOF(3) ''Length of OGG sound file...
  126.     'save it to QBV file
  127.     A$ = INPUT$(SL, 3): PRINT #1, A$;: CLOSE #3
  128.     SL = 0 'No audio size at all
  129.  
  130. 'Now we same the jpg images to the .QBV file.
  131. 'We start at frame 0, because image sequences start at 0 usually.
  132. 'This is set to use 0000 series numbers (ie: bird0000.jpg)
  133. 'If yours are different, you will have to adjust the code.
  134.  
  135. 'Go through images...
  136. FOR t = 0 TO frames - 1
  137.  
  138.     'load a .jpg image file (a frame)
  139.     tag$ = LTRIM$(STR$(t))
  140.     IF LEN(tag$) = 3 THEN tag$ = "0" + tag$
  141.     IF LEN(tag$) = 2 THEN tag$ = "00" + tag$
  142.     IF LEN(tag$) = 1 THEN tag$ = "000" + tag$
  143.     '    f$ = source$ + tag$ + ".jpg"
  144.  
  145.     f$ = STR$(t) + ".jpg"
  146.  
  147.     OPEN f$ FOR BINARY AS 7
  148.     'Grab it, CLOSE it
  149.     frame$ = INPUT$(LOF(7), 7): CLOSE 7
  150.  
  151.     'Get size of frame
  152.     framelen$ = MKL$(LEN(frame$))
  153.  
  154.     'Save it's length to file
  155.     PRINT #1, framelen$;
  156.  
  157.     'Now save the frame data to file
  158.     PRINT #1, frame$;
  159.  
  160.     CLS
  161.     PRINT "============="
  162.     PRINT "QBVMAKE v0.10"
  163.     PRINT "============="
  164.     PRINT
  165.     PRINT "Making .QBV file: "; UCASE$(QBV$)
  166.     IF Auido$ = "0" THEN OGG$ = "(no audio)"
  167.     PRINT "Using audio file: "; OGG$
  168.     PRINT "Adding frame"; t + 1; "of"; frames; "..."
  169.  
  170.  
  171. 'Now we add a Footer to the end of the .QBV file.
  172. 'This will save all the .QBV settings information.
  173.  
  174. 'Set what version of .QBV file this is.
  175. PRINT #1, "QBV0.10";
  176.  
  177. 'Set if QBV has audio of not.
  178. IF Audio = 1 THEN
  179.     PRINT #1, "1";
  180.     PRINT #1, "0";
  181.  
  182. 'Save the width of video
  183. PRINT #1, MKI$(vidwidth);
  184.  
  185. 'Save the height of video
  186. PRINT #1, MKI$(vidheight);
  187.  
  188. 'Now, save the OGG file size to the end in MKL format
  189. PRINT #1, MKL$(SL);
  190.  
  191. 'Now save number of frames in MKI format
  192. PRINT #1, MKI$(frames);
  193.  
  194. 'Now save FPS to file in MKI format
  195. PRINT #1, MKI$(fps);
  196.  
  197.  
  198. PRINT "Done!"
  199. PRINT "Press any key to playback...."
  200. A$ = INPUT$(1)
  201.  
  202. '============================================================
  203.  
  204. 'Now lets play back the video we just made....
  205.  
  206. SCREEN _NEWIMAGE(800, 600, 32) 'Open a 32 bit screen first
  207.  
  208. 'Open the demo file bird.qbv below.....
  209. 'set x/y pos, Zoom x2, resize screen to fit vid, loop option
  210. PlayQBV "ForDav.qbv", 0, 0, 2, 1, 1
  211.  
  212.  
  213. '=============================================================
  214.  
  215.  
  216.  
  217. SaveScreen:
  218. SaveFullBMP (STR$(FrameCount) + ".bmp") 'JPG save is slow, therefore i use fastest saving method to BMP
  219. FrameCount = FrameCount + 1
  220.  
  221.  
  222. SUB PlayQBV (file$, x, y, zoom, fit, loopit) 'Dav's original SUB
  223.     'file$ = QBV file to play
  224.     'x = x position on screen
  225.     'y = y position on screen
  226.     'zoom factor of video, 1 is regular size,
  227.     '     2 is double size, etc...
  228.     'fit = fit video to match your current screen resolution
  229.     'loopit = Loop video or not. 1 is loop, 0 is play once.
  230.  
  231.     FF = FREEFILE
  232.  
  233.     OPEN file$ FOR BINARY AS FF
  234.  
  235.     'Get info saved at end of file
  236.     SEEK FF, LOF(FF) - 19
  237.  
  238.     Ver$ = INPUT$(7, FF) 'Version of QBV video format
  239.     Audio$ = INPUT$(1, FF) 'Audio setting
  240.     vidwidth = CVI(INPUT$(2, FF)) 'Width of video
  241.     vidheight = CVI(INPUT$(2, FF)) 'Height of video
  242.     VidData = CVL(INPUT$(4, FF)) 'Place in file Video data starts
  243.     frames = CVI(INPUT$(2, FF)) 'How many frames in file
  244.     fps = CVI(INPUT$(2, FF)) 'How many fps
  245.  
  246.     IF Audio$ = "1" THEN
  247.         b& = _SNDOPEN(file$) 'Open sound file
  248.     END IF
  249.  
  250.     'Set screen based on vid setting...
  251.     IF fit = 1 THEN
  252.         SCREEN _NEWIMAGE(vidwidth * zoom, vidheight * zoom, 32)
  253.     END IF
  254.  
  255.     DO
  256.         SEEK FF, VidData + 1
  257.  
  258.         IF Audio$ = "1" THEN _SNDPLAY b&
  259.  
  260.         FOR vid = 1 TO frames
  261.             framelen$ = INPUT$(4, FF)
  262.  
  263.             frame$ = INPUT$(CVL(framelen$), FF)
  264.  
  265.             'make a temp jpg on disk
  266.             FFF = FREEFILE
  267.             OPEN "_tmp_qbv_frame_.jpg" FOR OUTPUT AS FFF
  268.             PRINT #FFF, frame$;
  269.             CLOSE FFF
  270.  
  271.             'load it
  272.             frm& = _LOADIMAGE("_tmp_qbv_frame_.jpg")
  273.             'erase it
  274.             KILL "_tmp_qbv_frame_.jpg"
  275.  
  276.             _PUTIMAGE (x, y)-(x + (vidwidth * zoom), x + (vidheight * zoom)), frm&
  277.             _FREEIMAGE frm&
  278.  
  279.             _LIMIT fps
  280.  
  281.             'A little keyboad control if you want.
  282.             'If you don't want, comment this out....
  283.             SELECT CASE UCASE$(INKEY$)
  284.                 CASE IS = " "
  285.                     IF Audio$ = "1" THEN _SNDPAUSE b&
  286.                     pa$ = INPUT$(1)
  287.                     IF Audio$ = "1" THEN _SNDPLAY b&
  288.                 CASE IS = CHR$(27): EXIT DO 'ESC key exits
  289.             END SELECT
  290.  
  291.         NEXT
  292.  
  293.         IF loopit <> 1 THEN EXIT DO
  294.  
  295.     LOOP
  296.  
  297.     CLOSE FF
  298.  
  299.     IF Audio$ = "1" THEN _SNDSTOP b&
  300.  
  301.  
  302.  
  303.  
  304.  
  305. FUNCTION RAWLEN (handle)
  306.     RAWLEN = OTP(handle).Offset_End - OTP(handle).Offset_Start / 44100
  307.  
  308.  
  309. SUB SAVESOUND16S (arr() AS Snd, file AS STRING)
  310.  
  311.     TYPE head16
  312.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  313.         size AS LONG '              4 bytes  (file size)
  314.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  315.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  316.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  317.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  318.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  319.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  320.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  321.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  322.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  323.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  324.         lenght AS LONG '            4 bytes  Data block size
  325.     END TYPE '                     44 bytes  total
  326.     DIM H16 AS head16
  327.     ch = FREEFILE
  328.  
  329.     H16.chunk = "RIFF"
  330.     H16.size = 44 + UBOUND(arr) * 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  331.  
  332.     H16.fomat = "WAVE"
  333.     H16.sub1 = "fmt "
  334.     H16.subchunksize = 16
  335.     H16.format = 1
  336.     H16.channels = 2
  337.     H16.rate = 44100
  338.     H16.ByteRate = 44100 * 2 * 16 / 8
  339.     H16.Block = 4
  340.     H16.Bits = 16
  341.     H16.subchunk2 = "data"
  342.     H16.lenght = UBOUND(arr) * 4
  343.     IF _FILEEXISTS(file$) THEN KILL file$
  344.  
  345.     OPEN file$ FOR BINARY AS #ch
  346.     PUT #ch, , H16
  347.     DIM LeftChannel AS INTEGER, RightChannel AS INTEGER
  348.  
  349.     FOR audiodata = 0 TO UBOUND(arr)
  350.         LeftChannel = arr(audiodata).Left * 32768
  351.         RightChannel = arr(audiodata).Right * 32768
  352.  
  353.         PUT #ch, , LeftChannel
  354.         PUT #ch, , RightChannel
  355.     NEXT
  356.     CLOSE ch
  357.  
  358.  
  359. SUB RAWCOPY (handle, arr() AS Snd, position AS LONG)
  360.     SoundLenghtInBytes = OTP(handle).Offset_End - OTP(handle).Offset_Start
  361.     '    IF UBOUND(arr) < UBOUND(arr) + SoundLenghtInBytes + position THEN REDIM _PRESERVE arr(UBOUND(arr) + SoundLenghtInBytes + position) AS Snd
  362.     REDIM _PRESERVE arr(position + SoundLenghtInBytes) AS Snd
  363.     DIM rc AS LONG, OTPS AS LONG
  364.     OTPS = OTP(handle).Offset_Start
  365.     FOR rc = position TO position + SoundLenghtInBytes
  366.  
  367.         IF arr(rc).Left THEN OutLeft = (arr(rc).Left + OutputSound(OTPS).Left) ELSE OutLeft = OutputSound(OTPS).Left
  368.         IF arr(rc).Right THEN OutRight = (arr(rc).Right + OutputSound(OTPS).Right) ELSE OutRight = OutputSound(OTPS).Right
  369.  
  370.         IF OutLeft > .9 THEN OutLeft = .9
  371.         IF OutLeft < -.9 THEN OutLeft = -.9
  372.  
  373.         IF OutRight > .9 THEN OutRight = .9
  374.         IF OutRight < -.9 THEN OutRight = -.9
  375.  
  376.         arr(rc).Left = OutLeft
  377.         arr(rc).Right = OutRight
  378.  
  379.         '   arr(rc).Left = OutputSound(OTPS).Left
  380.         '   arr(rc).Right = OutputSound(OTPS).Right
  381.         OTPS = OTPS + 1
  382.     NEXT rc
  383.  
  384.  
  385. FUNCTION WAVtoRAW (file$) '                              Function load WAV file (this just 16bit, stereo format) and load it to array as RAW.
  386.     TYPE head
  387.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  388.         size AS LONG '              4 bytes  (?E??)
  389.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  390.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  391.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  392.         format AS STRING * 2 '      2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  393.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  394.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  395.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  396.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  397.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  398.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  399.     END TYPE '                     40 bytes  total
  400.     DIM H AS head
  401.     ch = FREEFILE
  402.  
  403.     IF _FILEEXISTS(file$) THEN OPEN file$ FOR BINARY AS #ch ELSE PRINT file$; " not found": SLEEP 2: SYSTEM
  404.     GET #ch, , H
  405.  
  406.     block = H.Block
  407.     RATE = H.rate
  408.     chan = H.channels
  409.     bits = H.Bits
  410.  
  411.     SEEK #ch, Find_data_area(file$)
  412.  
  413.     OTP_Size = UBOUND(otp)
  414.     OTP(OTP_Size).Offset_Start = UBOUND(outputsound) + 1
  415.  
  416.     DO WHILE NOT EOF(ch)
  417.         IF bits = 16 AND chan = 2 THEN
  418.             REDIM lefi AS INTEGER, righi AS INTEGER
  419.             GET #ch, , lefi
  420.             GET #ch, , righi
  421.             lef = lefi / 65536
  422.             righ = righi / 65536
  423.         END IF
  424.  
  425.         IF RATE > 44100 THEN frekvence = RATE ELSE frekvence = 44100
  426.  
  427.         oss = UBOUND(OutputSound)
  428.         REDIM _PRESERVE OutputSound(oss + (frekvence / RATE)) AS Snd
  429.  
  430.         FOR plll = 1 TO frekvence / RATE
  431.             OutputSound(oss + plll).Left = lef
  432.             OutputSound(oss + plll).Right = righ
  433.         NEXT plll
  434.  
  435.         DO WHILE _SNDRAWLEN > 0: LOOP: REM comment this
  436.     LOOP
  437.  
  438.     OTP(OTP_Size).Offset_End = UBOUND(outputsound)
  439.     REDIM _PRESERVE OTP(OTP_Size + 1) AS OtpSndHelper
  440.     CLOSE ch
  441.     WAVtoRAW = OTP_Size
  442.  
  443. SUB RAWPLAY (handle) '                                                      Play file content from RAW array (array OutputSounds)
  444.     FOR Playi = OTP(handle).Offset_Start TO OTP(handle).Offset_End
  445.         _SNDRAW OutputSound(Playi).Left, OutputSound(Playi).Right
  446.     NEXT
  447.  
  448. FUNCTION Find_data_area (handle$)
  449.     REDIM D AS STRING * 10024
  450.     ff = FREEFILE
  451.     OPEN handle$ FOR BINARY AS #ff
  452.     GET #ff, 1, D$
  453.     CLOSE #ff
  454.     Find_data_area = INSTR(1, D$, "data") + 8
  455.     D$ = ""
  456. '$include:'saveimage.bm'
  457.  
* ForVideo.zip (Filesize: 399.3 KB, Downloads: 189)
« Last Edit: May 17, 2020, 04:32:12 pm by Petr »

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Working on a Audio+Video file format to use.
« Reply #33 on: May 17, 2020, 08:28:51 pm »
Thanks, Petr!  That very nice!

- Dav

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Working on a Audio+Video file format to use.
« Reply #34 on: May 24, 2020, 10:04:40 pm »
Hey @SierraKen,  I was playing with your tweaked version with _DISPLAY added, I paused playback and minimized it, and discovered something very interesting I never noticed before with _DISPLAY.   If you minimize a QB64 program while automatic display is turned off (if under _DISPLAY)  then the program screen will be blank when you maximize it again, util the screen is updated again.  Here's a short example...

Code: QB64: [Select]
  1. PRINT "Minimize this and the screen will be blank when maximzing it again"
  2.  
  3.  

I have never accounted for this in any of my programs. Many of my games posted here, which use _DISPLAY a bunch,  go blank when I minimize them.  I need to adjust my code from here on to allow for this.

So in your version of QBVPLAY.BAS, I added an _AUTODISPLAY when hiting the pause key and the screen won't go blank when minimizing/maximizing while paused.


- Dav


Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Working on a Audio+Video file format to use.
« Reply #35 on: May 25, 2020, 09:56:55 am »

This problem can be solved:

Code: [Select]
PRINT "Minimize this and the screen will be blank when maximzing it again"
_DISPLAY
IF _SCREENICON = 0 THEN _AUTODISPLAY
SLEEP