LibStageFright
AwesomePlayer
AudioPlayer
MEPG4Writer
(default)
AMRWriter
OMXCodec
OMX
AwesomeRender
OMXClient
SoftWareRender
AwesomeNativeWindowRenderer
MediaExtractor
SoftWareCodec
DataSource
图1LibStageFright内部架构图
LibStageFright
图2LibStageFright与外部接口调用关系图
MediaSource
OMXMaster
MediaPlayerService
AwesomePlayer
MEPG4Writer
AMRWriter
SoftWareRender
AwesomeNativeWindowRenderer
AudioPlayer
OMXClient
OMX
StagefrightRecorder
Audio
Output
Get
OMX
SurfaceFlinger
EGL
AudioFlinger
StagefrightPlayer
OMXMaster
libstagefrighthw
Hardware
MediaPlayer
MediaPlayeService
Jni_android_media_MediaPlayer
AwesomPlayer
StagefrightPlayer
图3MediaPlayer框架
Jni_android_media_MediaRecorder
MediaRecorder
MediaPlayerService
MediaRecorderClientStagefrightRecorder
AudioSourceCameraSource
AudioRecordCamera
图4MediaRecorder框架
libmedia和libmediaplayerrvice分析
1)libmedia目录在frameworks/ba/media/libmedia,为多媒体底层库,这里面的内容被
编译成在整个MediaPlayer运行中属于Client部分
处于核心位置,主要实现对上层以及下层的接口类。对上层主要提供
MediaPlayer类的接口,类libmedia_通过调用MediaPlayer类,提供对JAVA的接口。
2.另外一部分则通过Binder机制和进行通讯。
3.对stagefright,则定义了标准的IOMX接口。Stagefirght通过该接口调用OpenMax插
件。
2)libmeidaplayerrvice目录在frameworks/ba/media/libmediaplayerrvice为多媒体
服务部分,文件为mediaplayerrvice.h和,这部分内容被编译成
在整个MediaPlayer运行中处于Server部分
这部分通过继承的类,实现服务器的功能。对mediaplayer整个流程进行管
理调度。
通过stagefrightPlayer和stagefrightRecorder,调用到stagefirght框架中的音视频播放与
录制功能。
调用Media客户端
Java调用关系
MediaPlayerInterface
JAVA程序
Libmedia_
图5MediaPlayer各个库之间结构图
Java程序
Android_media_mediaPlayer
IMediaPlayerClient
BnMediaPlayerClient
MediaPlayer
IMediaPlayer
BnMediaPlayer
IMediaPlayerClient
MediaPlayer
IMediaPlayer
Client
IMediaPlayerService
IMediaPlayerService
BnMediaPlayerServic
e
MediaPlayerBa
MediaPlayerInterface
MediaPlayerInterface
MediaPalyerService
MediaPalyerService::Client
MediaPlayerService
awesomePlayer
AwesomePlayer
Server
图6整个Media库调用关系图
LibStageFright主要工作流程
videoDecode
1创建playerengine
//设置数据源,以及audiosink
MediaPlayer::SetDataSource(PATH_TO_FILE)->
MediaPlayerService::create->
MediaPlayerService::Client::tDataSource->
MediaPlayerService::Client::GetPlayerType->
MediaPlayerService::Client::CreatePlayer->
StagefrightPlayer::tAudioSink->
StagefrightPlayer::tDataSource->
CreateMediaPlayerImpl(AwesomePlayer)->
MediaPlayerImpl::MediaPlayerImpl
PlayerType:
PV_PLAYER--------------------(已经不使用,原本为创建OpenCore中的PVPlayer)
SONIVOX_PLAYER-----------MidiFile()(MIDI格式)
STAGEFRIGHT_PLAYER-----StagefrightPlayer
NU_PLAYER---------------------NuPlayer(流媒体播放器)
TEST_PLAYER-------------------TestPlayerStub(onlyfor‘test’and‘eng’build)
//以下为与openMax插件的初始化连接。
AwesomePlayer:t()->
OMXClient::connect->
MediaPlayerService::getOMX()->
OMXMaster::OMXMaster:addVendorPlugin()->
addPlugin((*createOMXPlugin())->
*createOMXPlugin(){
newTIOMXPlugin;
}
2.解析mUri指定的内容,根据header来确定对应的Extractor
AwesomePlayer::prepare()
AwesomePlayer::prepareAsync_l()->
在该函数中启动mQueue,作为EventHandler(stagefright使用event来进行驱动)
AwesomePlayer::finishSetDataSource_l()->
MediaExtractor::create(datasource)->
3.使用extractor对文件做A/V分离(mVideoTrack/mAudioTrack)
AwesomePlayer::tDataSource_l(extractor)->
AwesomePlayer::tVideoSource()->
AwesomePlayer::tAudioSource()->
mVideoTrack=source
mAudioTrack=source
4根据mVideoTrace中编码类型来选择video_decoder(mVideoSource)
AwesomePlayer::initVideoDecoder()->
mVideoSource->start();(初始化解码器)
OMXCodec::Create()->
根据编码类型去匹配codecs,将softwareCodec优先放在matchCodecs前面,优先匹配,即优先建
立softWareCodec
如果没有匹配的softWareCodec则去调用hardware中实现的omx_codec
omx->allocateNode(componentName...)->
sp
obrver->tCodec(codec)->
err=codec->configureCodec(meta,flags)->
returncodec.
5.根据Codec类型选择Renderer
AwesomePlayer::start->
postVideoEvent_l();
AwesomePlayer::onVideoEvent()->
mVideoSource->read()(&mVideoBuffer,&options)->
AwesomePlayer::initRenderer_l()->
判断Codec类型,
HardWareCodec:
mVideoRenderer=newAwesomeNativeWindowRenderer(mSurface,rotationDegrees);
AwesomeNativeWindowRenderer::render()(hookCalledbyEGL)->
HardWareCodec不需要进行ColorConvert操作,直接push到NativeWindow
SoftWareCodec:
mVideoRenderer=newAwesomeLocalRenderer(mSurface,meta)->
mVideoRenderer=newSoftwareRenderer()->
SoftwareRenderer::render()->
AwesomePlayer::onVideoEvent()->
[CheckTimestamp]
mVideoRenderer->render(mVideoBuffer);
和Video同步
Stagefright中Audio由CallBack驱动数据流,Video则在OnVideoEvent中获取Audio的
timeStamp,进行同步。
Audio::fillBuffer()->
mPositionTimeMediaUs为资料中的timestamp,
mPositionTimeRealUs为播放资料的实际时间。
AwesomePlayer::onVideoEvent()->
mTimeSourceDeltaUs=realTimeUs-mediaTimeUs
AudioDecode
1创建playerengine
//设置数据源,以及audiosink
MediaPlayer::SetDataSource(PATH_TO_FILE)->
MediaPlayerService::create->
MediaPlayerService::Client::tDataSource->
MediaPlayerService::Client::GetPlayerType->
MediaPlayerService::Client::CreatePlayer->
StagefrightPlayer::tAudioSink->
StagefrightPlayer::tDataSource->
CreateMediaPlayerImpl(AwesomePlayer)->
MediaPlayerImpl::MediaPlayerImpl
PlayerType:
PV_PLAYER--------------------(已经不使用,原本为创建OpenCore中的PVPlayer)
SONIVOX_PLAYER-----------MidiFile()(MIDI格式)
STAGEFRIGHT_PLAYER-----StagefrightPlayer
NU_PLAYER---------------------NuPlayer(流媒体播放器)
TEST_PLAYER-------------------TestPlayerStub(onlyfor‘test’and‘eng’build)
//以下为与openMax插件的初始化连接。
AwesomePlayer:t()->
OMXClient::connect->
MediaPlayerService::getOMX()->
OMXMaster::OMXMaster:addVendorPlugin()->
addPlugin((*createOMXPlugin())->
*createOMXPlugin(){
newTIOMXPlugin;
}
2.解析mUri指定的内容,根据header来确定对应的Extractor
AwesomePlayer::prepare()
AwesomePlayer::prepareAsync_l()->
在该函数中启动mQueue,作为EventHandler(stagefright使用event来进行驱动)
AwesomePlayer::finishSetDataSource_l()->
MediaExtractor::create(datasource)->
3.使用extractor对文件做A/V分离(mVideoTrack/mAudioTrack)
AwesomePlayer::tDataSource_l(extractor)->
AwesomePlayer::tVideoSource()->
AwesomePlayer::tAudioSource()->
mVideoTrack=source
mAudioTrack=source
4根据mAudioTrace中编码类型来选择audio_decoder(mAudioSource)
AwesomePlayer::initAudioDecoder()->
mAudioSource->start();(初始化解码器)
OMXCodec::Create()->
根据编码类型去匹配codecs,将softwareCodec优先放在matchCodecs前面,优先匹配,即优先建
立softWareCodec
如果没有匹配的softWareCodec则去调用Hardware中实现的omx_codec
omx->allocateNode(componentName...)->
sp
obrver->tCodec(codec)->
err=codec->configureCodec(meta,flags)->
returncodec.
5.创建AudioPlayer,解码并开启Audiooutput播放audio数据
AwesomePlayer::play_l->
mAudioPlayer=newAudioPlayer(mAudioSink,this);
mAudioPlayer->tSource(mAudioSource);
mAudioPlayer->start
mSource->read(&mFirstBuffer);(在audioplayer启动过程中,会先读取第一段需解码后的资
料。)
mAudioSink->open(...,&AudioPlayer::AudioSinkCallback,...);
AudioSinkCallback{
me->fillBuffer(buffer,size)
}
开启audiooutput,同时AudioPlayer将callback函数设给它,之后每次callback函数被调用,
AudioPlayer便会去读取Audiodecoder解码后的资料。)
Audio&VideoRecorder
1.创建Recorder
mMediaRecorder=newMediaRecorder->
Mediaplayerrvice->createMediaRecorder
:
mRecorder=newStagefrightRecorder;
2.设置AudioSource&VideoSource&Profile
Package/:
ioSource(DER)->
eoSource()->
tOutputFormat(rmat)->
tVideoFrameRate(rameRate)->
tVideoSize(rameWidth,rameHeight)->
tVideoEncodingBitRate(itRate)->
tVideoEncoder(odec)->
FileSize(maxFileSize)->
e()->
以上函数最终调用的是
frameworks/ba/media/libmediaplayerrvice/中的实现。
3.根据设置的Audio&Videooutputformat等内容,选择Writer
以及Encoder。
StagefrightRecorder::start()->
startMPEG4Recording()->(作为多媒体的Recorder,支持3gpp和mp4两种多媒体文件类型的
的录制,默认类型为3gpp)
startAMRRecording()->(作为单音频输出类型的Recorder,支持AMRNB和AMRWB两种)。
startAACRecording()->(未有具体实现,暂时不支持)。
startRTPRecording()->(流媒体文件Recorder,streamoverasocket)
startMPEG2TSRecording()->(MPEG2TS类型的Recorder).
(以MPEG4Recording的初始化为例)
tupMPEG4Recording(mCaptureAuxVideo,…)->
sp
MPEG4Writer::MPEG4Writer(intfd)(位于libstagefright下的实现)
tupCameraSource(&cameraSource)->
StagefrightRecorder::tupVideoEncoder->
switch(mVideoEncoder)->
enc_meta->tCString(kKeyMIMEType,MEDIA_MIMETYPE_VIDEO_H263)->(根据设置的
mVideoEncoder的值来设置MIMETYPE,目前支持三种Video的编码类型:
MEDIA_MIMETYPE_VIDEO_H263、MEDIA_MIMETYPE_VIDEO_MPEG4、
MEDIA_MIMETYPE_VIDEO_AVC)
sp
videoEncoder,创建过程和videoDecoder过程类型,只是其中VideoEncoder的值设为true,
以及videosource的值设置未cameraSource,具体过程参考video/audioDecode)
writer->addSource(encoder)->(将创建完成的videoEncoder加入Writer中。)
tupAudioEncoder(writer)->(设置创建AudioEncoder,过程和VideoEncoder类似)
sp
sp
writer->addSource(audioEncoder)->
startTimeUs=systemTime()/1000->(记录开始时间)
tupMPEG4MetaData->
mWriter->start()(开始录制多媒体数据)
Stagefright已经实现的codec
1)Extractor
frameworks/ba/media/libstagefrightStagefright/
中的OnCreate()函数,列出了所有的Extractor。
表1MR2中所有Extractor
2)Codec
frameworks/ba/media/libstagefright/
中的宏定义
#defineFACTORY_CREATE(name)
#defineFACTORY_CREATE_ENCODER(name)
分别定义了所有的softwareDecoder和softwareEncoder。这些Decoder/Encoder也同样可以
在InstantiateSoftwareEncoder()和InstantiateSoftwareCodec()中看到。所有softwarecodec的
实现代码在libstagefright/Codecs下。
所有的Decoder/Encoder分别定义在数组
staticconstCodecInfokDecoderInfo[]和staticconstCodecInfokEncoderInfo[]中
其中以OMX.开头的Codec均为HardwareCodec.
AllExtractor
DRMExtractor
MPEG4Extractor
MP3Extractor
AMRExtractor
WAVExtractor
OggExtractor
MatroskaExtractor
MPEG2TSExtractor
WVMExtractor
AACExtractor
表2MR2中所定义全部Codecs
Allcodecs
Software
codecs
decoder
mp3MP3Decoder
AMR
AMRNBDecoder
AMRWBDecoder
AACAACDecoder
G711G711Decoder
mpeg4/h263M4vH263Decoder
AVCAVCDecoder
vorbisVorbisDecoder
vpxVPXDecoder
encoder
AACAACEncoder
mpeg4/h263M4vH263Encoder
AVCAVCEncoder
AMR
AMRNBEncoder
AMRWBEncoder
Hardware
codecs
decoder
AMR(WB)
mpeg4
4
4
r
r
h263
r.h263
r.h263
r
AVC
r
r
encoder
AMR
(NB)
mpeg4
4
4
r
r
r
h263
r.h263
r.h263
r
r
r
AVC
r
r
r
添加新的Extractor
1)在中定义
Mime类型,以MPGE4为例
constchar*MEDIA_MIMETYPE_CONTAINER_MPEG4="video/mpeg4";
2)在,Create函数中加入
if(!strcacmp(mime,MEDIA_MIMETYPE_CONTAINER_MPEG4)
||!strcacmp(mime,"audio/mp4")){
returnnewMPEG4Extractor(source);
3)在,RegisterDefaultSniffers()函数中注册Extractor.
RegisterSniffer(SniffMPEG4);
4)在libstagefright和libstagefrightinclude文件夹下加入Extractor,
/MPEG4Extractor.h(需实现SniffMPEG4函数)
5)以上步骤需要在已经实现了分离器的前提下所要做的添加工作,若要实现新的文件分离器,
则需要参考等已经实现的内容,所有分离器都是继承的。
添加新的Decoder(softwaredecoder)
中(frameworks/ba/media/libstagefright/)
1)在#defineFACTORY_CREATE(name)
加入定义FACTORY_CREATE(M4vH263Decoder)
2)在kDecoderInfo[]中定义Codec,如果是s/wCodec则命名时不以OMX开头,H/WCodec则以
OMX开头。
{MEDIA_MIMETYPE_VIDEO_MPEG4,"M4vH263Decoder"},
若是S/WCodec则同时还需要在
InstantiateSoftwareCodec函数kFactoryInfo[]中加入定义:
FACTORY_REF(M4vH263Decoder)
3)在codecs加入CodecNode,
和M4VH263Decoder.h
4)在中加入包含该编解码格式的媒体文件封装格式的定义。
staticboolFileHasAcceptableExtension(constchar*extension){
staticconstchar*kValidExtensions[]={
".mp3",".mp4",".m4a",".3gp",".3gpp",".3g2",".3gpp2",
".mpeg",".ogg",".mid",".smf",".imy",".wma",".aac",
".wav",".amr",".midi",".xmf",".rtttl",".rtx",".ota",
".mkv",".mka",".webm",".ts",".fl"
};
5)同理,以上步骤是在已经实现了Codec的前提下所做的源文件添加步骤,所有的软解码
Codec均为的子类,需要实现里面定义的接口函数。
OpenMaxCodecs插件引用
StageFright实现了对OpenCore中的实例openmax的调用。最终的实现都硬件编解码。
在中的Create函数,初始化Codec时,通过设置codec类型为OMXCodec来
引用openmax插件。sp
omx,node,quirks,
createEncoder,mime,componentName,
source,nativeWindow);
调用codec是通过componentName来对openmax中的组件名称进行匹配,如果成功,则返
回OMX_HANDLETYPE,用于OMXCodec与Component之间的通信。因此要引用openmax中的
component,只需要将已经实现的componentName注册到OMXCodec的CodecInfo
kDecoderInfo[]/CodecInfokEncoderInfo[]中即可。
如:staticconstCodecInfokDecoderInfo[]={
{MEDIA_MIMETYPE_AUDIO_AAC,""},
}
Stagefrightperformanceissue
1.由于stagefright,采用传统AV时间戳同步,时钟来源于Audio,同时Audio完全由
callback驱动数据流,Video的Decode,Render在同一线程工作,而两者耗时都比较大,
容易造成Video显示滞后。
2.默认最大帧率为20,而最后录制的视频帧率实际值只能达到17/18帧,影响流畅度。
Multimediaporting
1).修正进度条不能根据用户点击位置进行音乐播放问题。
Packages/apps/Music/src/com/android/music/
问题描述:在拖动ekbar过程中,music会根据当前进度条的位置播放音乐,停止拖动操
作后,进度条并未准确停止在拖动结束的位置。
问题原因:因为源代码中设有250ms的延迟以及拖动过程中的每隔250ms的ek动作;
问题解决:在拖动进度条过程中,music不会播放音乐(即不会去ek),仅当停止拖动后,
程序根据此时拖动条的位置再ekmusicsource,播放音乐。
2).修正Gallery不能正确显示当前videosize的问题.
Frameworks/ba/media/libstagefright/
问题描述:播放較小videosize的视频源(如320*240),只显示原画面的左上角内容。
问题原因:MPEG4Extractor解析trackheader,獲取kKeyDisplayWidth和kKeyDisplayHeight值,
向上提交至AwesomePlayer,并作为video的width和height值,一直上报至AP,但是这两个值
与真实videosize不符,AP以这两个值为参数,做相应的measure,然后将错误的结果上报
给surface,surface以AP的错误计算结果对codec输出的image做拉伸,导致画面显示出现
问题。
问题解决:直接將codec解析得到的videosize提交至AwesomePlayer,并上报至AP,以保
证AP在measureviewsize后得到准确的结果传给surface。
3).修正默认Videocodec的profiles。
Frameworks/ba/media/libmedia/
Frameworks/ba/media/libstagefright/
Frameworks/ba/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_
问题描述:默认Recorder录制的video显示效果不佳,视频流畅度不够好。
问题原因:默认H263VideoEncoderCap与M4vVideoEncoderCap的MaxFrameRate为20,这
样最后video的帧率只有17或者18fps。
问题解决:将MaxFrameRate调整为30.这样实际得到的帧可以达到27fps-28fps左右。
4).增加
Frameworks/ba/media/libstagefright/
Frameworks/ba/media/libstagefright/
Frameworks/ba/media/libstagefright/include/AwesomePlayer.h
Frameworks/ba/media/libstagefright/include/PtrControl.h
Frameworks/ba/media/libstagefright/include/PtrControlInterface.h
支持链表操作。
5).修正音视频同步问题
Frameworks/ba/media/libstagefright/
Frameworks/ba/media/libstagefright/include/AwesomePlayer.h
Frameworks/ba/media/libstagefright/codecs/m4v_h263/dec/
Frameworks/ba/media/libstagefright/include/M4vH263Decoder.h
问题描述:视频播放时,video的部分相对于audio会滞后。
问题原因:stagefright框架中,videosource的Read和Render在同一线程中,串行执行。同
时decode和Render的耗时都比较长,造成video的速度根不上audio,造成画面滞后。
问题解决:另起一个thread来做Render,达到并行的效果,减少总时间。
GalleryAP
MovieActivityMoviePlayerVideoView
Gallery
MediaPlayer
Media
图7Gallery中VideoPlayback主要接口调用
GalleryVideoplayback接口调用流程
1).在Gallery中的video播放器为MoviePlayer,在的OnCreate()函数中会有初始化:
mPlayer=newMoviePlayer(rootView,this,a())
a()为传入的Uri。
2).在的构造函数中,起到播放作用的对象为mVideoView,在该构造函数中
初始化:
mVideoView=(VideoView)ewById(e_view)
之后调用
eoURI(mUri);//将数据传入,同时创建MediaPlayer
tVideoURI{
openVideo()
}
openVideo(){
mMediaPlayer=newMediaPlayer();
~
}
在该类中的播放控制,如start()、pau()、均调用的是();、
();
之后的实际播放流程和Music相同,参见LibStageFright主要工作流程videoDecode。
JpegEncode流程
在java层调用Camera拍照
Package/apps/camera/src/com/android/camera/
onShutterButtonClick(ShutterButtonbutton){
doSnap()
}//按下拍照按键的响应函数
capture()
cture(...,newJpegPictureCallback(loc))
通过jni调用
android_hardware_Camera_takePicture(...)//android_hardware_
Camera::takePicture()//
通过接口函数,与CameraService进行Binder通信
takePicture()//
CameraService::Client::takePicture()//
通过CameraHardwareInterface.h中定义的接口,调用Camera的HAL层。
virtualstatus_ttakePicture()=0//CameraHardwareInterface.h
CameraHardware::takePicture()//
createThread(beginPictureThread,this)//创建拍照线程
CameraHardware::beginPictureThread()
CameraHardware::pictureThread()
egFrame()
V4L2Camera::GrabJpegFrame//
V4L2Camera::saveYUYVtoJPEG
{//进行jpeg编码压缩转换
structjpeg_compress_structcinfo;//标准libjpeg库调用,调用库文件位置
external/jepg下
jpeg_create_compress(&cinfo);
~
}
图像Decode流程
在java层调用//以Gallery为例
Package/app/Gallery3D/src/com/cooliris/media/
createFromUri(Uri,...)//传入Uri,返回值为Bitmap
Stream(inputstream,...)//根据Uri创建输入流,根据inputstream,调用
BitmapFactory中的解码函数。()
nativeDecodeStream(is,...)//通过jni调用中的函数
doDecode(env,stream,padding,options,fal);
SkImageDecoder*decoder=SkImageDecoder::Factory(stream);
SkImageDecoder::Factory(stream){
constDecodeReg*curr=DecodeReg::Head();
while(curr){
codec=curr->factory()(stream);
stream->rewind();
if(codec){
returncodec;
}
curr=curr->next();
#ifdefSK_ENABLE_LIBPNG
codec=sk_libpng_dfactory(stream);
stream->rewind();
if(codec){
returncodec;
}
#endif
returnNULL;
}
//DecodeReg为模板类SkTRegistry的一个实例,(除pngDecoder外)所有的ImageDecoder
均为SKImageDecdoder的子类。且都会实例化SkTRegistry。在Factory中,根据传入的stream
遍历Decoder并返回合适的Decoder,若以上子类中没有,且宏SK_ENABLE_LIBPNG有定义,
则去匹配PNGDecoder,若合适,则返回。(位于SkImageDecoder_)
//以Jpeg为例
在SkImageDecoder_中实例化SKTRegistry.
staticSkTRegistry
此时调用
SkImageDecoder*DFactory(SkStream*stream){
returnSkNEW(SkJPEGImageDecoder);
}
返回一个SKJPEGImageDecoder实例。
之后在中调用mDecoder->Decode(...)
最终调用
SkJPEGImageDecoder::onDecode(SkStream*stream,SkBitmap*bm,Modemode)
{
jpeg_decompress_structcinfo;
jpeg_create_decompress(&cinfo);
...
}//从函数中可以看到标准jpeg库的调用,函数位于SkImageDecoder_中。
AllImageCodecs
所有Image的Decoder均位于external/skia/src/images文件夹下
目前存在的编/解码器如下表所示:
表3allimagecodecs
ImagetypeCodecsname
WBMPSkWBMPImageDecoder
PVJPEGSkPVJPEGImageDecoder
PNGSkPNGImageDecoder(Encoder)
JPEGSkJPEGImageDecoder(Encoder)
ICOSkICOImageDecoder
GIFSkGIFImageDecoder
BMPSkBMPImageDecoder
PDFSkFPDFEMBImageDecoder
本文发布于:2022-11-27 08:31:53,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/29899.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |