有人有 MediaRecorder 使用 ParcelFileDescriptor 和 createPipe() 吗?

Posted

技术标签:

【中文标题】有人有 MediaRecorder 使用 ParcelFileDescriptor 和 createPipe() 吗?【英文标题】:Anyone Have MediaRecorder Working with ParcelFileDescriptor and createPipe()? 【发布时间】:2012-10-05 09:19:45 【问题描述】:

我正在尝试制作一个录制音频的示例,数据存储由应用程序处理,而不是 MediaRecorder。用例包括将录音存储在内部存储器上或加密录音。

原则上,这应该使用createPipe()ParcelFileDescriptor 上创建的管道,但我得到的输出格式错误。

首先,here is a sample project 使用MediaRecorder“自然”记录,MediaRecorder 直接写入外部存储上的输出文件。这个应用程序运行良好,输出可以通过录制它的 android 设备或我的 Linux 机器上的 VLC 播放。

Here is my createPipe() variation of this project。从一般的MediaRecorder配置来看(如setOutputFormat()),和第一个一样,所以代码大概是正确的。

但是,我通过以下方式提供输出:

  recorder.setOutputFile(getStreamFd());

其中getStreamFd()使用createPipe(),产生一个后台线程从管道读取,并返回写入端供MediaRecorder使用:

  private FileDescriptor getStreamFd() 
    ParcelFileDescriptor[] pipe=null;

    try 
      pipe=ParcelFileDescriptor.createPipe();

      new TransferThread(new AutoCloseInputStream(pipe[0]),
                       new FileOutputStream(getOutputFile())).start();
    
    catch (IOException e) 
      Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
    

    return(pipe[1].getFileDescriptor());
  

TransferThread 是经典的java.io 流到流复制例程,增强了刷新和同步输出文件的智能:

  static class TransferThread extends Thread 
    InputStream in;
    FileOutputStream out;

    TransferThread(InputStream in, FileOutputStream out) 
      this.in=in;
      this.out=out;
    

    @Override
    public void run() 
      byte[] buf=new byte[8192];
      int len;

      try 
        while ((len=in.read(buf)) > 0) 
          out.write(buf, 0, len);
        

        in.close();

        out.flush();
        out.getFD().sync();
        out.close();
      
      catch (IOException e) 
        Log.e(getClass().getSimpleName(),
              "Exception transferring file", e);
      
    
  

当我运行第二个应用程序时,我得到一个输出文件,通过十六进制编辑器的粗略检查,它看起来基本没问题。 IOW,它不像是一个零字节的文件,或者充满了无法识别的乱码。它充满了与第一个应用程序的输出类似的乱码。但是,Android 和 VLC 都无法播放。

如果我不得不猜测,我会假设我在从管道读取时搞砸了,但我不确定具体哪里出错了。

有什么建议吗?

提前致谢!

【问题讨论】:

FWIW,我有一个关于使用 createPipe()MediaPlayer 的相关问题:***.com/questions/12920429/… 这个问题你解决了吗? @Teocci:没有。Android O 的ProxyFileDescriptorCallback 可能在这里提供帮助,但仅限于 Android O 及更高版本。基本上,管道不会产生可搜索的流。 天啊,我有这个问题,因为我使用MediaRecorder 使用 RTP 协议流式传输视频。我尝试过使用 MediaCodec,但在 Android 中是否这么难。 【参考方案1】:

我猜这与我对您其他问题的回答有关。 Anyone Have MediaPlayer Working with ParcelFileDescriptor and createPipe()?

可能当 MediaRecorder 将寻求写入 Header 信息时,管道已关闭。

如果你使用:

recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

记录工作正常,因为它没有标题信息,只有原始音频。

【讨论】:

啊哈!这确实有效,您的解释是有道理的。非常感谢! 我正在尝试使用它为视频录制应用程序创建一个输入流,但我不确定您的输入流来自哪里,您究竟为输入流传递了什么?任何帮助都会大有帮助 它现在不工作。 RAW_AMR 已弃用。 @CommonsWare 你有其他解决方案吗? @mr.icetea:我已经有几年没关注过这个问题了,所以我不知道哪些媒体代码不需要标头。无法寻找管道的根本问题仍然没有改变 AFAIK,所以如果没有无头编解码器,我不知道你能做什么。

以上是关于有人有 MediaRecorder 使用 ParcelFileDescriptor 和 createPipe() 吗?的主要内容,如果未能解决你的问题,请参考以下文章

MediaProjection与MediaRecorder实现录屏

使用 MediaRecorder 录制时的音频质量问题

使用android的mediaRecorder的文件大小限制?

Android 使用 MediaRecorder 捕获音频。

并行使用 MediaRecorder.AudioSource.CAMCORDER

在 Android 中使用 AudioRecorder/MediaRecorder 录制 FLAC 音频