Android Tutorial Slow Motion video recording using CamEX2

Discussion in 'Tutorials & Examples' started by Brandsum, Aug 8, 2019.

  1. Brandsum

    Brandsum Well-Known Member Licensed User

    Here is the example of SlowMo video capture using Camera2 API and CamEX2 class. This is the code for recording slow-motion video which you can find at the bottom of CamEX2 Class of attached example,
    #Region HighSpeed/SlowMo

    Public Sub getHighSpeedVideoSizesAndFPS As List
    Dim scMap As JavaObject = GetFromCameraCharacteristic("SCALER_STREAM_CONFIGURATION_MAP")
    Dim sizelist() As Object = scMap.RunMethod("getHighSpeedVideoSizes",Null)
    Dim FPSRanges() As Object
    Dim vList As List
    For Each size As JavaObject In sizelist
            FPSRanges = scMap.RunMethodJO(
    Dim fpsVal As Int
    Dim fpsR As Object
    For Each fps As JavaObject In FPSRanges
                fpsVal = fps.RunMethod(
                fpsR = fps
    "sizeObject":size, "FPSRange":fpsR, "FPS":fpsVal, "quality":size.RunMethod("getHeight",Null)&"p"))
    Return vList
    End Sub

    'Prepares the surface for high speed video capture.
    'Need to add this line to the manifest editor:
    Public Sub PrepareSurfaceForHighSpeedVideo (MyTaskIndex As Int, Dir As String, FileName As String, FPS As Int, Size As Object) As ResumableSub
    If getHighSpeedVideoSizesAndFPS.Size > 0 Then

            HighSpeedVideo = 
    If MyTaskIndex <> TaskIndex Then Return False
    Wait For (CreateSurface) Complete (Result As Boolean)
    If MyTaskIndex <> TaskIndex Then Return False
    File.Delete(Dir, FileName)
            MediaRecorder = 
    Camera.CreateMediaRecorder(PreviewSize, Dir, FileName)
    Dim dFps As Double = FPS
    Dim ii As Int = (FPS/30)*1000000
    Dim jo As JavaObject = Me
    "StartHighSpeedSession",Array(Camera,tv, Size))
    Wait For Camera_SessionConfigured (Success As Boolean)
    If MyTaskIndex <> TaskIndex Then Return False
            HighSpeedVideo = 
    Return Success
    Return False
    End If
    End Sub

    #End Region

    #if Java
    import android.view.TextureView;
    import android.view.Surface;
    import android.util.Size;
    import android.util.Log;
    import android.util.Range;
    import java.util.ArrayList;
    import java.util.List;
    import android.hardware.camera2.CameraAccessException;
    import android.hardware.camera2.CameraCaptureSession;
    import android.hardware.camera2.CaptureRequest;
    import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
    import android.os.Handler;

    public void StartHighSpeedSession(final anywheresoftware.b4a.objects.Camera2 _cam,final TextureView Surface, final Size PreviewSize) throws CameraAccessException, IllegalStateException, IOException {
        final ArrayList<Surface> targets = new ArrayList<Surface>();
        if (Surface != null) {
            _cam.previewSurface = new Surface(Surface.getSurfaceTexture());
            Surface.getSurfaceTexture().setDefaultBufferSize(PreviewSize.getWidth(), PreviewSize.getHeight());
        _cam.persistentSurface = MediaCodec.createPersistentInputSurface();
        _cam.cameraDevice.createConstrainedHighSpeedCaptureSession((java.util.List)targets, (CameraCaptureSession.StateCallback)new CameraCaptureSession.StateCallback() {
            public void onConfigureFailed(final CameraCaptureSession session) {
                ba.raiseEventFromUI(null, "camera_sessionconfigured", new Object[] { false });
            public void onConfigured(final CameraCaptureSession session) {
                _cam.captureSession = session;
                ba.raiseEventFromUI(null, "camera_sessionconfigured", new Object[] { true });
            public void onClosed(final CameraCaptureSession session) {
                if (_cam.captureSession != null && _cam.captureSession.equals(session)) {
                    _cam.captureSession = null;
        }, (Handler)null);

    public Object SetRepeatingBurst(final anywheresoftware.b4a.objects.Camera2 _cam,final Object Builder, final Range<Integer> fpsRange) throws CameraAccessException {

        final CaptureRequest.Builder builder = ((CaptureRequest.Builder)Builder);
        final CaptureRequest req =;
        CameraConstrainedHighSpeedCaptureSession mPreviewSessionHighSpeed = (CameraConstrainedHighSpeedCaptureSession) _cam.captureSession;
        List<CaptureRequest> mPreviewBuilderBurst = mPreviewSessionHighSpeed.createHighSpeedRequestList(req);
        mPreviewSessionHighSpeed.setRepeatingBurst(mPreviewBuilderBurst, null, (Handler)null);
        return req;

    #End If
    1. Check if the device supports High FPS video recording using getHighSpeedVideoSizesAndFPS.
      1. This will return a list of High FPS profile.
      2. Each Profile will contain a capture size, fps range, max fps of that profile and a quality string (eg. 720p) for information
      3. If the list size is ZERO then the device does not support High FPS recording
    2. Initialize Camera Preview (check example attached line 84, 85)
    3. At last call, PrepareSurfaceForHighSpeedVideo to prepare the hardware to High FPS mode. (check example attached line 87)
    4. Now you can call StartVideoRecording and StopVideoRecording to record a slow-motion video.
    I have modified some codes of the CamEX2 class to make those compatible with these new functions. This attached example is a modified version of the original Camex2 example. If you need that example project click here.

    Note: This is not a complete camera example but just a tutorial of the above functions. So the preview panel may look stretched but the recorded video file will not.

    Attached Files:

    Last edited: Aug 9, 2019
  2. ElliotHC

    ElliotHC Active Member Licensed User

    Hi, I've tried to run this but unsuccessfully.

  3. Brandsum

    Brandsum Well-Known Member Licensed User

    Run in debug mode and check the line number. Also try to run the Camex2 original example and check if that works
  4. Cableguy

    Cableguy Expert Licensed User

    Hummmm.... I'm pretty sure that "Slow Motion video RECORDING" is impossible... Not to say against nature laws!
    You can, however, do "Slow Motion Video PLAYBACK"
    Last edited: Aug 9, 2019
    jimmyF likes this.
  5. ElliotHC

    ElliotHC Active Member Licensed User

    I need a 250ms loop at 960fps recording at 720p, a further 250ms taken after the trigger and added to the clip.. Then played back at 30fps.

    Maybe I'll just use the default app, rename and upload the files when they appear.
  6. Brandsum

    Brandsum Well-Known Member Licensed User

    That is partially true. Actually, the hardware is recording at a higher frame rate but it is being written to disk at a lower frame rate. So if you capture for 5 seconds at 480 fps, then your video file duration will be greater than 1minute 20sec.
    Last edited: Aug 9, 2019
    ElliotHC likes this.
  7. Brandsum

    Brandsum Well-Known Member Licensed User

    If your device supports then you will get this profile from getHighSpeedVideoSizesAndFPS and then set previewsize and start video capture. You will get your slow-motion video.
  8. ElliotHC

    ElliotHC Active Member Licensed User

    I was running in debug mode, it didn't give me a line number :(
  9. Brandsum

    Brandsum Well-Known Member Licensed User

    Log window will show an arrow (->) sign before the error text. Click on that to goto line number.
  10. emexes

    emexes Well-Known Member Licensed User

    Maybe the B4A debug line numbers are not generated within inline Java.

    Presumably could work around by manually coding your own trace mechanism, eg strategically-placed calls to a B4A Sub that writes to the log.
  11. ElliotHC

    ElliotHC Active Member Licensed User

    As I've pretty much run out of time on this, I'm going to use the un-built app and run an app in the background to upload the file. I'll come back to this next week to see if I can get it working.
  12. Brandsum

    Brandsum Well-Known Member Licensed User

    That error was occurring from starter service. Maybe you need to give storage write access to your app.
    emexes likes this.
  13. ElliotHC

    ElliotHC Active Member Licensed User

    I'm stuck between two options..

    1. Try and get the SD card reading working so that I can move the video file out when it sees a new video produced by the internal camera app.
    2. Try and get this app working, filming at 960fps constantly for 500ms looping, then on trigger take a further 500ms and save in a location I can easily read and write to.

    In your opinion, which of these two options is going to be the easiest to implement?
  14. Brandsum

    Brandsum Well-Known Member Licensed User

    Both options are almost similar. Assuming that you can read and write to external storage and can monitor for a new file,
    1. You need to find a way to trigger the internal camera app.
    2. You need to modify this example to record further 500ms after trigger.
  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