StagefrightPlayer+AwesomePlayer+omx

   上文我们介绍到通过不同的playerType创建不同的player。
     StagefrightPlayer:
   
   
  1. sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
  2. {
  3. // determine if we have the right player type
  4. sp<MediaPlayerBase> p = mPlayer;
  5. if ((p != NULL) && (p->playerType() != playerType)) {
  6. ALOGV("delete player");
  7. p.clear();
  8. }
  9. if (p == NULL) {
  10. p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid);
  11. }
  12. if (p != NULL) {
  13. p->setUID(mUID);
  14. }
  15. return p;
  16. }
   
   
  1. virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {
  2. ALOGV(" create StagefrightPlayer");
  3. return new StagefrightPlayer();
  4. }
   当我们打开StagefrightPlayer,发现其只是一个空壳:
    
    
  1. kernel\android\marshmallow\frameworks\av\media\libmediaplayerservice\StagefrightPlayer.cpp
     
     
  1. status_t StagefrightPlayer::setDataSource(
  2. const char *url, const KeyedVector<String8, String8> *headers) {
  3. return mPlayer->setDataSource(url, headers);
  4. }
  5. status_t StagefrightPlayer::prepare() {
  6. return mPlayer->prepare();
  7. }
  8. status_t StagefrightPlayer::start() {
  9. ALOGV("start");
  10. return mPlayer->play();
  11. }
  12. status_t StagefrightPlayer::stop() {
  13. ALOGV("stop");
  14. return pause(); // what's the difference?
  15. }
  16. status_t StagefrightPlayer::pause() {
  17. ALOGV("pause");
  18. return mPlayer->pause();
  19. }
    实际起作用的是AwesomePlayer *mPlayer; 
    AwesomePlayer:
视频处理过程中有很多都是十分耗时的,如果都放在一个大的线程空间中。用户体验的效果可想而知。所以通常都是做异步操作。  
AwesomePlayer是通过event事件调度来实现这些功能之间的驱动和调用的。  
AwesomePlayer中的内部变量:
    
    
  1. TimedEventQueue mQueue;
这个mQueue就是AwesomePlayer的事件队列,也是事件调度器。从他类型的名字上就能很清楚的看出他是以时间为基础事件队列。接下来看看它是怎么玩转的。
  1.先来看TimedEventQueue的内部结构,TimedEventQueue内部有一个 List<QueueItem>,每个QueueItem包含enent和时间:
     
     
  1. struct QueueItem {
  2. sp<Event> event;
  3. int64_t realtime_us;
  4. };
有一个独立线程threadEntry是在TimedEventQueue::start被创建,TimedEventQueue::stop被销毁的。
    
    
  1. void TimedEventQueue::start() {
  2. if (mRunning) {
  3. return;
  4. }
  5. mStopped = false;
  6. pthread_attr_t attr;
  7. pthread_attr_init(&attr);
  8. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  9. pthread_create(&mThread, &attr, ThreadWrapper, this);
  10. pthread_attr_destroy(&attr);
  11. mRunning = true;
  12. }
  13. void TimedEventQueue::stop(bool flush) {
  14. if (!mRunning) {
  15. return;
  16. }
  17. if (flush) {
  18. postEventToBack(new StopEvent);
  19. } else {
  20. postTimedEvent(new StopEvent, INT64_MIN);
  21. }
  22. void *dummy;
  23. pthread_join(mThread, &dummy);
  24. mQueue.clear();
  25. mRunning = false;
  26. }

2.List<QueueItem>目的就是按照延时时间维护一个event事件队列,threadEntry线程就是不断的从队列的头取出一个event,然后通过  event->fire(this, now_us); 回调到这个event事件提前注册好的相对应功能函数。
     
     
  1. void TimedEventQueue::threadEntry() {
  2. prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);
  3. for (;;) {
  4. int64_t now_us = 0;
  5. sp<Event> event;
  6. bool wakeLocked = false;
  7. {
  8. Mutex::Autolock autoLock(mLock);
  9. if (mStopped) {
  10. break;
  11. }
  12. while (mQueue.empty()) {
  13. mQueueNotEmptyCondition.wait(mLock);
  14. }
  15. event_id eventID = 0;
  16. for (;;) {
  17. if (mQueue.empty()) {
  18. // The only event in the queue could have been cancelled
  19. // while we were waiting for its scheduled time.
  20. break;
  21. }
  22. List<QueueItem>::iterator it = mQueue.begin();
  23. eventID = (*it).event->eventID();
  24. now_us = ALooper::GetNowUs();
  25. int64_t when_us = (*it).realtime_us;
  26. int64_t delay_us;
  27. if (when_us < 0 || when_us == INT64_MAX) {
  28. delay_us = 0;
  29. } else {
  30. delay_us = when_us - now_us;
  31. }
  32. if (delay_us <= 0) {
  33. break;
  34. }
  35. static int64_t kMaxTimeoutUs = 10000000ll; // 10 secs
  36. bool timeoutCapped = false;
  37. if (delay_us > kMaxTimeoutUs) {
  38. ALOGW("delay_us exceeds max timeout: %" PRId64 " us", delay_us);
  39. // We'll never block for more than 10 secs, instead
  40. // we will split up the full timeout into chunks of
  41. // 10 secs at a time. This will also avoid overflow
  42. // when converting from us to ns.
  43. delay_us = kMaxTimeoutUs;
  44. timeoutCapped = true;
  45. }
  46. status_t err = mQueueHeadChangedCondition.waitRelative(
  47. mLock, delay_us * 1000ll);
  48. if (!timeoutCapped && err == -ETIMEDOUT) {
  49. // We finally hit the time this event is supposed to
  50. // trigger.
  51. now_us = ALooper::GetNowUs();
  52. break;
  53. }
  54. }
  55. // The event w/ this id may have been cancelled while we're
  56. // waiting for its trigger-time, in that case
  57. // removeEventFromQueue_l will return NULL.
  58. // Otherwise, the QueueItem will be removed
  59. // from the queue and the referenced event returned.
  60. event = removeEventFromQueue_l(eventID, &wakeLocked);
  61. }
  62. if (event != NULL) {
  63. // Fire event with the lock NOT held.
  64. event->fire(this, now_us);
  65. if (wakeLocked) {
  66. Mutex::Autolock autoLock(mLock);
  67. releaseWakeLock_l();
  68. }
  69. }
  70. }
  71. }
 
3.然后看看AwesomePlayer是怎么用TimedEventQueue,AwesomePlayer会定义很多类型的event事件,并把和这些事件相关的功能函数一定绑定起来。
     
     
  1. mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
  2. mVideoEventPending = false;
  3. mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
  4. mStreamDoneEventPending = false;
  5. mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
  6. mBufferingEventPending = false;
  7. mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
  8. mVideoEventPending = false;
  9. mCheckAudioStatusEvent = new AwesomeEvent(this, &AwesomePlayer::onCheckAudioStatus);
        原因之前也说了,因为好多音视频处理的功能是十分耗时间的,假如AwesomePlayer 想用某个功能,他并不是直线去调用它,而是抽象成一种AwesomeEvent,将想要调用的功能函数与事件捆绑。通过TimedEventQueue::postTimedEvent(),按照延时的优先顺序把它放到TimedEventQueue的队列之中。然后AwesomePlayer就不管了。TimedEventQueue start之后,自己内部的线程会从队列中依次取出这些事件,然后通过event->fire回调事件的功能函数。这样就达到了AwesomePlayer的目的。
4.之前也介绍过mediaPlayer大致流程就是
      
      
  1. mediaPlayer.setDataSource(path);
  2. mediaPlayer.prepare();
  3. mediaPlayer.start();
在AwesomePlayer 也是这种流程,在AwesomePlayer prepare()相关函数中。
     
     
  1. status_t AwesomePlayer::prepareAsync_l() {
  2. if (mFlags & PREPARING) {
  3. return UNKNOWN_ERROR; // async prepare already pending
  4. }
  5. if (!mQueueStarted) {
  6. mQueue.start();
  7. mQueueStarted = true;
  8. }
  9. modifyFlags(PREPARING, SET);
  10. mAsyncPrepareEvent = new AwesomeEvent(
  11. this, &AwesomePlayer::onPrepareAsyncEvent);
  12. mQueue.postEvent(mAsyncPrepareEvent);
  13. return OK;
  14. }
并没有实际的调用onPrepareAsyncEvent()真正的功能函数,他只是把mQueue start之后,然后创建个mAsyncPrepareEvent事件,把它插入到mQueue之中就不管了,具体调用是由mQueue中的threadEntry线程来做。
1.通过setDataSource 指定播放器的数据源。可以是URI或者fd.可以是http:// 、rtsp://、本地地址或者本地文件描述符fd。其最终调用是将上层传递来的参数转化为DataSource,为下一步的demux提供数据支持。
2.在真正Prepare功能函数onPrepareAsyncEvent()会调用finishSetDataSource_l。通过第一步产生的DataSource来生成extractor,因为封装的格式很多,所以需要通过DataSource的信息,去创建不同的extractor。
     
     
  1. kernel\android\marshmallow\frameworks\av\media\libstagefright\MediaExtractor.cpp
     
     
  1. extractor = MediaExtractor::Create(
  2. dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
      
      
  1. if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
  2. || !strcasecmp(mime, "audio/mp4")) {
  3. ret = new MPEG4Extractor(source);
  4. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
  5. ret = new MP3Extractor(source, meta);
  6. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
  7. || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
  8. ret = new AMRExtractor(source);
  9. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
  10. ret = new FLACExtractor(source);
  11. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
  12. ret = new WAVExtractor(source);
  13. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
  14. ret = new OggExtractor(source);
  15. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
  16. ret = new MatroskaExtractor(source);
  17. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
  18. ret = new MPEG2TSExtractor(source);
  19. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
  20. // Return now. WVExtractor should not have the DrmFlag set in the block below.
  21. return new WVMExtractor(source);
  22. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
  23. ret = new AACExtractor(source, meta);
  24. } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
  25. ret = new MPEG2PSExtractor(source);
  26. }
3.得到extractor之后,通过setVideoSource() setAudioSource()产生独立的mVideoTrack(视频)、mAudioTrack(音频)数据流,分别为音视频解码器提供有各自需要的数据流。
 
其实extractor和mVideoTrack、mAudioTrack就组成了播放器模型中的demuxer部分。把封装格式里面的音视频流拆分出来,分别的送给音视频解码器。
    
    
  1. void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
  2. CHECK(source != NULL);
  3. mVideoTrack = source;
  4. }
     
     
  1. void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
  2. CHECK(source != NULL);
  3. mAudioTrack = source;
  4. }
4.接下来就是initVideoDecoder() initAudioDecoder().依赖上面产生的mVideoTrack(视频)、mAudioTrack(音频)数据流。生成了mVideoSource和mAudioSource这两个音视频解码器。不同类型匹配不同的解码器。
    
    
  1. mVideoSource = OMXCodec::Create(
  2. mClient.interface(), mVideoTrack->getFormat(),
  3. false, // createEncoder
  4. mVideoTrack,
  5. NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
  6. mAudioSource = OMXCodec::Create(
  7. mClient.interface(), mAudioTrack->getFormat(),
  8. false, // createEncoder
  9. mAudioTrack);
  10. }
mVideoSource、mAudioSource组成了播放器模型中的decoder部分。
android系统中的编解码器部分用的是openmax,以后会深入了解。openma x是一套标准接口,各家硬件厂商都可以遵循这个标准来做自己的实现,发挥自己芯片特性。然后提供给android系统来用。因为大部分的机顶盒芯片产品硬件的编解码是它的优势,可以把这种优势完全融入到android平台中。以后手机高清视频硬解码也会是个趋势。
5.解码完之后的数据就要输出了。AwesomePlayer分别用了mVideoRenderer做视频输出、mAudioPlayer做音频输出。他们分别调用android图像和音频的相关服务。这俩部分是android平台中十分重要的2块,以后会深入了解。
 
mVideoRenderer和mAudioPlayer就组成了播放器中output的部分。

OMX:待续










   




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值