1. StageFright介绍
    Android froyo版本多媒体引擎做了变动,新添加了stagefright框架,并且默认情况android选择stagefright,并没有完全抛弃opencore,主要是做了一个OMX层,仅仅是对 opencore的omx-component部分做了引用。stagefright是在MediaPlayerService这一层加入的,和opencore是并列的。Stagefright在 Android中是以shared library的形式存在(libstagefright.so),其中的module – AwesomePlayer可用来播放video/audio。 AwesomePlayer提供许多API,可以让上层的应用程序(Java/JNI)来调用。
  2. StageFright数据流封装
    2.1 由数据源DataSource生成MediaExtractor
    通过MediaExtractor::Create(dataSource)来实现。Create方法通过两步来生成相应的 MediaExtractor(MediaExtractor.cpp):

通过dataSource->sniff来探测数据类型

生成相应的Extractor:

 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")){        return new MPEG4Extractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {       return new MP3Extractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {        return new AMRExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {        return new WAVExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {        return new OggExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {        return new MatroskaExtractor(source);   } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {        return new MPEG2TSExtractor(source);
}

2.2 demux
把音视频轨道分离,生成mVideoTrack和mAudioTrack两个MediaSource。代码如下(AwesomePlayer.cpp):

if (!haveVideo && !strncasecmp(mime, "video/", 6)) {       setVideoSource(extractor->getTrack(i));        haveVideo = true;
} else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {       setAudioSource(extractor->getTrack(i));        haveAudio = true;
}

2.3 MediaSource(Parse, Decode)
得到的这两个MediaSource,只具有parser功能,没有decode功能。还需要对这两个MediaSource做进一步的包装,获取了两个MediaSource(具有parse和decode功能):

mVideoSource = OMXCodec::Create(mClient.interface(), mVideoTrack->getFormat(), false, // createEncoder            mVideoTrack,            NULL, flags);
mAudioSource = OMXCodec::Create(mClient.interface(), mAudioTrack->getFormat(),               false, // createEncoder                mAudioTrack);

当调用MediaSource.start()方法后,它的内部就会开始从数据源获取数据并解析,等到缓冲区满后便停止。在AwesomePlayer里就可以调用MediaSource的read方法读取解码后的数据。

对于mVideoSource来说,读取的数据:mVideoSource->read(&mVideoBuffer, &options)交给显示模块进行渲染,mVideoRenderer->render(mVideoBuffer);

对mAudioSource来说,用mAudioPlayer对mAudioSource进行封装,然后由mAudioPlayer负责读取数据和播放控制。

  1. StageFright的Decode
    经过“数据流的封装”得到的两个MediaSource,其实是两个OMXCodec。AwesomePlayer和mAudioPlayer都是从MediaSource中得到数据进行播放。AwesomePlayer得到的是最终需要渲染的原始视频数据,而mAudioPlayer读取的是最终需要播放的原始音频数据。也就是说,从OMXCodec中读到的数据已经是原始数据了。
    OMXCodec是怎么把数据源经过parse、decode两步以后转化成原始数据的。从OMXCodec::Create这个构造方法开始,它的参数:

IOMX &omx指的是一个OMXNodeInstance对象的实例。
MetaData &meta这个参数由MediaSource.getFormat获取得到。这个对象的主要成员就是一个KeyedVector<uint32_t, typed_data> mItems,里面存放了一些代表MediaSource格式信息的名值对。
bool createEncoder指明这个OMXCodec是编码还是解码。
MediaSource &source是一个MediaExtractor。
char *matchComponentName指定一种Codec用于生成这个OMXCodec。

先使用findMatchingCodecs寻找对应的Codec,找到以后为当前IOMX分配节点并注册事件监听器:omx->allocateNode(componentName, observer, &node)。最后,把IOMX封装进一个OMXCodec:

sp<OMXCodec> codec = new OMXCodec(omx, node, quirks, createEncoder, mime, componentName, source);

这样就得到了OMXCodec。
AwesomePlayer中得到这个OMXCodec后,首先调用mVideoSource->start()进行初始化。 OMXCodec初始化主要是做两件事:

(1) 向OpenMAX发送开始命令。mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle)

(2) 调用allocateBuffers()分配两个缓冲区,存放在Vector mPortBuffers中,分别用于输入和输出。

AwesomePlayer开始播放后,通过mVideoSource->read(&mVideoBuffer, &options)读取数据。

mVideoSource->read(&mVideoBuffer, &options)具体是调用OMXCodec.read来读取数据。而OMXCodec.read主要分两步来实现数据的读取:

(1) 通过调用drainInputBuffers()对mPortBuffers[kPortIndexInput]进行填充,这一步完成 parse。由OpenMAX从数据源把demux后的数据读取到输入缓冲区,作为OpenMAX的输入。

(2) 通过fillOutputBuffers()对mPortBuffers[kPortIndexOutput]进行填充,这一步完成 decode。由OpenMAX对输入缓冲区中的数据进行解码,然后把解码后可以显示的视频数据输出到输出缓冲区。

AwesomePlayer通过mVideoRenderer->render(mVideoBuffer)对经过parse和decode 处理的数据进行渲染。一个mVideoRenderer其实就是一个包装了IOMXRenderer的AwesomeRemoteRenderer:

mVideoRenderer = new AwesomeRemoteRenderer(mClient.interface()->createRenderer(mISurface, component, (OMX_COLOR_FORMATTYPE)format, decodedWidth, decodedHeight, mVideoWidth, mVideoHeight, rotationDegrees));
  1. StageFright处理流程
    Audioplayer 为AwesomePlayer的成员,audioplayer通过callback来驱动数据的获取,awesomeplayer则是通过 videoevent来驱动。二者有个共性,就是数据的获取都抽象成mSource->Read()来完成,且read内部把parser和dec 绑在一起。Stagefright AV同步部分,audio完全是callback驱动数据流,video部分在onVideoEvent里会获取audio的时间戳,是传统的AV时间戳做同步。
    4.1 AwesomePlayer的Video主要有以下几个成员:
    (1) mVideoSource(解码视频)

(2) mVideoTrack(从多媒体文件中读取视频数据)

(3) mVideoRenderer(对解码好的视频进行格式转换,android使用的格式为RGB565)

(4) mISurface(重绘图层)

(5) mQueue(event事件队列)
4.2 stagefright运行时的Audio部分抽象流程如下:
(1) 设置mUri的路径

(2) 启动mQueue,创建一个线程来运行 threadEntry(命名为TimedEventQueue,这个线程就是event调度器)

(3) 打开mUri所指定的文件的头部,则会根据类型选择不同的分离器(如MPEG4Extractor)

(4) 使用 MPEG4Extractor对MP4进行音视频轨道的分离,并返回MPEG4Source类型的视频轨道给mVideoTrack

(5) 根据 mVideoTrack中的编码类型来选择解码器,avc的编码类型会选择AVCDecoder,并返回给mVideoSource,并设置mVideoSource中的mSource为mVideoTrack

(6) 插入onVideoEvent到Queue中,开始解码播放

(7) 通过mVideoSource对象来读取解析好的视频buffer
如果解析好的buffer还没到AV时间戳同步的时刻,则推迟到下一轮操作

(1) mVideoRenderer为空,则进行初始化(如果不使用 OMX会将mVideoRenderer设置为AwesomeLocalRenderer)

(2) 通过mVideoRenderer对象将解析好的视频buffer转换成RGB565格式,并发给display模块进行图像绘制

(3) 将onVideoEvent重新插入event调度器来循环
4.3 数据由源到最终解码后的流程如下:

设置DataSource,数据源可以两种URI和FD。URI可以http: //,rtsp://等。FD是一个本地文件描述符,能过FD,可以找到对应的文件。
由DataSource生成MediaExtractor。通过sp extractor = MediaExtractor::Create(dataSource);来实现。 MediaExtractor::Create(dataSource)会根据不同的数据内容创建不同的数据读取对象。
通过调用setVideoSource由MediaExtractor分解生成音频数据流(mAudioTrack)和视频数据流(mVideoTrack)。
onPrepareAsyncEvent()如果DataSource是URL的话,根据地址获取数据,并开始缓冲,直到获取到mVideoTrack和mAudioTrack。mVideoTrack和mAudioTrack通过调用initVideoDecoder()和initAudioDecoder()来生成 mVideoSource和mAudioSource这两个音视频解码器。然后调用postBufferingEvent_l()提交事件开启缓冲。
数据缓冲的执行函数是onBufferingUpdate()。缓冲区有足够的数据可以播放时,调用play_l()开始播放。play_l()中关键是调用了postVideoEvent_l(),提交了 mVideoEvent。这个事件执行时会调用函数onVideoEvent()。这个函数通过调用 mVideoSource->read(&mVideoBuffer, &options)进行视频解码。音频解码通过mAudioPlayer实现。
视频解码器解码后通过mVideoSource->read读取一帧帧的数据,放到mVideoBuffer中,最后通过 mVideoRenderer->render(mVideoBuffer)把视频数据发送到显示模块。当需要暂停或停止时,调用cancelPlayerEvents来提交事件用来停止解码,还可以选择是否继续缓冲数据。

Android Media Framework(3): Stagefright框架流程解读相关推荐

  1. StageFright框架流程解读

    1.    StageFright介绍 Android froyo版本多媒体引擎做了变动,新添加了stagefright框架,并且默认情况android选择stagefright,并没有完全抛弃ope ...

  2. Android Media Framework(1): 总纲

    转自:http://www.jianshu.com/users/5ba48666a89d/latest_articles Android系统整体架构: 我们先看一下多媒体框架在整个Android系统所 ...

  3. Android Media (Audio) Framework 多媒体系统框架

    http://blog.csdn.net/lskshz/article/details/17264113 原址:http://blog.csdn.net/myzhzygh/article/detail ...

  4. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(二)

    文章大纲 引言 一.DirectFragment 1.当选中DirectoryFragment中RecyclerView的Item时 2.选中DirectoryFragment中RecyclerVie ...

  5. android stagefright框架

    http://blog.csdn.net/mirkerson/article/details/38520135 stagefright框架(一)Video Playback的流程 在Android上, ...

  6. android stagefright 框架

    原文:[转]android stagefright 框架 链接:http://blog.chinaunix.net/uid-9838896-id-2976618.html 在Android上,预设的多 ...

  7. Android Multimedia Framework overview(多媒体框架概述)--base on jellybean(一)

    不知为啥今晚突然脑海中闪现出一个念头:写博客!原因有二,其一就是记录下自己的学习所得,巩固自己的知识,温故而知新吧,以前都是光看光想,都没有记录,而且不写下来,领悟估计就差点了,好记忆不如烂笔头啊!其 ...

  8. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(一)

    文章大纲 引言 一.Android Storage Access Framework 二.Storage Access Framework 的主要角色成员 1.Document Provider 文件 ...

  9. 高通msm8917 37 40(android 7.1) 摄像头框架调用流程

    以问答的形式来理解摄像头框架流程 问:aw_camera.xml中配置的多个摄像头在哪里匹配? 答:sensor.c(vendor)通过iotcl到底层在msm_sensor_driver_probe ...

  10. android jni framework,Android Framework层的JNI机制(二)

    Java框架层中有很多地方使用JNI机制,每一个部分的框架层代码,都可能有与之对应的JNI库.先了解Java框架层的组成,继续看一下JNI在框架层中的使用. Java框架层的组成 Java框架层的实体 ...

最新文章

  1. 线程,协程对比和Python爬虫实战说明
  2. Linux基金会网络策略副总裁Marc Cohn:OPEN-O遍及网络,尽享服务
  3. Android面试闯关——Activity(持续更新中)
  4. IHelloWorldService
  5. 专心做业务,别想不开搞研发
  6. python tablewidget 颜色_更改QTableWidget的默认选择颜色,并使其半透明
  7. dhdas信号测试分析系统软件,基于DHDAS动态信号采集分析系统的折叠舵面模态试验探究...
  8. MongoDB的性能优化
  9. MATLAB数字图像处理 实验一:图像处理基本操作(平移、放大、缩小、旋转、插值)
  10. PackageManager.hasSystemFeature Android SystemServer裁剪
  11. Spring学习-黎活明视频学习注解
  12. 计算机课程设计答辩评语,课程设计评语模板.doc
  13. 汤姆猫代码python_iOS开发:纯代码实现汤姆猫小游戏
  14. 如何将硬盘分区合并不丢失数据,合并两个硬盘分区不删除数据
  15. word双栏左右不能对齐
  16. 2022黑马Python学习笔记
  17. 文件服务器搭建手机,自己搭建手机云服务器
  18. 张丽俊最新演讲:要像竹子一样扎根,你终会一飞冲天
  19. 10项目管理--项目沟通管理
  20. 银河麒麟桌面操作系统V10创建热点

热门文章

  1. 受康奈尔笔记法启发设计的程序员算法手写本
  2. 神经网络预测模型基本原理与编程实现
  3. 嫡权法赋权法_三种权重赋权法的比较分析
  4. [开源教程] 双路混控有刷电调 DIY教程【作者:我爱萝丽爱萝丽】(双路单向电调)
  5. 谷歌地图地名显示繁体字_谷歌地图怎么把字去掉
  6. 邮件服务器pop110什么意思,pop pop3区别_25和110端口_imap和pop怎么设置
  7. ArcGis拓扑——规则、概念与要点
  8. Matlab中直方图的绘制histogram函数
  9. Nutch简介(转2)
  10. 南天PR2 PR2E PR9 中航 PR-b PR-V PR-C PR-t PR-u PR-d GWI PR2 plus 打印机驱动安装视频教程