Android Question How To Record From VIdeoVIew http source?

ronovar

Active Member
Licensed User
Longtime User
I read online tutorials using MediaRecorder and they are using Camera on Device to record audio and video stream from VideoView.

My device is android box and does not contain hardware camera...so is there a way how can i record video from VIdeoVIew but without camera?

Any good tutorial site or android developer api or idea is welcome.

Thanks.
 

DonManfred

Expert
Licensed User
Longtime User
using Camera on Device to record audio and video stream from VideoView
No. It is NOT recording from Videoview. It is recording the camerastream.

so is there a way how can i record video from VIdeoVIew but without camera?
Not that i know of.
 
Upvote 0

ronovar

Active Member
Licensed User
Longtime User
Thanks DonManfred...do you have any idea how to do it? So that i can try?

I im thinking of idea to write videoview wrapper that puts it's surface to surface of MediaRecorder and then to record or in short..how can i create fake viewview camera interface so that i can use it with mediarecorder...this is just an i idea.

Thanks:)
 
Upvote 0

moster67

Expert
Licensed User
Longtime User
As far as I know, you cannot do that. I tried to find similar information about recording a video in the past and I found this:

You can't record from a SurfaceView. When you play video to a SurfaceView, the frames are being sent to a Surface, which is a queue of buffers with a producer-consumer interface. The app only has access to the producer end -- the system graphics compositor (SurfaceFlinger) is the consumer.

It might be possible using OpenGL ES and directing the output of your video player to a SurfaceTexture rather than a SurfaceView. I did not study this further and I believe it is rather complex to get that working.

Another possibility would be using a TextureView but I doubt it would work.

The thing to remember is that SurfaceView and TextureView are where the output goes. Ideally you should get the video stream as it is arriving.

If you are only interested in obtaining/saving frames of the video playing, you can use Vitamio5 or my other project B4ATextureVideoView, both available here in the forum.

Alternatively you can save the video if the server permits downloading but you will not be able to watch at the same time. Here is example code in Java which you could perhaps manage to translate into B4A.

That said, the only viable and probably less complicated solution is to use FFMpeg. I believe that in Kodi you can record a video, running on Android-boxes. I am pretty sure they are using FFMpeg, Python and various scripts to do that. One day I might try....
 
Upvote 0

ronovar

Active Member
Licensed User
Longtime User
Thanks...i will try B4ATextureVideoView and i im now trying in android studio the following idea: i have successfully put VideoView to SurfaceView but now i im testing if it will accept MediaRecorder for VideoInput (because VIdeoVIew is now on surfaceview).

It is shame for android developers that works on android images and API that does not include in native VideoView API for recording...for example when you call VideoVIew.Play(), to call the if you want record VideoView.Record().

Thanks for informations and if i found some informations that works i will post here.
 
Upvote 0

ronovar

Active Member
Licensed User
Longtime User
I have an idea...why we don't just open http stream file (from http url) and save it as file on usb flash drive? Stream that is coming from url does not have file size so httputils2 service for downloading huge files will not work.

Could some one give idea or example how to opet file from url that is downloading inginitely (because it is stream file with extension ts) and save that on usb drive or card external default dir as stream.ts.

This way i think will recording work.
 
Upvote 0

ronovar

Active Member
Licensed User
Longtime User
I have try to open file and save it using httputils when job is done (job is done when user press stop recording) and this piece of code works

B4X:
'GET - Date & Time
                DateTime.DateFormat="yyyy.MM.dd-hh:mm:ss"

                'SAVE - stream to usb device
                Dim Out As OutputStream
                Out = File.OpenOutput("/storage/external_storage/sda1", "Proba-"&DateTime.Date(DateTime.now)&"-EPG.mp4", True)
                File.Copy2(Job.GetInputStream, Out)
                Out.Close

Now i have question how can i add File->OpenOutput to open HTTP URL with stream then save it to "/storage/external_storage/sda1" as known file name...so that i then use videoview to play saved file while in background video is saving to flash drive.

Now i have problem that i can't use file save and watch stream using videoview because server only allows 1 connection per channel....so if i open 1 connection to VideoView and 1 connection to file save (recording) i have 2 connections and recording is working only few seconds...if i disable videoview and only run code that save file to flash drive then recording works excellent.

So my idea is how can i do that with file save on B4A:

- save file from HTTP to USB flash drive with known file name ("/storage/external_storage/sda1", "Proba-"&DateTime.Date(DateTime.now)&"-EPG.mp4")
- read saved file with VideoView so that user can watch stream while in background file is saved every second to flash drive.

Idea is simple but i don't know how to use FIle.Copy2 to use direct http url with stream.

Thanks
 
Upvote 0

moster67

Expert
Licensed User
Longtime User
I tried the same procedure yesterday but on Windows and with FFMpeg. I start saving the stream and then while the file is downloading, I opened it with VLC for Windows and this worked nice.

I guess you could do the same in Android, something like this:

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private NativeMe As JavaObject
    Dim timer1 As Timer
  
  
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim vv1 As VideoView
  
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
  
    If FirstTime Then
         NativeMe.InitializeContext
    End If
      
    vv1.Initialize("vv1")
    Activity.AddView(vv1,0,0,100%x,50%y)
  
    Dim streamURL As String = "http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi"
  
    If File.Exists(File.DirRootExternal & "/b4arecordings", "rec.avi") Then
        File.Delete(File.DirRootExternal & "/b4arecordings", "rec.avi")
    End If
  
'*NOTE: this java code is not good - you need to use Async-method
    NativeMe.RunMethod("DownloadStream",Array(streamURL,"b4arecordings","rec.avi"))
    timer1.Initialize("Timer1",4000)
    timer1.Enabled = True

End Sub


Sub timer1_Tick


        If vv1.IsPlaying = False Then
            If File.Exists(File.DirRootExternal & "/b4arecordings", "rec.avi") Then
                vv1.LoadVideo(File.DirRootExternal & "/b4arecordings", "rec.avi")
                vv1.Play
            End If
        End If
    timer1.Enabled = False
End Sub


Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub



#If JAVA

//NOTE: this java code is not good - you need to use Async-method

import android.os.Environment;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public void DownloadStream(String strUrl, String folderName, String fileName) {
        final int TIMEOUT_CONNECTION = 5000; //5sec
        final int TIMEOUT_SOCKET = 30000; //30sec
        final int BUFFER_SIZE = 1024 * 5; // 5MB

        BufferedInputStream in = null;
        FileOutputStream out = null;
        try {
            File dir = new File(Environment.getExternalStorageDirectory() + "/"
                    + folderName);
            if (dir.exists() == false) {
                dir.mkdirs();
            }

            URL url = new URL(strUrl);
            File file = new File(dir, fileName);

            //Open a connection to that URL.
            URLConnection ucon = url.openConnection();
            ucon.setReadTimeout(TIMEOUT_CONNECTION);
            ucon.setConnectTimeout(TIMEOUT_SOCKET);

            // Define InputStreams to read from the URLConnection.
            // uses 5KB download buffer
            InputStream is = ucon.getInputStream();
            in = new BufferedInputStream(is, BUFFER_SIZE);
            out = new FileOutputStream(file);
            byte[] buff = new byte[BUFFER_SIZE];

            int len = 0;
            while ((len = in.read(buff)) != -1) {
                out.write(buff, 0, len);
            }
        } catch (IOException ioe) {
            // Handle the error
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    // Nothing you can do
                }
            }
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (Exception e) {
                    // Nothing you can do
                }
            }
        }

        BA.Log("Finished download task");
    }


#End If

However, you will need to change the code for downloading so you are not keeping the main thread busy. You need to use an Async-mode. Better would be to write the code in B4A.

Remaining question is if Android/VideoView will permit you to open the file while it is still downloading and this I don't know. I never tried it. On Windows it works.
 
Last edited:
Upvote 0

ronovar

Active Member
Licensed User
Longtime User
Thanks...this is great code and idea is the same...i will not try to figure out how can i read tmp file in httputils2 i see when recording is started that file is saved to tmp folder on my usb stick and file name is 1 without extension so now i will try to read that tmp file in videoview while is stil open and see what i will get...if this is not working i will slide modify code to use call sub delayed to get rid of timer because in my app i im using 3 timers and won't use much of them because i need to save cpu resources.

Thanks for above code and i will post results as soon as i get progress.
 
Upvote 0

moster67

Expert
Licensed User
Longtime User
You could call this java download snippet in above project. It will probably work fine without blocking the UI-thread. The file should be saved/appended every 5MB (working in chunks)

B4X:
public void DownloadStreamAsync(final String strUrl, final String folderName, final String fileName) {
        new Thread(new Runnable() {
            @Override
            public void run() {
     
                final int TIMEOUT_CONNECTION = 5000; //5sec
                final int TIMEOUT_SOCKET = 30000; //30sec
                final int BUFFER_SIZE = 1024 * 5; // 5MB
     
                BufferedInputStream in = null;
                FileOutputStream out = null;
                try {
                    File dir = new File(Environment.getExternalStorageDirectory() + "/"
                            + folderName);
                    if (dir.exists() == false) {
                        dir.mkdirs();
                    }
     
                    URL url = new URL(strUrl);
                    File file = new File(dir, fileName);
     
                    //Open a connection to that URL.
                    URLConnection ucon = url.openConnection();
                    ucon.setReadTimeout(TIMEOUT_CONNECTION);
                    ucon.setConnectTimeout(TIMEOUT_SOCKET);
     
                    // Define InputStreams to read from the URLConnection.
                    // uses 5KB download buffer
                    InputStream is = ucon.getInputStream();
                    in = new BufferedInputStream(is, BUFFER_SIZE);
                    out = new FileOutputStream(file);
                    byte[] buff = new byte[BUFFER_SIZE];
     
                    int len = 0;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                } catch (IOException ioe) {
                    // Handle the error
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (Exception e) {
                            // Nothing you can do
                        }
                    }
                    if (out != null) {
                        try {
                            out.flush();
                            out.close();
                        } catch (Exception e) {
                            // Nothing you can do
                        }
                    }
                }
            }
        }).start();
    BA.Log("Finished download task");
    }
 
Upvote 0

ronovar

Active Member
Licensed User
Longtime User
I used httputils2 from this forum (https://www.b4x.com/android/forum/threads/download-huge-files-with-httputils2.30220/#content)

This works fine and i see that temporary file is saved every 1seconds on usb flash drive and is named by number (for example 1)

I added this to videoview to read temp file from usb flash drive but videoview is black....do i need to add code to open close open close open close to tmp file so that videoview can read it?

On windows this temporary file is working excellent (WMP and VLC tried and it works).

So this is the code to read temp file that is growing as httputils2 i sdownloading in background:

B4X:
                'RECORDING - Stuff
                Record = True
           
                'DEFINE - HttpJobs
                Dim Job2 As HttpJob

                'INITIALIZE - Job2
                Job2.Initialize("Job2", Me)

                'INITIALIZE - HttpUtils2Service
                HttpUtils2Service.ProgressSub = "DownloadProgress"
                HttpUtils2Service.TimerInterval = 200

                'GET - Stream
                Job2.Download("http://url/"&Channels(ScrolledChannel, 0)&"/"&Authorisation(0)&"/"&Authorisation(1))
           
                'STOP - Selected Channel
                VideoView1.Stop
       
                'URL - Selected Channel
                VideoView1.LoadVideo(HttpUtils2Service.TempFolder, (HttpUtils2Service.filename+1))
    Log(HttpUtils2Service.TempFolder)                       
                'PLAY - Selected Channel
                VideoView1.Play

When i stop recording the is job done called and temp file is renamed to my custom file name with extension mp4

And as i think file that read videoview using http stream is receiving file and is the same as saved tmp file...so i think we need to redefine videoview to read tmp file...


UPDATE: And good news is when i close receiving tmp file and then load to videoview it is playing...so i think we need to figure out how can we read tmp file to viewview when it is saving and file is growing when saving stream to usb flash drive
 
Last edited:
Upvote 0

moster67

Expert
Licensed User
Longtime User
Not all videoplayers on Windows can open a file while it is still being written (one exception is VLC). Maybe it is the same with VideoView? You could test with my VLC project and see if your code works there...
 
Upvote 0
Top