解决方案

stagefright简介

seo靠我 2023-09-24 14:03:34

1、    StageFright介绍      Android froyo版本多媒体引擎做了变动,新添加了stagefright框架,并且默认情况android选择stagefright,并没有完全SEO靠我抛弃 opencore,主要是做了一个OMX层,仅仅是对 opencore的omx-component部分做了引用。stagefright是在MediaPlayerService这一层加入的,和 opSEO靠我encore是并列的。Stagefright在 Android中是以shared library的形式存在(libstagefright.so),其中的module -- AwesomePlayer可SEO靠我用来播放video/audio。 AwesomePlayer提供许多API,可以让上层的应用程序(Java/JNI)来调用。

2、    StageFright数据流封装     

2.1》由数据源DataSourSEO靠我ce生成MediaExtractor。

            通过MediaExtractor::Create(dataSource)来 实现。

Create方法通过两步来生成相应的 MediaExtractor(MediaESEO靠我xtractor.cpp):通过dataSource->sniff来探测数据类型生成相应的Extractor:

if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINSEO靠我ER_MPEG4) || !strcasecmp(mime, "audio/mp4")) {

                   return new MPEG4Extractor(source);     

} else if (!strcasecSEO靠我mp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {

                 return new MP3Extractor(source, meta);     

} else if (!strcasecmp(mSEO靠我ime, MEDIA_MIMETYPE_AUDIO_AMR_NB)

             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {        

return new AMRESEO靠我xtractor(source);

            } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {        

return new WAVExtractoSEO靠我r(source);

            } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {        

return new OggExtractor(sourcSEO靠我e);

            } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {        

return new MatroskaExtractor(soSEO靠我urce);

           } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {        

return new MPEG2TSExtractor(sSEO靠我ource);

          }      

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

if (!haveVideo &SEO靠我& !strncasecmp(mime, "video/", 6)) {

                  setVideoSource(extractor->getTrack(i));        

                 haveVideo = true;    

} else iSEO靠我f (!haveAudio && !strncasecmp(mime, "audio/", 6)) {

               setAudioSource(extractor->getTrack(i));        

haveAudio SEO靠我= true;

           }      

    2.3》得到的这两个MediaSource,只具有parser功能,没有decode功能。

还需要对这两个MediaSource做进一步的包装,获取了两个MediaSource(具有paSEO靠我rse和decode功能):

                mVideoSource = OMXCodec::Create(

                                                          mClient.interface(), mVideoTrack->getFormat(), 

false, /SEO靠我/ createEncoder

                                                          mVideoTrack,            

                                                          NULL,

                                                          flags); 

                mAudioSource = OMXCodec::Create(                 

mClient.interface(), mAudioTrSEO靠我ack->getFormat(),

                                                          false, // createEncoder                

                                                          mAudioTrack);     

当调用MediaSource.start()方法后,它的内部就会开始从数据源获取数据并解析,等SEO靠我到缓冲区满后便停止。

               在AwesomePlayer里就可以调用MediaSource的read方法读取解码后的数据。     

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

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

   3、    StageFright的Decode 经过“数据流的封装”得到的两个MediaSource,

其实SEO靠我是两个OMXCodec。AwesomePlayer和mAudioPlayer都是从 MediaSource中得到数据进行播放。AwesomePlayer得到的是最终需要渲染的原始视频数据,而mAudiSEO靠我oPlayer读取的是最终需 要播放的原始音频数据。也就是说,从OMXCodec中读到的数据已经是原始数据了。

              OMXCodec是怎么把数据源经过parse、decode两步以后转化成原始数据的。

从OMSEO靠我XCodec::Create这个构造方法开始,它的参数:IOMX  &omx指的是一个OMXNodeInstance对象的实例。

MetaData  &meta这个参数由MediaSource.getFSEO靠我ormat获取得到。这个对象的主要成员就是一个 KeyedVector<uint32_t, typed_data> mItems,里面存放了一些代表MediaSource格式信息的名值对。

bool cSEO靠我reateEncoder指明这个OMXCodec是编码还是解码。

             MediaSource &source是一个MediaExtractor。     

char *matchComponentName指定一种CSEO靠我odec用于生成这个OMXCodec。

先使用findMatchingCodecs寻找对应的Codec,找到以后为当前IOMX分配节点并注册事件监听器:omx->allocateNode(componSEO靠我entName, observer, &node)。

            最后,把IOMX封装进一个OMXCodec:

                   sp<OMXCodec> codec = new OMXCodec(                    

omx, node, quirks,SEO靠我

                                                                             createEncoder, mime, componentName,                    

                                                                             source); 

这样就得到了OMXCodec。AwesomePlayer中得到这个OMXCodec后,首先调用mVideoSourSEO靠我ce->start()进行初始化。

OMXCodec初始化主要是做两件事: 向OpenMAX发送开始命令。mOMX->sendCommand(mNode, OMX_CommandStateSet, OMSEO靠我X_StateIdle)  调用allocateBuffers()分配两个缓冲区,存放在Vector<BufferInfo> mPortBuffers[2]中,分别用于输入和输出。AwesomePlaSEO靠我yer开始播放后,通过mVideoSource->read(&mVideoBuffer, &options)读取数据。mVideoSource->read(&mVideoBuffer, &optionSEO靠我s)具体是调用OMXCodec.read来读取数据。

而OMXCodec.read主要分两步来实现数据的读取: 通过调用drainInputBuffers()对mPortBuffers[kPortIndSEO靠我exInput]进行填充,这一步完成 parse。由OpenMAX从数据源把demux后的数据读取到输入缓冲区,作为OpenMAX的输入。

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

AwesomePlayeSEO靠我r通过mVideoRenderer->render(mVideoBuffer)对经过parse和decode 处理的数据进行渲染。

一个mVideoRenderer其实就是一个包装了IOMXRenderSEO靠我er的

             AwesomeRemoteRenderer: 

                mVideoRenderer = new AwesomeRemoteRenderer(                

mClient.interface()->createRendeSEO靠我rer(

                                                                          mISurface, component,                         

                                                                          (OMX_COLOR_FORMATTYPE)format,                        

                                                                           decodedWidth, decodedHeight,                                     

mVideoWidth, mVideSEO靠我oHeight,

                                                                           rotationDegrees));  

4、    StageFright处理流程     

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

4.1》AwesomeSEO靠我Player的Video主要有以下几个成员:

              mVideoSource(解码视频)     

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

mVideoRenderer(对解码好的视频进行格式转换,andSEO靠我roid使用的格式为RGB565)

             mISurface(重绘图层)    

             mQueue(event事件队列)          

     4.2》stagefright运行时的Audio部分抽象流程如下:    

                 设置mUri的路径     

启动mQuSEO靠我eue,创建一个线程来运行 threadEntry(命名为TimedEventQueue,这个线程就是event调度器)

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

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

根据 mVideoTrack中的编码类型来选择解码SEO靠我器,avc的编码类型会选择AVCDecoder,并返回给mVideoSource,并设置mVideoSource中的mSource为mVideoTrack     插入onVideoEvent到QuSEO靠我eue中,开始解码播放

                 通过mVideoSource对象来读取解析好的视频buffer 

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

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

通过mVideoRenderer对象将解析好的视频buffer转换成RGB565格式,并发给dSEO靠我isplay模块进行图像绘制

                将onVideoEvent重新插入event调度器来循环      

     4.3》数据由源到最终解码后的流程如下:                

                           URI,FD                   

                              |             

                         DataSource                    

                              |           

                     MediaExtractor                    

                               |     

mViSEO靠我deoTrack   mAudioTrack//音视频数据流

                              |     

                     mVideoSource   mAudioSource//音视频解码器         

                             |                      |       

mVideoBuffSEO靠我er    mAudioPlayer

               说明:     

                   设置DataSource,数据源可以两种URI和FD。

               URI可以http://,rtsp://等。FD是一个本地文件描述符,能过FD,可以找到对应的文件。     

SEO靠我DataSource生成MediaExtractor。通过sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);来实现。SEO靠我

              MediaExtractor::Create(dataSource)会根据不同的数据内容创建不同的数据读取对象。     

通过调用setVideoSource由MediaExtractor分解生成音频数据流(mSEO靠我AudioTrack)和视频数据流(mVideoTrack)。     

onPrepareAsyncEvent()如果DataSource是URL的话,根据地址获取数据,并开始缓冲,直到获取到mVSEO靠我ideoTrack和 mAudioTrack。mVideoTrack和mAudioTrack通过调用initVideoDecoder()和 initAudioDecoder()来生成 mVideoSoSEO靠我urce和mAudioSource这两个音视频解码器。然后调用postBufferingEvent_l()提交事件开启缓冲。     

数据缓冲的执行函数是onBufferingUpdate()。缓冲SEO靠我区有足够的数据可以播放时,调用play_l()开始播放。play_l()中关键是 调用了postVideoEvent_l(),提交了 mVideoEvent。这个事件执行时会调用函数onVideoEvSEO靠我ent()。这个函数通过调用 mVideoSource->read(&mVideoBuffer, &options)进行视频解码。音频解码通过mAudioPlayer实现。

视频解码器解码后通过mVidSEO靠我eoSource->read读取一帧帧的数据,放到mVideoBuffer中,最后通过 mVideoRenderer->render(mVideoBuffer)把视频数据发送到显示模块。当需要暂停或停SEO靠我止时,调用 cancelPlayerEvents来提交事件用来停止解码,还可以选择是否继续缓冲数据。

 5、    代码标记Log    

依据第4》项StageFright描述的Vide视频播放流程,作Log标记SEO靠我跟踪视频DATA获取、CODEC 过程。

             从AwesomePlayer.cpp中方法着手,步骤如下:     

在修改的/mydroid/frameworks/base/media/libstagefrigh/下,SEO靠我用mm编译,并调试直到生成相应的.so文件。注:允许单模块编译时,需事先在/mydroid下允许. ./build/envsetup.sh文件。

在/mydroid/目录下make进行整体编译,生成sSEO靠我ystem.img文件。说明:先单模块编译,后再整体编译的好处是,可以缩短调试编译的时间。     

将system.img文件copy到/android-sdk-linux/platforms/aSEO靠我ndroid-8/下。注意:事先备份原有的system.img。

                带sdcard启动模拟器,在/android-sdk-linux/tools/下运行./adb shell文件,再运行logcat    

打开SEO靠我Gallery选择视频文件运行,并同步查看log。

              反馈结果如下:

I/ActivityManager( 61): Starting: Intent { act=android.intent.actioSEO靠我n.VIEW dat=content://media/external/video/media/5 typ=video/mp4 cmp=com.cooliris.media/.MovieView } SEO靠我from pid 327

                  I/RenderView(  327): OnPause RenderView com.cooliris.media.RenderView@4054a3b0

E/AwesomePSEO靠我layer(   34): beginning AwesomePlayer... by jay remarked...

E/AwesomePlayer(   34): returning AwesomeSEO靠我Event...by jay remarked...

                  E/AwesomePlayer(   34): returning AwesomeEvent...by jay remarked...

E/AwesoSEO靠我mePlayer(   34): returning AwesomeEvent...by jay remarked...

E/AwesomePlayer(   34): returning AwesomSEO靠我eEvent...by jay remarked...

                 E/AwesomePlayer(   34): ending AwesomePlayer... by jay remarked...

E/AwesoSEO靠我mePlayer(   34): setting video source now... by jay remarked...

E/AwesomePlayer(   34): setting VideoSEO靠我 Type... by jay remarked...

                 E/AwesomePlayer(   34): returning AwesomeEvent...by jay remarked...

E/AwesSEO靠我omePlayer(   34): beginning initVideoDecoder by jay remarked...

                 D/MediaPlayer(  327): getMetadata 

I/AcSEO靠我tivityManager(   61): Displayed com.cooliris.media/.MovieView: +1s761ms

E/AwesomePlayer(   34): beginSEO靠我ning AwesomeLocalRenderer init ...by jay remarked...

E/AwesomePlayer(   34): returning open(libstagefSEO靠我righthw.so) correctly by jay remarked...

E/MemoryHeapBase(   34): error opening /dev/pmem_adsp: No suSEO靠我ch file or directory

I/SoftwareRenderer(   34): Creating physical memory heap failed, reverting to reSEO靠我gular heap.

                 E/AwesomePlayer(   34): ending AwesomeLocalRenderer init close ...by jay remarked...

E/AweSEO靠我somePlayer(   34): returning AwesomeLocalRenderer...by jay remarked...

I/CacheService(  327): StartinSEO靠我g CacheService

http://blog.csdn.net/menguio/archive/2011/04/14/6323954.aspx

“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2