B4A Library Bitmaps to Video

Discussion in 'Additional libraries, classes and official updates' started by CaptKronos, Apr 29, 2018.

  1. CaptKronos

    CaptKronos Member Licensed User

    This is a library which creates a video from a series of bitmaps.

    The library uses the surface input capabilities of Android's mediacodec (https://developer.android.com/reference/android/media/MediaCodec) that were introduced in Android 4.3 (API 18), hence 4.3 is the earliest version of Android that supports this library. A lot of the code that I used came from snippets than can be found here: https://bigflake.com/mediacodec/.

    There is very little parameter sanity checking so be careful. For example, setting up a video encoding with a weird resolution can lock up your device, though, for me, the device has always restarted itself after a few seconds. Different devices behave differently. My S7 seems to be very forgiving and will create videos at any resolution provided the width and height are divisible by two. Another of my devices only likes the standard resolutions. Speaking of which: https://developer.android.com/guide/topics/media/media-formats. Stick to the standard resolutions and you shouldn't have any problem.

    Likewise with the other setup parameters. Going lower than 3FPS sometimes caused playback issues. I haven't played around with the bitrate and IFrame_Interval settings since I found the commonly quoted values of 2,000,000 bps and 1 IFrame per second worked well for my requirements. (Look at the previously referenced web pages for more info.) Finally for the codec (MIME_Type) parameter, I always use "video/avc" (H.264) though you can play around with the other codecs supported by your device. You can get the codec list by calling the encoderCodecs method.

    Multiple videos can be generated simultaneously but remember to send the correct state information to each encoder instance.

    BitmapToVideoEncoder

    Author: CaptKronos
    Version: 1.1
    • BitmapToVideoEncoder
      • Functions:
        • encoderCodecs As String
          Returns a comma separated string of the available encoder codecs together with their supported MIME types.
          It's the MIME type that is passed to the setup method.
          Example:<code>
          Dim codecs As String = aBitmapToVideoEncoder.encoderCodecs</code>
        • endEncoding (theMediacodecParams As com.cyfer.bitmapstovideo.BitmapToVideoEncoder.mediacodecParams)
          Ends the encoding session. Pass the object returned from the call to setup.
          Example:<code>
          aBitmapToVideoEncoder.endEncoding(state)</code>
        • setup (Filename As String, Width As Int, Height As Int, MIME_Type As String, Codec_Name As String, Bitrate As Int, Frame_Rate As Int, IFrame_Interval As Int) As com.cyfer.bitmapstovideo.BitmapToVideoEncoder.mediacodecParams
          Initialises a new encoding session. Returns an object that holds the encoder state. This object must be passed to the write and end methods.
          More than one session can be active simultaneously - make sure to send the correct state object!
          Example:<code>
          Dim aBitmapToVideoEncoder As BitmapToVideoEncoder
          Dim state As JavaObject=aBitmapToVideoEncoder.setup("/sdcard/Movies/test.mp4", 1920, 1080, "video/avc", "OMX.google.h264.encoder", 2000000, 15, 1)</code>
        • writeBitmap (theMediacodecParams As com.cyfer.bitmapstovideo.BitmapToVideoEncoder.mediacodecParams, bitmap As android.graphics.Bitmap) As Boolean
          Sends a bitmap to the encoder. Pass the object returned from the call to setup.
          Example:<code>
          Dim success As Boolean = aBitmapToVideoEncoder.writeBitmap(state, bitmap)</code>
        • writeImageFile (theMediacodecParams As com.cyfer.bitmapstovideo.BitmapToVideoEncoder.mediacodecParams, filename As String) As Boolean
          Sends an image file (e.g. a jpeg) to the encoder. Pass the object returned from the call to setup.
          Example:<code>
          Dim success As Boolean = aBitmapToVideoEncoder.writeImageFile(state, "/sdcard/Pictures/test.jpg")</code>

    The use of the library is straightforward:

    Code:
    Sub CreateVideo
        
    Dim state As JavaObject
        
    Dim aBitmapToVideoEncoder As BitmapToVideoEncoder
        state = aBitmapToVideoEncoder.setup(
    "/sdcard/Movies/test.mp4",  _
                                
    19201080"video/avc""OMX.google.h264.encoder"2000000151)
        
    Dim bmp As Bitmap=generateVideoFrame(0), ret As Boolean = True
        
    Dim n As Int = 1
        
    Do While bmp.IsInitialized And ret=True
            ret=aBitmapToVideoEncoder.writeBitmap(state, bmp)
            bmp=generateVideoFrame(n)
            n=n+
    1
        
    Loop
        aBitmapToVideoEncoder.endEncoding(state)
    End Sub

    'return Null when finished
    Sub generateVideoFrame(n As Int) As Bitmap
     
    End Sub
     

    Attached Files:

    Last edited: Aug 9, 2018
  2. SoportePatrol

    SoportePatrol Member Licensed User

    Hello, thank you very much for this great library, I try to use but it gives me the following error:

    "java.lang.OutOfMemoryError: Failed to allocate a 1228812 byte allocation with 672768 free bytes and 657KB until OOM"

    this is my code:

    Code:
    Sub Globals
        
    Dim imgByte() As Byte
        
    Private IntervalMs As Int = 150
        
    Private lastPreviewSaved As Long
    End Sub

    ' Frame Source is stored in imgByte
    Sub Camera1_Preview (PreviewPic() As Byte)
        
    If DateTime.Now > lastPreviewSaved + IntervalMs Then
            imgByte = camEx.PreviewImageToJpeg(PreviewPic, 
    70)
            lastPreviewSaved = 
    DateTime.Now
        
    End If
    End Sub

    Sub CreateVideo
        
    Dim state As JavaObject
        
    Dim aBitmapToVideoEncoder As BitmapToVideoEncoder
       
        state = aBitmapToVideoEncoder.setup(
    "/sdcard/Movies/testX.mp4"640480"video/avc"2000000151)
        
    Dim bmp As Bitmap=generateVideoFrame(0)
        
    Dim ret As Boolean = True
        
    Dim n As Int = 1
        
    Do While bmp.IsInitialized And ret=True
            ret=aBitmapToVideoEncoder.writeBitmap(state, bmp)
            bmp=generateVideoFrame(n)
            n=n+
    1
        
    Loop
        aBitmapToVideoEncoder.endEncoding(state)
    End Sub

    'the imgByte is converted to stream and then to bitmap
    Sub generateVideoFrame(n As Int) As Bitmap
        
    Dim In As InputStream
        
    In.InitializeFromBytesArray(imgByte, 0, imgByte.Length)
        
    Dim bmp As Bitmap
        bmp.Initialize2(
    In)
        
    Return bmp
    End Sub

    'start video recording
    Sub Camera1_Ready (Success As Boolean)
        
    If Success Then
            Starter.csu.CallSubPlus(Me, 
    "CreateVideo"5000)
        
    End If
    End Sub
     
  3. CaptKronos

    CaptKronos Member Licensed User

    At what point do you get that error? When calling writeBitmap?

    Perhaps try adding

    Code:
    SetApplicationAttribute(android:largeHeap,"true")
    to the manifest but that is a fairly random suggestion.
     
  4. SoportePatrol

    SoportePatrol Member Licensed User

    thanks, after editing the manifest and moving the "writeBitmap" function to Camera1_Preview, it worked perfectly!!!
     
  5. CaptKronos

    CaptKronos Member Licensed User

    Updated the library to v1.1.

    Added the parameter Codec_name to Setup. Previously Setup would use the first codec that matched the requested MIME_type. I have since discovered (from personal experience and from Googling) that codecs not provided by Google don't seem to work reliably. I hadn't noticed this before because all my devices had the Google codecs ordered before the non-Google ones and hence by default the Google ones were being used. I recently tested with a Samsung S3 running a CyanogenMod ROM which had its codecs ordered as follows (only showing the video ones):

    Code:
    OMX.SEC.MPEG4.Encoder{video/mp4v-es}
    OMX.SEC.H263.Encoder{video/3gpp}
    OMX.SEC.AVC.Encoder{video/avc}
    OMX.google.h263.encoder{video/3gpp}
    OMX.google.h264.encoder{video/avc}
    OMX.google.mpeg4.encoder{video/mp4v-es}
    OMX.google.vp8.encoder{video/x-vnd.on2.vp8}
    This meant that calling Setup with a MIME type of (for example) video/avc would have the effect of setting OMX.SEC.AVC.Encoder as the codec. With v1.0 of the library it is not possible to request the Google codec. With version 1.1 of Setup, the request to use the Google codec corresponding to video/avc would be:

    Code:
    Setup(outFn, fileRes.x, fileRes.y, "video/avc""OMX.google.h264.encoder", bitRate, FPS, IFrames)
    The codec names, along with the MIME types, can be obtained from calling encoderCodecs().
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice