fright

更新时间:2022-11-27 08:31:53 阅读: 评论:0


2022年11月27日发(作者:forget什么意思)

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=InstantiateSoftwareCodec(componentName,source)->

如果没有匹配的softWareCodec则去调用hardware中实现的omx_codec

omx->allocateNode(componentName...)->

spcodec=newOMXCodec(~)->

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=InstantiateSoftwareCodec(componentName,source)->

如果没有匹配的softWareCodec则去调用Hardware中实现的omx_codec

omx->allocateNode(componentName...)->

spcodec=newOMXCodec(~)->

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,…)->

spwriter=newMPEG4Writer(outputFd)->

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)

spencoder=OMXCodec::Create(…)->(根据MIMETYPE以及videosource创建

videoEncoder,创建过程和videoDecoder过程类型,只是其中VideoEncoder的值设为true,

以及videosource的值设置未cameraSource,具体过程参考video/audioDecode)

writer->addSource(encoder)->(将创建完成的videoEncoder加入Writer中。)

tupAudioEncoder(writer)->(设置创建AudioEncoder,过程和VideoEncoder类似)

spaudioEncoder=createAudioSource()->

spaudioEncoder=OMXCodec::Create(…)->

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插件。spcodec=newOMXCodec(

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.

staticSkTRegistrygDReg(DFactory);

此时调用

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小时内删除。

上一篇:blue plate special
下一篇:language learning
标签:fright
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图