有人让 MediaPlayer 使用 ParcelFileDescriptor 和 createPipe() 吗? [英] Anyone Have MediaPlayer Working with ParcelFileDescriptor and createPipe()?
问题描述
关于 我最近关于 MediaRecorder
和 createPipe()
,以及 这个其他问题,我现在试图让 MediaPlayer
处理由ContentProvider
通过 ParcelFileDescriptor
和 createPipe()
.
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
与 这个示例项目,用于为 Adobe 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屋!