注: 不同的android版本所用的player是不同的。
后缀是m3u8(不管是htpp/https还是local的), 用widevine player,
rtsp://用stagefright player
后缀是wvm, 使用widevine
后缀是webm, 使用stagefright player
ogg vorbis用stagefright player
midi用sonivox player(就是mediaservice下的midifile)
mp3: stagefright player
amr_bb/wb: stagefright player
其他缺省用avapi player(googletv case, 非googletv使用stagefright player),
smf/xmf/imy/rtx/rtttl/ota: sonivox player
udpmpt:/file:前缀: 用gtv mp2t media player
hdmi:前缀:用hdmi passthru player
content://前缀: 用contentprovider得到fd, 然后根据fd选择player
使用streamsource方式create player的时候使用nuplayer, 这个player支持httplive和rtsp
讲nuplayer:
http://wenku.baidu.com/view/096109bac77da26925c5b0a9.html
http://hi.baidu.com/yaoxidao/blog/item/50a85aebaa8a33c8d539c91a.html
zhegetaolun:
http://topic.csdn.net/u/20120320/10/549eafa0-b9aa-4293-a9a4-3e572aa8fbd4.html
注意这个:
在2.3,4.0上播放http和rtsp流媒体都是用的stagefright框架,但在4.0.3播放rtsp流媒体和m3u8的http流媒体使用的是NuPlayer框架。
mediaplayerclient: notify: 处理从mediaplayer service返回的callback消息
mediaplayerservice: create, decode, 等
bp/bn_mediaplayer: disconnect, setvideosurface, preparesync, start, stop, pause, seekTo, getDuration, reset, setlooping, invoke
mediaplayer 类使用getmediaplayerservice得到bpmediaplayerservice, 通过bpmediaplayerservice的create在bnmediaplayerservice端创建bnmediaplayer(server侧的client, 不是mediaplayerclient:), 并且返回bpmediaplayer给mediaplayer作为mPlayer. mediaplayer类中的控制函数通过bpmediaplayer实现具体media的控制。
mediaplayer类的setdatasource会转化为mediaplayerservice的create, 而这个create中又会调用继承bnmediaplayer的client的setdatasource(不是bp/bn mediaplayer的成员)
mediaplayer类继承了bnMediaplayerClient, 相应bpmediaplayerclient会作为bnmedialayer的继承对象client的成员, 这样, media service可将mediaplayerbase(具体mediaplayer的基类)的状态返回media的客户端程序。
如果是通过mediaplayerservice的decode接口, 那么是不需要mediaplayerclient/bp/bn_mediplayer的.
bp端的transact是bpbinder的transact, 这个函数会调用talkwithdriver来通过ioctrl调用binder driver, 而服务器端的jointhread也会产生循环的线程(会有两个: startthreadpool和jointhreadpool都会产生), 这个调用talkwithdriver获得相应的request, IPCThreadState的exucutecmd会调用bbinder的transact, 这个transact会调用自己的ontransact, bn也是bbinder的派生类, 这样bn的ontransact就被调用了!(因为ibinder是面向进程的, 所以这在mediaplayer serve的main函数里start/join Thread pool, 这样mediaplayerservice/(bp/bnmediaplayer), mediaplayerclient就可通过ibinder通信了(这个理解应该没错, 不然没地方找到这些是怎么有transaction响应的))
bpmedia player的client端的callback被mediaservice的cilent(bnmedialayer)的notify调用, 而这个notify会注册进antagonizer(在define callback_antagonizer时)和具体的player. 在antagonizer的callback线程中这个notify会被调用。而这个线程在antagonizer start(bnmediaplayer prepareAsync)之后每10ms循环一次, 直到退出(anatagonizer stop或者player)。
audiooutput也会收到mediaplayerbase的audiosink注册的callback。
audiocache在mediaplayerservice调decode的时候用,也是继承自mediaplayerbase的audiosink. 不同的是它自己分配buffer。
这里有个create问题, 怎么能在进程之间传递文件描述符fd呢?!!!!!
这里有个讨论传递描述符的:
http://www.chinaunix.net/jh/23/121580.html
下面的文章解释了java层的文件描述符传递:
1.文件描述符是如何在进程之间传递的?
我们知道文件描述符,就像虚拟内存的地址一样,是进程私有的资源。在一个进程中文件描 述符,在另外一个进程中,可能是无效的,也可能是对应另外一个文件。Android却可以把文件描述符从一个进程传到另外一个进程。第一次发现这种情况时,让我感到很惊奇,所以花了点时间去研究。看明白之后,发现其实现也 很简单:
Java代码:
-
复制到剪贴板 Java代码
- status_t Parcel::writeFileDescriptor(int fd)
- {
- flat_binder_object obj;
- obj.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj.handle = fd;
- obj.cookie = (void*)0;
- return writeObject(obj, true);
- }
在对文件描述符打包时,把对象的类型设置为BINDER_TYPE_FD。
在binder的内核模块binder_transaction函数中,我们可以看:
Java代码:
-
复制到剪贴板 Java代码
- case BINDER_TYPE_FD: {
- int target_fd;
- struct file *file;
-
- if (reply) {
- if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
- binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
- proc->pid, thread->pid, fp->handle);
- return_error = BR_FAILED_REPLY;
- goto err_fd_not_allowed;
- }
- } else if (!target_node->accept_fds) {
- binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
- proc->pid, thread->pid, fp->handle);
- return_error = BR_FAILED_REPLY;
- goto err_fd_not_allowed;
- }
-
- file = fget(fp->handle);
- if (file == NULL) {
- binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
- proc->pid, thread->pid, fp->handle);
- return_error = BR_FAILED_REPLY;
- goto err_fget_failed;
- }
- target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
- if (target_fd < 0) {
- fput(file);
- return_error = BR_FAILED_REPLY;
- goto err_get_unused_fd_failed;
- }
- task_fd_install(target_proc, target_fd, file);
- binder_debug(BINDER_DEBUG_TRANSACTION,
- " fd %ld -> %d\n", fp->handle, target_fd);
-
- fp->handle = target_fd;
- } break;
这里如果是文件描述符,就在目标进程中重新打开同一个文件了(虽然打开的是同一个文件,但目标进程拿到的文件描述符可能不相同)。
2.Receiver是如何工作的?
大家对Service的工作原理应该比较熟悉,先通过服务名称从 ServiceManager获取一个Binder,然后通过Binder去调用服务相应的函数。由客户端主动发起请求,这是典型是C/S模型。而 Receiver则是服务端反过来调用客户端函数,这就看起来有点让人感到迷惑了。
其实Receiver更简单,所有Broadcast都是从 ActivityManagerService发出的,所以只需要让 ActivityManagerService知道你的Receiver就行了,这是通过 ActivityManagerNative.registerReceiver完成的。实现自己的Receiver时都是实现 BroadcastReceiver接口,BroadcastReceiver本身并不是可以跨进程调用的,这是由 ActivityThread.PackageInfo.ReceiverDispatcher来包装的。
这里值得注意的是Receiver都是在ActivityThread里处理的,而不是在Binder线程里处理的,主要目的可能为了避免不必要的加锁操作吧。
Java代码:
-
复制到剪贴板 Java代码
- case BINDER_TYPE_FD: {
- int target_fd;
- struct file *file;
-
- if (reply) {
- if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
- binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
- proc->pid, thread->pid, fp->handle);
- return_error = BR_FAILED_REPLY;
- goto err_fd_not_allowed;
- }
- } else if (!target_node->accept_fds) {
- binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
- proc->pid, thread->pid, fp->handle);
- return_error = BR_FAILED_REPLY;
- goto err_fd_not_allowed;
- }
-
- file = fget(fp->handle);
- if (file == NULL) {
- binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
- proc->pid, thread->pid, fp->handle);
- return_error = BR_FAILED_REPLY;
- goto err_fget_failed;
- }
- target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
- if (target_fd < 0) {
- fput(file);
- return_error = BR_FAILED_REPLY;
- goto err_get_unused_fd_failed;
- }
- task_fd_install(target_proc, target_fd, file);
- binder_debug(BINDER_DEBUG_TRANSACTION,
- " fd %ld -> %d\n", fp->handle, target_fd);
-
- fp->handle = target_fd;
- } break;
这篇也讲了:
http://blog.csdn.net/xujianqun/article/details/6677897
http://blog.sina.com.cn/s/blog_4ad7c25401010tdv.html(这里面有些图很好)
http://wenku.baidu.com/view/5b7b3b6348d7c1c708a14521.html:
fd2 = dup(fd1): 复制fd1给fd2: fd2指向fd1指向的文件,
dup2(fd1, fd2): 使fd1指向fd2, 重定向fd2到fd1, 比如原来fd2指向标准输出, 那么现在fd2指向fd1打开的文件