android media service

 注: 不同的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代码:
  1. Java代码
    1. status_t Parcel::writeFileDescriptor(int fd)  
    2. {  
    3. flat_binder_object obj;  
    4. obj.type = BINDER_TYPE_FD;  
    5. obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;  
    6. obj.handle = fd;  
    7. obj.cookie = (void*)0;  
    8. return writeObject(obj, true);  
    9. }  



在对文件描述符打包时,把对象的类型设置为BINDER_TYPE_FD。
在binder的内核模块binder_transaction函数中,我们可以看:

Java代码:
  1. Java代码
    1. case BINDER_TYPE_FD: {  
    2. int target_fd;  
    3. struct file *file;  
    4.   
    5. if (reply) {  
    6. if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {  
    7. binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",  
    8. proc->pid, thread->pid, fp->handle);  
    9. return_error = BR_FAILED_REPLY;  
    10. goto err_fd_not_allowed;  
    11. }  
    12. else if (!target_node->accept_fds) {  
    13. binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",  
    14. proc->pid, thread->pid, fp->handle);  
    15. return_error = BR_FAILED_REPLY;  
    16. goto err_fd_not_allowed;  
    17. }  
    18.   
    19. file = fget(fp->handle);  
    20. if (file == NULL) {  
    21. binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",  
    22. proc->pid, thread->pid, fp->handle);  
    23. return_error = BR_FAILED_REPLY;  
    24. goto err_fget_failed;  
    25. }  
    26. target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);  
    27. if (target_fd < 0) {  
    28. fput(file);  
    29. return_error = BR_FAILED_REPLY;  
    30. goto err_get_unused_fd_failed;  
    31. }  
    32. task_fd_install(target_proc, target_fd, file);  
    33. binder_debug(BINDER_DEBUG_TRANSACTION,  
    34. " fd %ld -> %d\n", fp->handle, target_fd);  
    35. /* TODO: fput? */  
    36. fp->handle = target_fd;  
    37. 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代码:
  1. Java代码
    1. case BINDER_TYPE_FD: {  
    2. int target_fd;  
    3. struct file *file;  
    4.   
    5. if (reply) {  
    6. if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {  
    7. binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",  
    8. proc->pid, thread->pid, fp->handle);  
    9. return_error = BR_FAILED_REPLY;  
    10. goto err_fd_not_allowed;  
    11. }  
    12. else if (!target_node->accept_fds) {  
    13. binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",  
    14. proc->pid, thread->pid, fp->handle);  
    15. return_error = BR_FAILED_REPLY;  
    16. goto err_fd_not_allowed;  
    17. }  
    18.   
    19. file = fget(fp->handle);  
    20. if (file == NULL) {  
    21. binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",  
    22. proc->pid, thread->pid, fp->handle);  
    23. return_error = BR_FAILED_REPLY;  
    24. goto err_fget_failed;  
    25. }  
    26. target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);  
    27. if (target_fd < 0) {  
    28. fput(file);  
    29. return_error = BR_FAILED_REPLY;  
    30. goto err_get_unused_fd_failed;  
    31. }  
    32. task_fd_install(target_proc, target_fd, file);  
    33. binder_debug(BINDER_DEBUG_TRANSACTION,  
    34. " fd %ld -> %d\n", fp->handle, target_fd);  
    35. /* TODO: fput? */  
    36. fp->handle = target_fd;  
    37. 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打开的文件

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值