安卓棒棒糖上的MediaRecorder问题

21

我正在新的Android Lollipop上测试libstreaming,之前版本上运行正常的代码似乎出现了异常。

    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());
    }

抛出的异常是:

MediaRecorder:启动失败 -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)

我尝试进行评论:

mMediaRecorder.setOutputFile(mSender.getFileDescriptor());
没有异常被抛出,但当我开始流式传输时,会弹出一个对话框告诉我需要一个输出文件。
感激不尽您的帮助。

我觉得我遇到了类似的错误。 我也尝试使用本地套接字来流传音频/视频,但是在出现"-38"错误E/ StagefrightRecorder:输出文件描述符无效之后。根据https://android.googlesource.com/platform/frameworks/av/+/master/media/libmediaplayerservice/StagefrightRecorder.cpp,在文件描述符小于0时,即-1默认标记值时,错误会在第752行输出。 除非我在设置输出文件之前验证我将描述符设置为136。 - sbaar
你使用的是哪个安卓版本? - andreasperelli
这个问题只出现在Lollipop上。当Nexus 5和Nexus 7设备运行KitKat时,相同的代码可以正常工作。我现在非常确定问题与套接字有关,但我仍在努力寻找可能发生了什么变化。 - sbaar
跟我一样...不幸的是,到目前为止在网上没有找到任何东西... - andreasperelli
在Android 5.0中使用ParcelFileDescriptor效果很好,但是我在使用MediaRecorder时遇到了视频颜色问题。颜色与真实颜色和之前的Android版本不同。我认为颜色格式是错误的。@andreasperelli,你遇到过这个问题吗? - Bao Doan
没有达到它 @BảoĐoàn... 在哪个设备上? - andreasperelli
2个回答

26

我在AOSP上提交了一个错误报告。 https://code.google.com/p/android/issues/detail?id=80715

"当前的SELinux策略不允许mediaserver处理应用生成的抽象UNIX域套接字。

相反,我建议您创建一个管道对 (http://developer.android.com/reference/android/os/ParcelFileDescriptor.html#createPipe()) ,这符合Android 5.0策略。

我不知道他们为什么这样做或者我们该如何知道。

我正在使用一个非常老的/修改过的(无法确定)版本的libstreaming,在当前版本中看,您可能需要将createSockets更改为包含以下内容的内容:

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

然后在你的视频/音频流中

setOutputFile(parcelWrite.getFileDescriptor());

同时,在同一个文件中进行更改。

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

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

正如andreasperelli在评论中指出的那样,在调用closeSockets()之前或根据你的实现和版本,在调用MediaRecorder.stop()之前,确保关闭ParcelFileDescriptors。


1
这似乎在开始流式传输时有效,在停止它时我在logcat中看到MediaCodecInputStream - 没有可用的缓冲区...,而onSessionStopped似乎没有被调用。顺便说一句,修复得很好! - andreasperelli
1
在 closeSockets() 方法中添加 parcelRead.close(); 和 parcelWrite.close(); 已解决 :-) - andreasperelli
1
在搭载Android 5.0的Nexus 4上运行良好,在搭载Android 5.0的Nexus 5上流媒体会出现绿屏和卡顿的情况。 - andreasperelli
1
在VideoStream.java的createCamera()方法中添加参数.parameters.set("cam_mode", 1);问题已解决。 - andreasperelli
7
请问您能否发布完整的解决方案代码? - Flyview
显示剩余7条评论

2

在 Android 6.0 中,我通过以下代码解决了这个问题

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();

我使用文件作为缓冲区,并在另一个线程中写入字节。MediaRecorder将输出写入该文件。


您好,请更详细地说明如何使用这段代码。 - Karan Nagpal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接