20

I'm testing libstreaming on new Android Lollipop, and this code that worked on previous release, seems to launch exception.

    try {
        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setCamera(mCamera);

        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mMediaRecorder.setVideoEncoder(mVideoEncoder);
        mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
        mMediaRecorder.setVideoSize(mRequestedQuality.resX,mRequestedQuality.resY);


        mMediaRecorder.setVideoFrameRate(mRequestedQuality.framerate);

        // The bandwidth actually consumed is often above what was requested 

        mMediaRecorder.setVideoEncodingBitRate((int)(mRequestedQuality.bitrate*0.8));

        // We write the ouput of the camera in a local socket instead of a file !           
        // This one little trick makes streaming feasible quiet simply: data from the camera
        // can then be manipulated at the other end of the socket

        mMediaRecorder.setOutputFile(mSender.getFileDescriptor());

        mMediaRecorder.prepare();
        mMediaRecorder.start();

    } catch (Exception e) {
        throw new ConfNotSupportedException(e.getMessage());
    }

Launched exception is:

MediaRecorder: start failed -38

11-18 09:50:21.028: W/System.err(15783): net.majorkernelpanic.streaming.exceptions.ConfNotSupportedException
11-18 09:50:21.028: W/System.err(15783):    at net.majorkernelpanic.streaming.video.VideoStream.encodeWithMediaRecorder(VideoStream.java:442)
11-18 09:50:21.028: W/System.err(15783):    at net.majorkernelpanic.streaming.MediaStream.start(MediaStream.java:250)

I've tried to comment:

mMediaRecorder.setOutputFile(mSender.getFileDescriptor());

no exception launched, but when I start streaming a dialog tell me that need an outputfile.

Help appreciated.

Padma Kumar
  • 20,420
  • 16
  • 69
  • 127
andreasperelli
  • 962
  • 2
  • 9
  • 35
  • I think I'm getting a similar error. I'm trying to write to a local socket to stream audio/video as well but am getting after the -38 error E/StagefrightRecorder﹕ Output file descriptor is invalid. According to https://android.googlesource.com/platform/frameworks/av/+/master/media/libmediaplayerservice/StagefrightRecorder.cpp the error outputs on line 752. when the file descriptor is less than 0, meaning -1 the default sentinel value. Except that I verify that I set the descriptor as 136 before I set the output file. – sbaar Nov 21 '14 at 22:44
  • which Android version are you using ? – andreasperelli Nov 21 '14 at 23:02
  • This problem is only on Lollipop. The same code on the same nexus 5 and same nexus 7 device worked when they were on kitkat. I'm now pretty sure the problem has something to do with sockets, but I'm still trying to hunt down what could have changed. – sbaar Nov 21 '14 at 23:07
  • same for me... unfortunately, nothing found in the web until now... – andreasperelli Nov 21 '14 at 23:10
  • using ParcelFileDescriptor in Android 5.0 works well but I have a problem with video color while using MediaRecorder. Color is different from real color and previous Android version.I think color format is wrong. Do you meet it @andreasperelli? – Bao Doan Nov 26 '14 at 04:52
  • didn't meet it @BảoĐoàn... on which device ? – andreasperelli Nov 26 '14 at 08:32

2 Answers2

25

I filed a bug report on AOSP. https://code.google.com/p/android/issues/detail?id=80715

"The current SELinux policies don't allow for mediaserver to handle app generated abstract unix domain sockets.

Instead, I'd recommend you create a pipe-pair ( http://developer.android.com/reference/android/os/ParcelFileDescriptor.html#createPipe() ) which is allowed by the Android 5.0 policy. " I don't know why they did this or how we were supposed to know.

I'm using a very old/modified (can't tell) version of libstreaming where mediastream is still extended from mediarecorder, but looking at the current version, in MediaStream you'll probably want to change createSockets to something including the following:

        ParcelFileDescriptor[] parcelFileDescriptors =ParcelFileDescriptor.createPipe();
        parcelRead = new ParcelFileDescriptor(parcelFileDescriptors[0]);
        parcelWrite  = new ParcelFileDescriptor(parcelFileDescriptors[1]);

then in your video/audio stream

setOutputFile(parcelWrite.getFileDescriptor());

and in that same file change

    // The packetizer encapsulates the bit stream in an RTP stream and send it over the network
    mPacketizer.setInputStream(mReceiver.getInputStream());
    mPacketizer.start();

to

            InputStream is = null;
            try{ is = new ParcelFileDescriptor.AutoCloseInputStream(parcelRead);
            }
            catch (Exception e){}
            mPacketizer.setInputStream(is);

As andreasperelli pointed out in the comment, make sure to close the ParcelFileDescriptors in closeSockets(), or depending on your implementation and version, before closeSockets() and before you call MediaRecorder.stop().

sbaar
  • 1,412
  • 1
  • 16
  • 32
  • can you please paste me the MediaStream.java code to see how have you modified the createSockets() method ? – andreasperelli Nov 25 '14 at 08:37
  • I'm sorry I wasn't clear. You can leave createSockets() and closeSockets() alone and just completely the ignore the code in them. You won't be using the LocalSockets. Instead create the protected parcelRead and parcelWrite vars in mediastream, initialize them in createSockets as shown above, and use them in place where the local sockets were used, substituting the code above when setting the outputFile and packetizer input stream – sbaar Nov 25 '14 at 10:12
  • 1
    this seems to work on start streaming, on stop it I see MediaCodecInputStream - No buffer available... in logcat and onSessionStopped seems to be not called. By the way, great fix! – andreasperelli Nov 25 '14 at 11:14
  • 1
    solved adding: parcelRead.close(); and parcelWrite.close(); in closeSockets() method :-) – andreasperelli Nov 25 '14 at 13:54
  • 1
    on Nexus 4 with Android 5.0 is working well, on Nexus 5 with Android 5.0 the streaming is green and junky... – andreasperelli Nov 26 '14 at 08:31
  • 1
    solved adding: parameters.set( "cam_mode", 1 ); in VideoStream.java createCamera() method – andreasperelli Nov 26 '14 at 08:44
  • I'm looking to do something similar but using a socket for livestreaming. Could you adapt this solution to wrap around a ParcelFileDescriptor creating using ParcelFileDescriptor.fromSocket(socket)? – user1743524 Dec 22 '14 at 19:48
  • 6
    Can you please post complete code for the solution? – Flyview Apr 28 '15 at 23:18
  • @sbaar - Do you have a snippet to show how this is done? That would be very helpful. – Jeff Fischer Jul 29 '15 at 08:48
  • Good news. The libstreaming library has been updated to work with parcel file descriptors. – sbaar Jul 29 '15 at 18:22
  • Any updates on this? How do I connect the `ParcelFileDescriptor`s from pipe pair to my client `Socket`? – Roman Samoilenko Sep 11 '17 at 12:36
  • @RomanSamoylenko You'll want to use the pfd in conjunction with input streams. Take a look at how it's used in practice https://github.com/fyhertz/libstreaming/search?utf8=%E2%9C%93&q=parcelfiledescriptor&type= – sbaar Sep 11 '17 at 17:24
1

at Android 6.0 I resolve this problem with the code

new Thread(new Runnable() {
  @Override public void run() {
    FileInputStream inputStream = null;
    try {
      inputStream = new FileInputStream(path);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
    while (true) {
      byte[] buffer = new byte[0];
      try {
        buffer = new byte[inputStream.available()];
      } catch (IOException e) {
        e.printStackTrace();
      }
      try {
        inputStream.read(buffer);
      } catch (IOException e) {
        e.printStackTrace();
      }
      try {
        mSender.getOutputStream().write(buffer);
        mSender.getOutputStream().flush();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}).start();

I use a file as buffer and write bytes at another thread.the MediaRecorder output to the file.

xiaose
  • 34
  • 4