Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stream camcorder stream over network, producing valid video file, using Android?

I'm trying to write camcorder recordings to a network stream, see the following snippet:

ParcelFileDescriptor fd = ParcelFileDescriptor.fromSocket(socket);
this.camera.lock(); // this.camera refers to an android.hardware.Camera instance.
this.camera.unlock();
this.mediaRecorder = new MediaRecorder();
this.mediaRecorder.setCamera(this.camera);
this.mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
this.mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
this.mediaRecorder.setProfile(CamcorderProfile.get(0, CamcorderProfile.QUALITY_HIGH));
this.mediaRecorder.setOutputFile(fd.getFileDescriptor());
this.mediaRecorder.prepare();
this.mediaRecorder.start();

Then I'm trying to capture it at the other side of the connection: with Socket.getInputStream() I am reading the bytes, and yes, bytes come in. Byte are actually written over the network.

But when try to save it to a file using the FileOutputStream class, and open the file with VLC, it just can't be read.

How can I eventually make the file 'playable', that means, that it is a valid video file?

Edit:

When I use this.mediaRecorder.setOutputFile("/sdcard/out.mp4");, I can open the video file from within Android, and it will play successfully. However, when I use this.mediaRecorder.setOutputFile(fd.getFileDescriptor());, it won't.

like image 361
MC Emperor Avatar asked May 03 '14 00:05

MC Emperor


1 Answers

The problem might be due to the fact that you're not setting everything in your camcorder profile.

Instead of this:

this.mediaRecorder.setProfile(CamcorderProfile.get(0, CamcorderProfile.QUALITY_HIGH));

try for example this:

CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
profile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
profile.videoCodec = MediaRecorder.VideoEncoder.MPEG_4_SP;
this.mediaRecorder.setProfile(profile);

BTW, are you trying to transmit this video after you finish recording it, or real-time while getting data from your camcorder?

EDIT:

If I remember correctly mpeg4 file format does not have a footer so there should be no need to "wait for the whole file"... BUT: this type of file has a structure which you cannot break if you want to read it. Therefore there might be a problem if you're sending raw bytes of video that has been prepared in mpeg4 file format, and you want to open a file after you've received a random number of those bytes. You can be almost sure that you will not get lucky enough to receive just the right number of bytes of your video.

What I'd advise you to do is:

  1. Check it. For example: send some video to the other side and use some sort of software that allows you to check the file structure. Maybe one of them will tell you whether your file has the correct structure. I can try to link some tools but I haven't tried any of them myself so it's possible you might need to look for something else (if none of them works well enough). You can try for example this or that.

  2. If step 1. confirmes that your file is being cut in a wrong place then you can try to control it somehow. For example, by informing the receiver of the places of the file, that when used for cutting it, will not result in breaking the structure (will let you open the file).

  3. The alternative would be to try to send some sort of "raw" video frames. And by "raw" I mean some sort of low-level data from camera that you could send and apply the specific codec on the receiving side. I haven't ever tried to do that so you might need to check whether it's even possible (to get this type of data).

like image 114
Bartek Lipinski Avatar answered Nov 10 '22 23:11

Bartek Lipinski