http://wenku.baidu.com/link?url=k3jTV9Fiy1v5VFY5iqvGvpZmsBrUsVV3eviWGfWe-zw5_CDwsMqNP7cGSRf4rqryZ1WvW-CIQ3DITQoZVkzDw82UAio3scxosB4JkFABQoG
http://wenku.baidu.com/view/79451720a5e9856a56126084.html
---------------------------------
libmedia和libmediaplayerservice分析
1) libmedia目录在frameworks/base/media/libmedia,为多媒体底层库,这里面的内容被
编译成libmedia.so在整个MediaPlayer运行中属于Client部分
1.libmedia.so处于核心位置,主要实现对上层以及下层的接口类。对上层主要提供MediaPlayer类的接口,类libmedia_jni.so通过调用MediaPlayer类,提供对JAVA的接口。 2.另外一部分则通过Binder机制和libmediaplayerservice.so进行通讯。
3.对stagefright,则定义了标准的IOMX接口。 Stagefirght通过该接口调用OpenMax插件。
2)libmeidaplayerservice目录在frameworks/base/media/libmediaplayerservice为多媒体
服务部分,文件为mediaplayerservice.h和mediaplayerservice.cpp,这部分内容被编译成libmediaplayerservice.so在整个MediaPlayer运行中处于Server部分
这部分通过继承libmedia.so的类,实现服务器的功能。对mediaplayer整个流程进行管理调度。
通过stagefrightPlayer和stagefrightRecorder,调用到stagefirght框架中的音视频播放与录制功能。
LibStageFright主要工作流程
videoDecode
1创建playerengine
// 设置数据源,以及 audio sink
MediaPlayer::SetDataSource(PATH_TO_FILE)-> MediaPlayerService::create->
MediaPlayerService::Client::setDataSource-> MediaPlayerService:: Client:: GetPlayerType-> MediaPlayerService:: Client::CreatePlayer-> StagefrightPlayer:: setAudioSink-> StagefrightPlayer:: setDataSource->
Create MediaPlayerImpl(AwesomePlayer)-> MediaPlayerImpl:: MediaPlayerImpl PlayerType:
PV_PLAYER--------------------(已经不使用,原本为创建OpenCore中的PVPlayer) SONIVOX_PLAYER----------- MidiFile()(MIDI 格式) STAGEFRIGHT_PLAYER----- StagefrightPlayer
NU_PLAYER---------------------NuPlayer(流媒体播放器)
TEST_PLAYER------------------- TestPlayerStub (only for ‘test’ and ‘eng’build) //以下为与openMax插件的初始化连接。
AwesomePlayer:mClient.connect()-> OMXClient::connect->
MediaPlayerService::getOMX()->
OMXMaster::OMXMaster: addVendorPlugin ()-> addPlugin((*createOMXPlugin ())-> *createOMXPlugin (){ new TIOMXPlugin; }
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::setDataSource_l(extractor)-> AwesomePlayer::setVideoSource()-> AwesomePlayer::setAudioSource()->
mVideoTrack=source
mAudioTrack=source
4根据mVideoTrace中编码类型来选择video_decoder(mVideoSource)
AwesomePlayer::initVideoDecoder()-> mVideoSource->start();(初始化解码器) OMXCodec::Create()->
根据编码类型去匹配codecs,将softwareCodec优先放在matchCodecs前面,优先匹配,即优先建立softWareCodec
<MediaSource>softwareCodec=InstantiateSoftwareCodec(componentName, source)-> 如果没有匹配的softWareCodec则去调用hardware中实现的omx_codec omx->allocateNode(componentName...)-> sp<OMXCodec> codec = new OMXCodec(~)-> observer->setCodec(codec)->
err = codec->configureCodec(meta, flags)-> return codec.
5.根据Codec类型选择Renderer
AwesomePlayer::start-> postVideoEvent_l();
AwesomePlayer::onVideoEvent()->
mVideoSource->read()(&mVideoBuffer, &options)-> AwesomePlayer::initRenderer_l()-> 判断Codec类型, HardWare Codec:
mVideoRenderer =new AwesomeNativeWindowRenderer(mSurface, rotationDegrees); AwesomeNativeWindowRenderer::render()(hook Called by EGL)-> HardWare Codec不需要进行ColorConvert操作,直接push到NativeWindow SoftWare Codec:
mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta)-> mVideoRenderer = new SoftwareRenderer()-> SoftwareRenderer::render()-> AwesomePlayer::onVideoEvent()-> [Check Timestamp]
mVideoRenderer->render(mVideoBuffer);
6.Audio和Video同步
Stagefright中Audio由CallBack驱动数据流,Video则在OnVideoEvent中获取Audio的timeStamp,进行同步。 Audio::fillBuffer()->
mPositionTimeMediaUs为资料中的timestamp, mPositionTimeRealUs为播放资料的实际时间。 AwesomePlayer::onVideoEvent()->
mTimeSourceDeltaUs = realTimeUs- mediaTimeUs
LibStageFright主要工作流程
videoDecode
1创建playerengine
// 设置数据源,以及 audio sink
MediaPlayer::SetDataSource(PATH_TO_FILE)-> MediaPlayerService::create->
MediaPlayerService::Client::setDataSource-> MediaPlayerService:: Client:: GetPlayerType-> MediaPlayerService:: Client::CreatePlayer-> StagefrightPlayer:: setAudioSink-> StagefrightPlayer:: setDataSource->
Create MediaPlayerImpl(AwesomePlayer)-> MediaPlayerImpl:: MediaPlayerImpl PlayerType:
PV_PLAYER--------------------(已经不使用,原本为创建OpenCore中的PVPlayer) SONIVOX_PLAYER----------- MidiFile()(MIDI 格式) STAGEFRIGHT_PLAYER----- StagefrightPlayer
NU_PLAYER---------------------NuPlayer(流媒体播放器)
TEST_PLAYER------------------- TestPlayerStub (only for ‘test’ and ‘eng’build) //以下为与openMax插件的初始化连接。
AwesomePlayer:mClient.connect()-> OMXClient::connect->
MediaPlayerService::getOMX()->
OMXMaster::OMXMaster: addVendorPlugin ()-> addPlugin((*createOMXPlugin ())-> *createOMXPlugin (){ new TIOMXPlugin; }
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::setDataSource_l(extractor)-> AwesomePlayer::setVideoSource()-> AwesomePlayer::setAudioSource()->
mVideoTrack=source
mAudioTrack=source
4根据mVideoTrace中编码类型来选择video_decoder(mVideoSource)
AwesomePlayer::initVideoDecoder()-> mVideoSource->start();(初始化解码器) OMXCodec::Create()->
根据编码类型去匹配codecs,将softwareCodec优先放在matchCodecs前面,优先匹配,即优先建立softWareCodec
<MediaSource>softwareCodec=InstantiateSoftwareCodec(componentName, source)-> 如果没有匹配的softWareCodec则去调用hardware中实现的omx_codec omx->allocateNode(componentName...)-> sp<OMXCodec> codec = new OMXCodec(~)-> observer->setCodec(codec)->
err = codec->configureCodec(meta, flags)-> return codec.
5.根据Codec类型选择Renderer
AwesomePlayer::start-> postVideoEvent_l();
AwesomePlayer::onVideoEvent()->
mVideoSource->read()(&mVideoBuffer, &options)-> AwesomePlayer::initRenderer_l()-> 判断Codec类型, HardWare Codec:
mVideoRenderer =new AwesomeNativeWindowRenderer(mSurface, rotationDegrees); AwesomeNativeWindowRenderer::render()(hook Called by EGL)-> HardWare Codec不需要进行ColorConvert操作,直接push到NativeWindow SoftWare Codec:
mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta)-> mVideoRenderer = new SoftwareRenderer()-> SoftwareRenderer::render()-> AwesomePlayer::onVideoEvent()-> [Check Timestamp]
mVideoRenderer->render(mVideoBuffer);
6.Audio和Video同步
Stagefright中Audio由CallBack驱动数据流,Video则在OnVideoEvent中获取Audio的timeStamp,进行同步。 Audio::fillBuffer()->
mPositionTimeMediaUs为资料中的timestamp, mPositionTimeRealUs为播放资料的实际时间。 AwesomePlayer::onVideoEvent()->
mTimeSourceDeltaUs = realTimeUs- mediaTimeUs
4根据mAudioTrace中编码类型来选择audio_decoder(mAudioSource)
AwesomePlayer::initAudioDecoder()-> mAudioSource->start();(初始化解码器) OMXCodec::Create()->
根据编码类型去匹配codecs,将softwareCodec优先放在matchCodecs前面,优先匹配,即优先建立softWareCodec
<MediaSource>softwareCodec=InstantiateSoftwareCodec(componentName, source)-> 如果没有匹配的softWareCodec则去调用Hardware中实现的omx_codec omx->allocateNode(componentName...)-> sp<OMXCodec> codec = new OMXCodec(~)-> observer->setCodec(codec)->
err = codec->configureCodec(meta, flags)-> return codec.
5.创建AudioPlayer,解码并开启Audio output播放audio数据
AwesomePlayer::play_l->
mAudioPlayer = new AudioPlayer(mAudioSink, this); mAudioPlayer->setSource(mAudioSource); mAudioPlayer->start
mSource->read(&mFirstBuffer);(在audioplayer启动过程中,会先读取第一段需解码后的资料。)
mAudioSink->open(..., &AudioPlayer::AudioSinkCallback, ...); AudioSinkCallback{
me->fillBuffer(buffer, size) }
开启audio output,同时AudioPlayer将callback函数设给它,之后每次callback函数被调用,AudioPlayer便会去读取Audio decoder解码后的资料。)
4根据mAudioTrace中编码类型来选择audio_decoder(mAudioSource)
AwesomePlayer::initAudioDecoder()-> mAudioSource->start();(初始化解码器) OMXCodec::Create()->
根据编码类型去匹配codecs,将softwareCodec优先放在matchCodecs前面,优先匹配,即优先建立softWareCodec
<MediaSource>softwareCodec=InstantiateSoftwareCodec(componentName, source)-> 如果没有匹配的softWareCodec则去调用Hardware中实现的omx_codec omx->allocateNode(componentName...)-> sp<OMXCodec> codec = new OMXCodec(~)-> observer->setCodec(codec)->
err = codec->configureCodec(meta, flags)-> return codec.
5.创建AudioPlayer,解码并开启Audio output播放audio数据
AwesomePlayer::play_l->
mAudioPlayer = new AudioPlayer(mAudioSink, this); mAudioPlayer->setSource(mAudioSource); mAudioPlayer->start
mSource->read(&mFirstBuffer);(在audioplayer启动过程中,会先读取第一段需解码后的资料。)
mAudioSink->open(..., &AudioPlayer::AudioSinkCallback, ...); AudioSinkCallback{
me->fillBuffer(buffer, size) }
开启audio output,同时AudioPlayer将callback函数设给它,之后每次callback函数被调用,AudioPlayer便会去读取Audio decoder解码后的资料。)
Audio & Video Recorder
1. 创建Recorder
mMediaRecorder = new MediaRecorder-> Mediaplayerservice->createMediaRecorder MediaRecorderClient.cpp:
mRecorder=new StagefrightRecorder;
2. 设置AudioSource &VideoSource&Profile
Package/VideoCamero.java:
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER)-> mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA)-> setOutputFormat(profile.fileFormat)->
setVideoFrameRate(profile.videoFrameRate)->
setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight)-> setVideoEncodingBitRate(profile.videoBitRate)-> setVideoEncoder(profile.videoCodec)->
mMediaRecorder.setMaxFileSize(maxFileSize)-> mMediaRecorder.prepare()->
以上函数最终调用的是
frameworks/base/media/libmediaplayerservice/ StagefrightRecorder.cpp中的实现。
3.根据设置的Audio &Video output format等内容,选择Writer以及Encoder。
StagefrightRecorder::start()->
startMPEG4Recording()->(作为多媒体的Recorder,支持3gpp和mp4两种多媒体文件类型的的录制,默认类型为3gpp)
startAMRRecording()->(作为单音频输出类型的Recorder,支持AMRNB和AMRWB两种)。 startAACRecording()->(未有具体实现,暂时不支持)。
startRTPRecording()->(流媒体文件Recorder,stream over a socket) startMPEG2TSRecording()->(MPEG2TS类型的Recorder). (以MPEG4Recording的初始化为例)
setupMPEG4Recording(mCaptureAuxVideo,…)->
sp<MediaWriter> writer = new MPEG4Writer(outputFd)->
MPEG4Writer::MPEG4Writer(int fd)(位于libstagefright下的实现) setupCameraSource(&cameraSource)-> StagefrightRecorder::setupVideoEncoder-> switch (mVideoEncoder)->
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263)->(根据设置的mVideoEncoder的值来设置MIMETYPE,目前支持三种Video的编码类型: MEDIA_MIMETYPE_VIDEO_H263、MEDIA_MIMETYPE_VIDEO_MPEG4、MEDIA_MIMETYPE_VIDEO_AVC)
sp<MediaSource> encoder = OMXCodec::Create(…)->(根据MIMETYPE以及videosource创建videoEncoder,创建过程和videoDecoder过程类型,只是其中VideoEncoder的值设为true,以及videosource的值设置未cameraSource,具体过程参考video/audio Decode) writer->addSource(encoder)->(将创建完成的videoEncoder加入Writer中。) setupAudioEncoder(writer)->(设置创建AudioEncoder,过程和VideoEncoder类似) sp<MediaSource> audioEncoder = createAudioSource()-> sp<MediaSource> audioEncoder =OMXCodec::Create(…)-> writer->addSource(audioEncoder)->
startTimeUs = systemTime() / 1000->(记录开始时间) setupMPEG4MetaData->
mWriter->start()(开始录制多媒体数据)
Stagefright 已经实现的codec
1)Extractor
frameworks/base/media/libstagefrightStagefright/MediaExtractor.cpp
中的OnCreate()函数,列出了所有的Extractor。
2) Codec
frameworks/base/media/libstagefright/OMXCodec.cpp
中的宏定义
#define FACTORY_CREATE(name)
#define FACTORY_CREATE_ENCODER(name)
分别定义了所有的software Decoder和software Encoder。这些Decoder/Encoder也同样可以在InstantiateSoftwareEncoder()和InstantiateSoftwareCodec()中看到。所有software codec的实现代码在libstagefright/Codecs下。
所有的Decoder/Encoder分别定义在数组
static const CodecInfo kDecoderInfo[]和static const CodecInfo kEncoderInfo[]中 其中以OMX.开头的Codec均为Hardware Codec.
添加新的Extractor
1) 在frameworks\base\media\libstagefright\MediaDefs.cpp中定义
Mime类型,以MPGE4为例
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4"; 2) 在MediaExtractor.cpp,Create函数中加入
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")) { return new MPEG4Extractor(source); 3)在DataSource.cpp, RegisterDefaultSniffers()函数中注册Extractor. RegisterSniffer(SniffMPEG4);
4)在libstagefright和libstagefright\include文件夹下加入Extractor,
MPEG4Extractor.cpp/MPEG4Extractor.h(需实现SniffMPEG4函数)
5)以上步骤需要在已经实现了分离器的前提下所要做的添加工作,若要实现新的文件分离器,则需要参考MPEG4Extractor.cpp等已经实现的内容,所有分离器都是继承Extractor.cpp的。
添加新的Decoder(software decoder)
OMXCodec.cpp中(frameworks/base/media/libstagefright/) 1) 在#define FACTORY_CREATE(name) \
加入定义FACTORY_CREATE(M4vH263Decoder)
2)在kDecoderInfo[]中定义Codec,如果是s/w Codec则命名时不以OMX开头,H/W Codec则以OMX开头。
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" }, 若是S/W Codec 则同时还需要在
InstantiateSoftwareCodec函数kFactoryInfo[]中加入定义: FACTORY_REF(M4vH263Decoder)
3) 在codecs\加入Codec Node,
M4VH263Decoder.cpp和M4VH263Decoder.h
4) 在StagefrightMediaScanner.cpp中加入包含该编解码格式的媒体文件封装格式的定义。
static bool FileHasAcceptableExtension(const char *extension) { static const char *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均为MediaSource.cpp的子类,需要实现里面定义的接口函数。
OpenMax Codecs 插件引用
StageFright实现了对OpenCore中的实例openmax的调用。最终的实现都硬件编解码。在OMXCodec.cpp中的Create函数,初始化Codec时,通过设置codec类型为OMXCodec来引用openmax插件。sp<OMXCodec> codec = new OMXCodec(
omx, node, quirks,
createEncoder, mime, componentName, source, nativeWindow);
调用codec是通过componentName来对openmax中的组件名称进行匹配,如果成功,则返回OMX_HANDLETYPE,用于OMXCodec与Component之间的通信。因此要引用openmax中的
component,只需要将已经实现的componentName注册到OMXCodec的CodecInfo kDecoderInfo[]/CodecInfo kEncoderInfo[]中即可。 如:static const CodecInfo kDecoderInfo[] = {
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" }, }
Stagefright performance issue
1. 由于stagefright,采用传统AV时间戳同步,时钟来源于Audio,同时Audio完全由
callback驱动数据流,Video的Decode,Render在同一线程工作,而两者耗时都比较大,容易造成Video显示滞后。
2. 默认最大帧率为20,而最后录制的视频帧率实际值只能达到17/18帧,影响流畅度。
Multimedia porting
1).修正进度条不能根据用户点击位置进行音乐播放问题。
Packages/apps/Music/src/com/android/music/MediaPlaybackActivity.java
问题描述:在拖动seekbar过程中,music会根据当前进度条的位置播放音乐,停止拖动操作后,进度条并未准确停止在拖动结束的位置。
问题原因:因为源代码中设有250ms的延迟以及拖动过程中的每隔250ms的seek动作; 问题解决:在拖动进度条过程中,music不会播放音乐(即不会去seek),仅当停止拖动后,程序根据此时拖动条的位置再seek musicsource,播放音乐。
2).修正Gallery不能正确显示当前video size的问题. Frameworks/base/media/libstagefright/AwesomePlayer.cpp
问题描述:播放較小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在measure view size后得到准确的结果传给surface。
3).修正默认Video codec的profiles。
Frameworks/base/media/libmedia/MediaProfiles.cpp
Frameworks/base/media/libstagefright/CameraSource.cpp
Frameworks/base/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp
问题描述:默认Recorder录制的video显示效果不佳,视频流畅度不够好。
问题原因:默认H263VideoEncoderCap与M4vVideoEncoderCap的MaxFrameRate为20,这样最后video的帧率只有17或者18fps。
问题解决:将MaxFrameRate调整为30.这样实际得到的帧可以达到27fps-28fps左右。
4).增加PtrControl.cpp
Frameworks/base/media/libstagefright/Android.mk Frameworks/base/media/libstagefright/PtrControl.cpp
Frameworks/base/media/libstagefright/include/AwesomePlayer.h Frameworks/base/media/libstagefright/include/PtrControl.h
Frameworks/base/media/libstagefright/include/PtrControlInterface.h
支持链表操作。
5).修正音视频同步问题
Frameworks/base/media/libstagefright/AwesomePlayer.cpp
Frameworks/base/media/libstagefright/include/AwesomePlayer.h
Frameworks/base/media/libstagefright/codecs/m4v_h263/dec/M4VH263Decoder.cpp Frameworks/base/media/libstagefright/include/M4vH263Decoder.h
问题描述:视频播放时,video的部分相对于audio会滞后。
问题原因:stagefright框架中,videosource的Read和Render在同一线程中,串行执行。同时decode和Render的耗时都比较长,造成video的速度根不上audio,造成画面滞后。 问题解决:另起一个thread来做Render,达到并行的效果,减少总时间。
Gallery Video playback接口调用流程
1).在Gallery中的video播放器为MoviePlayer,在MovieActivity.java的OnCreate()函数中会有初始化: mPlayer = new MoviePlayer(rootView, this, intent.getData())
intent.getData()为传入的Uri。
2).在MoviePlayer.java的构造函数中,起到播放作用的对象为mVideoView,在该构造函数中初始化:
mVideoView = (VideoView) rootView.findViewById(R.id.surface_view) 之后调用
mVideoView.setVideoURI(mUri);//将数据传入,同时创建MediaPlayer setVideoURI{ openVideo() }
openVideo(){
mMediaPlayer = new MediaPlayer(); ~ }
在该类中的播放控制,如start()、pause()、均调用的是mMediaPlayer.start();、 mMediaPlayer.pause();
之后的实际播放流程和Music相同,参见LibStageFright主要工作流程videoDecode。
Jpeg Encode流程
在java层调用Camera拍照
Package/apps/camera/src/com/android/camera/camera.java onShutterButtonClick(ShutterButton button){ doSnap()
}//按下拍照按键的响应函数 capture()
mCameraDevice.takePicture(...,new JpegPictureCallback(loc))
通过jni调用
android_hardware_Camera_takePicture(... )//android_hardware_Camera.cpp Camera::takePicture()//Camera.cpp
通过接口函数,与CameraService进行Binder通信 takePicture()//ICamera.cpp
CameraService::Client::takePicture()//CameraService.cpp
通过CameraHardwareInterface.h中定义的接口,调用Camera的HAL层。 virtual status_t takePicture() = 0//CameraHardwareInterface.h CameraHardware::takePicture()//CameraHardware.cpp createThread(beginPictureThread, this)//创建拍照线程 CameraHardware::beginPictureThread() CameraHardware::pictureThread() mCamera.GrabJpegFrame()
V4L2Camera::GrabJpegFrame//V4L2Camera.cpp V4L2Camera::saveYUYVtoJPEG
{ //进行jpeg编码压缩转换
struct jpeg_compress_struct cinfo;//标准libjpeg库调用,调用库文件位置 external/jepg下
jpeg_create_compress (&cinfo); ~ }
图像Decode流程
在java层调用//以Gallery为例
Package/app/Gallery3D/src/com/cooliris/media/UriTexture.java
createFromUri(Uri,...)//传入Uri,返回值为Bitmap
BitmapFactory.decodeStream(inputstream,...)//根据Uri创建输入流,根据inputstream,调用BitmapFactory中的解码函数 。(BitmapFactory.java)
nativeDecodeStream(is,...)//通过jni调用BitmapFactory.cpp中的函数 doDecode(env, stream, padding, options, false);
SkImageDecoder* decoder = SkImageDecoder::Factory(stream); SkImageDecoder::Factory(stream){
const DecodeReg* curr = DecodeReg::Head(); while (curr) {
codec = curr->factory()(stream); stream->rewind(); if (codec) {
return codec; }
curr = curr->next(); #ifdef SK_ENABLE_LIBPNG
codec = sk_libpng_dfactory(stream); stream->rewind(); if (codec) {
return codec; } #endif
return NULL; }
//DecodeReg为模板类SkTRegistry的一个实例,(除pngDecoder外)所有的Image Decoder均为SKImageDecdoder的子类。且都会实例化SkTRegistry。在Factory中,根据传入的stream遍历Decoder并返回合适的Decoder,若以上子类中没有,且宏SK_ENABLE_LIBPNG有定义,则去匹配PNGDecoder,若合适,则返回。(位于SkImageDecoder_Factory.cpp) //以Jpeg为例
在SkImageDecoder_libjpeg.cpp中实例化SKTRegistry.
static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
此时调用
SkImageDecoder* DFactory(SkStream* stream){ return SkNEW(SkJPEGImageDecoder); }
返回一个SKJPEGImageDecoder实例。
之后在BitmapFactory.cpp中调用mDecoder->Decode(...) 最终调用
SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
jpeg_decompress_struct cinfo; jpeg_create_decompress(&cinfo); ...
}//从函数中可以看到标准jpeg库的调用,函数位于SkImageDecoder_libjpeg.cpp中。
All Image Codecs
所有Image的Decoder均位于external/skia/src/images文件夹下 目前存在的编/解码器如下表所示: