有人让 MediaPlayer 使用 ParcelFileDescriptor 和 createPipe() 吗? [英] Anyone Have MediaPlayer Working with ParcelFileDescriptor and createPipe()?

查看:15
本文介绍了有人让 MediaPlayer 使用 ParcelFileDescriptor 和 createPipe() 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于 我最近关于 MediaRecordercreatePipe(),以及 这个其他问题,我现在试图让 MediaPlayer 处理由ContentProvider 通过 ParcelFileDescriptorcreatePipe().

Related to my recent question on MediaRecorder and createPipe(), and a discussion of the createPipe() technique in this other SO question, I am now trying to get MediaPlayer to work with content served by a ContentProvider via ParcelFileDescriptor and createPipe().

这个示例项目是我迄今为止的工作.它基于 一个较早的示例,该示例播放存储为原始资源.因此,我知道我的剪辑没问题.

This sample project has my work to date. It is based off of an earlier sample that plays an OGG clip stored as a raw resource. Hence, I know that my clip is fine.

我已将 MediaPlayer 设置更改为:

I have changed my MediaPlayer setup to:

  private void loadClip() {
    try {
      mp=new MediaPlayer();
      mp.setDataSource(this,
                       PipeProvider.CONTENT_URI.buildUpon()
                                               .appendPath("clip.ogg")
                                               .build());
      mp.setOnCompletionListener(this);
      mp.prepare();
    }
    catch (Exception e) {
      goBlooey(e);
    }
  }

通过登录 PipeProvider,我看到我的 Uri 被正确构建.

Through logging in PipeProvider, I see that my Uri is being properly constructed.

PipeProvider这个示例项目,用于为 Adob​​e Reader 提供 PDF 文件,这限制了我的代码可以搞砸的程度.:-)

PipeProvider is the same one as in this sample project, which works for serving PDFs to Adobe Reader, which limits how screwed up my code can be. :-)

具体来说,openFile()ParcelFileDescriptor 创建一个管道:

Specifically, openFile() creates a pipe from ParcelFileDescriptor:

  @Override
  public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    ParcelFileDescriptor[] pipe=null;

    try {
      pipe=ParcelFileDescriptor.createPipe();
      AssetManager assets=getContext().getResources().getAssets();

      new TransferTask(assets.open(uri.getLastPathSegment()),
                       new AutoCloseOutputStream(pipe[1])).start();
    }
    catch (IOException e) {
      Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
      throw new FileNotFoundException("Could not open pipe for: "
          + uri.toString());
    }

    return(pipe[0]);
  }

后台线程执行典型的流到流复制:

where the background thread does a typical stream-to-stream copy:

  static class TransferTask extends Thread {
    InputStream in;
    OutputStream out;

    TransferTask(InputStream in, OutputStream out) {
      this.in=in;
      this.out=out;
    }

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

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

        in.close();
        out.close();
      }
      catch (IOException e) {
        Log.e(getClass().getSimpleName(),
              "Exception transferring file", e);
      }
    }
  }

然而,MediaPlayer 窒息:

10-16 13:33:13.203: E/MediaPlayer(3060): Unable to to create media player
10-16 13:33:13.203: D/MediaPlayer(3060): Couldn't open file on client side, trying server side
10-16 13:33:13.207: E/TransferTask(3060): Exception transferring file
10-16 13:33:13.207: E/TransferTask(3060): java.io.IOException: write failed: EPIPE (Broken pipe)
10-16 13:33:13.207: E/TransferTask(3060):   at libcore.io.IoBridge.write(IoBridge.java:462)
10-16 13:33:13.207: E/TransferTask(3060):   at java.io.FileOutputStream.write(FileOutputStream.java:187)
10-16 13:33:13.207: E/TransferTask(3060):   at com.commonsware.android.audiolstream.PipeProvider$TransferTask.run(PipeProvider.java:120)
10-16 13:33:13.207: E/TransferTask(3060): Caused by: libcore.io.ErrnoException: write failed: EPIPE (Broken pipe)
10-16 13:33:13.207: E/TransferTask(3060):   at libcore.io.Posix.writeBytes(Native Method)
10-16 13:33:13.207: E/TransferTask(3060):   at libcore.io.Posix.write(Posix.java:178)
10-16 13:33:13.207: E/TransferTask(3060):   at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191)
10-16 13:33:13.207: E/TransferTask(3060):   at libcore.io.IoBridge.write(IoBridge.java:457)
10-16 13:33:13.207: E/TransferTask(3060):   ... 2 more
10-16 13:33:13.211: E/MediaPlayer(3060): Unable to to create media player
10-16 13:33:13.218: E/TransferTask(3060): Exception transferring file
10-16 13:33:13.218: E/TransferTask(3060): java.io.IOException: write failed: EPIPE (Broken pipe)
10-16 13:33:13.218: E/TransferTask(3060):   at libcore.io.IoBridge.write(IoBridge.java:462)
10-16 13:33:13.218: E/TransferTask(3060):   at java.io.FileOutputStream.write(FileOutputStream.java:187)
10-16 13:33:13.218: E/TransferTask(3060):   at com.commonsware.android.audiolstream.PipeProvider$TransferTask.run(PipeProvider.java:120)
10-16 13:33:13.218: E/TransferTask(3060): Caused by: libcore.io.ErrnoException: write failed: EPIPE (Broken pipe)
10-16 13:33:13.218: E/TransferTask(3060):   at libcore.io.Posix.writeBytes(Native Method)
10-16 13:33:13.218: E/TransferTask(3060):   at libcore.io.Posix.write(Posix.java:178)
10-16 13:33:13.218: E/TransferTask(3060):   at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191)
10-16 13:33:13.218: E/TransferTask(3060):   at libcore.io.IoBridge.write(IoBridge.java:457)
10-16 13:33:13.218: E/TransferTask(3060):   ... 2 more

有没有人看到使用 createPipe()MediaPlayer 提供媒体的工作代码?

Has anyone seen working code for using createPipe() to serve media to MediaPlayer?

提前致谢!

推荐答案

我不确定这是否可行.当我运行此代码时,我看到此跟踪:

I'm not sure this can ever work. When I run this code I see this trace:

I/AudioSystem(30916): getting audio flinger
I/AudioSystem(30916): returning new audio session id
D/IAudioFlinger(30916): newAudioSessionId In
D/AudioFlinger(28138): nextUniqueId, current 178
D/IAudioFlinger(30916): newAudioSessionId Out, id = 178
D/MediaPlayer(30916): setDataSource(Context context, content://com.commonsware.android.audiolstream/clip.ogg, Map<String, String> headers) in
D/MediaPlayer(30916): setDataSource(FileDescriptor fd) in
E/MediaPlayerService(28138): offset error

该偏移错误"来自 AOSP 中 MediaPlayerService.cpp 中的以下几行,它在管道的读取端执行 fstat():

That "offset error" comes from the following lines in MediaPlayerService.cpp in AOSP, where it does a fstat() on the read side of the pipe:

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
    struct stat sb;
    int ret = fstat(fd, &sb);

    ....

    if (offset >= sb.st_size) {
        LOGE("offset error");
        ::close(fd);
        return UNKNOWN_ERROR;
    }

并且 sb.st_size 报告为 -1(通过 Java 级别 ParcelFileDescriptor 上的 getStatSize()).错误处理程序关闭描述符,因此不久之后就会出现管道损坏错误.

And sb.st_size is reported as -1 (via getStatSize() on the ParcelFileDescriptor at the Java level). The error handler closes the descriptor, hence the broken pipe error shortly afterwards.

根据我的经验,MediaPlayer 有很多这样的坏点.除了直接在本地文件和(非常有问题)HTTP 流媒体上,我从未见过它适用于任何其他用途.我最终移植了 FFmpeg 来解决它的众多缺陷.

In my experience MediaPlayer has many broken bits like this. I've never seen it work for anything but directly on local files, and (very buggily) for HTTP streaming. I ended up porting FFmpeg to work around its numerous failings.

这篇关于有人让 MediaPlayer 使用 ParcelFileDescriptor 和 createPipe() 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆