Quantcast
Viewing all articles
Browse latest Browse all 5930

Android Multimedia框架总结(九)Stagefright框架之数据处理及到OMXCodec过程

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085

不知不觉到第九篇了,感觉还有好多好多没有写,路漫漫其修远兮 ,吾将上下而求索,上篇主要介绍了Stagefright框架及AwesomePlayer的数据解析器,最后我们说道,涉及parse及decode部分,将在本篇中介绍,看下今天的Agenda:

  • 两张图看数据走向
  • AwesomePlayer中prepare过程
  • AwesomePlayer初始化音视频解码器过程
  • Stagefright的Decode过程
  • Stagefright处理数据过程
  • 数据由源到最终解码后的流程

两张图看数据走向

一切从MediaSource中来,一切又从MediaSource中去
Audio:
Image may be NSFW.
Clik here to view.
这里写图片描述

Video:
Image may be NSFW.
Clik here to view.
这里写图片描述

AwesomePlayer中prepare过程

首先我们开始看下AwesomePlayer的prepare的执行过程:

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

以上代码总结为:prepare过程调用了prepareAsync_l函数,在prepareAsync_l中执行new AwesomeEvent,并将AwesomePlayer调用onPrepareAsyncEvent的结果返回AwesomeEvent的构造作为参数。
接着分析AwesomeEvent的过程: 启动mQueue,作为event handler

Image may be NSFW.
Clik here to view.
这里写图片描述

上面new AwesomeEvent会执行onPrepareAsyncEvent函数,我们看下该函数的做了什么?

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

以上代码总结为:会将AV(音视频)进行分处理,于是有了AwesomePlayer::initVideoDecoder及AwesomePlayer::initAudioDecoder()函数。
本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085

初始化音视频解码器过程

我们先看下initVideoDecoder,即初始化视频解码器:

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

接着看下初始化音频解码器,看下几个变量的声明:

Image may be NSFW.
Clik here to view.
这里写图片描述

接着看代码如下:

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

对上面代码进行总结:
Stagefright调用AwesomePlayer的prepare后,AwesomePlayer调用自身的prepareAsync进行初始化化音视频解码器,这两个方法里面都会OMXCodec::Create,接下来看下这个过程。

Stagefright的Decode过程

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

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

以上代码总结为:对应参数分析:

  • 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:

Image may be NSFW.
Clik here to view.
这里写图片描述

这样就得到了OMXCodec。

  • AwesomePlayer中得到这个OMXCodec后,接着看initVideoDecoder/initAudioDecoder,这里看initAudioDecoder方法,是把 mAudioSource = mOmxSource,赋值,接着调用mAudioSource->start()进行初始化。 OMXCodec初始化主要是做两件事:
    • 向OpenMAX发送开始命令。mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle)
    • 调用allocateBuffers()分配两个缓冲区,存放在Vector mPortBuffers[2]中,分别用于输入和输出。
  • 然后在现个initxxxDecoder方法中会调用(mAudioSource->start()/mVideoSource->start())

Image may be NSFW.
Clik here to view.
这里写图片描述

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

  • 对于mVideoSource来说,读取的数据:mVideoSource->read(&mVideoBuffer, &options)交给显示模块进行渲染,mVideoRenderer->render(mVideoBuffer);
  • 对mAudioSource来说,用mAudioPlayer对mAudioSource进行封装,然后由mAudioPlayer负责读取数据和播放控制。

  • AwesomePlayer调用OMXCode读取ES数据,并且进行解码的处理

  • OMXCodec调用MediaSource的read函数来获取音视频的数据
  • OMXCodec调用Android的IOMX接口,其实就是Stagefrightdecode中的 OMX实现

本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085

这个过程就是prepare的过程,重点是解码把流放到Buffer中
接下来,当java层调用start方法时,通过mediaplayerservice,再传到StagefrightPlayer中,引用AwesomePlayer,这样就调到AwesomePlayer的play方法,看代码:

Image may be NSFW.
Clik here to view.
这里写图片描述

Image may be NSFW.
Clik here to view.
这里写图片描述

  • 当AwesomePlayer调用play后,通过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:

Image may be NSFW.
Clik here to view.
这里写图片描述

Stagefright处理数据过程

  • Audioplayer为AwesomePlayer的成员,audioplayer通过callback来驱动数据的获取,awesomeplayer则是通过 videoevent来驱动。二者有个共性,就是数据的获取都抽象成mSource->read()来完成,且read内部把parse和decode绑在一起。Stagefright AV同步部分,audio完全是callback驱动数据流,注意是video部分在onVideoEvent里会获取audio的时间戳,是传统的AV时间戳做同步。

  • AwesomePlayer的Video主要有以下几个成员:

    • mVideoSource(解码视频)
    • mVideoTrack(从多媒体文件中读取视频数据)
    • mVideoRenderer(对解码好的视频进行格式转换,android使用的格式为RGB565)
    • mISurface(重绘图层)
    • mQueue(event事件队列)
  • stagefright运行时的Audio流程如下:

    • 首先设置mUri的路径
    • 启动mQueue,创建一个线程来运行 threadEntry(命名为TimedEventQueue,这个线程就是event调度器)
    • 打开mUri所指定的文件的头部,则会根据类型选择不同的分离器(如MPEG4Extractor)
    • 使用 MPEG4Extractor对MP4进行音视频轨道的分离,并返回MPEG4Source类型的视频轨道给mVideoTrack
    • 根据 mVideoTrack中的编码类型来选择解码器,avc的编码类型会选择AVCDecoder,并返回给mVideoSource,并设置mVideoSource中的mSource为mVideoTrack
    • 插入onVideoEvent到Queue中,开始解码播放
    • 通过mVideoSource对象来读取解析好的视频buffer

如果解析好的buffer还没到AV时间戳同步的时刻,则推迟到下一轮操作

1、mVideoRenderer为空,则进行初始化(如果不使用 OMX会将mVideoRenderer设置为AwesomeLocalRenderer)
2、通过mVideoRenderer对象将解析好的视频buffer转换成RGB565格式,并发给display模块进行图像绘制
3、将onVideoEvent重新插入event调度器来循环

本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085

Stagefright数据由源到最终解码后的流程

可以对照《Android Multimedia框架总结(八)Stagefright框架之AwesomePlayer及数据解析器》中那个图,这里不贴了,

  • 设置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干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

Image may be NSFW.
Clik here to view.
这里写图片描述

如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

作者:hejjunlin 发表于2016/9/14 3:02:36 原文链接
阅读:56 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>