20

andに関する私の最近の質問MediaRecorderと、createPipe()この他の SO questioncreatePipe()でのテクニックの議論に関連して、私は現在、 via andによって提供されるコンテンツを操作しようとしています。MediaPlayerContentProviderParcelFileDescriptorcreatePipe()

このサンプル プロジェクトには、これまでの作業が含まれています。これは、生のリソースとして保存されている OGG クリップを再生する以前のサンプルに基づいています。したがって、私のクリップが正常であることはわかっています。

MediaPlayerセットアップを次のように変更しました。

  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、myUriが適切に構築されていることがわかります。

PipeProviderは、このサンプル プロジェクトと同じもので、PDF を Adob​​e Reader に提供するために機能します。これにより、コードの混乱が制限されます。:-)

具体的には、以下openFile()からパイプを作成します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]);
  }

ここで、バックグラウンド スレッドは典型的なストリーム間のコピーを行います。

  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か?

前もって感謝します!

4

4 に答える 4

12

これが機能するかどうかはわかりません。このコードを実行すると、次のトレースが表示されます。

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

その「オフセット エラー」は、パイプの読み取り側で fstat() を実行する AOSP の MediaPlayerService.cpp の次の行から発生します。

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() を介して)。エラー ハンドラーが記述子を閉じるため、その直後に壊れたパイプ エラーが発生します。

私の経験では、MediaPlayer にはこのような壊れた部分がたくさんあります。ローカルファイルで直接動作するのを見たことがなく、(非常にバグがありますが) HTTP ストリーミングでも動作します。私はFFmpegを移植して、その多くの失敗を回避しました。

于 2012-10-17T14:47:01.093 に答える
8

PipeDataWriter(基本的にパイプとスレッドを使用)を使用して、ContentProviderを介してMediaPlayerでパイプを使用しようとしました。

問題は、少なくともビデオコンテンツに関して、MediaPlayerが期待するファイル記述子はシーク可能でなければならず、パイプでfseekを実行できないことです。

于 2012-10-17T13:29:32.067 に答える