`

android系统学习笔记六

阅读更多

android的多媒体系统

 

 

多媒体系统的结构和业务

多媒体系统的宏鸡观结构

应用层,java框架层,c语言层,硬件抽像层,其中输入输出由HAL,处理环节由packetViewOpenCore实现,

多媒体业备有以下几种:

musicPlayer(音频播放器)

viderPlayer(视频播放器)

Camera(照相机)

soundRecord(录音机)

videoCamera(摄像机)

Mediametadata(媒体元信息)

核心是媒体的播放和录制,分别由下层的OpenCorePVPlayerPVAuthor来实现

多媒体的java:

\frameworks\base\media\java\android\media

Jni部分的代码路径:

\frameworks\base\media\jni最终编译生成libMedia_jni.so

多媒体的本地框架:

\frameworks\base\include\media

\frameworks\base\media\libmedia

最终被子编译成libmedia.so

多媒体的服务部分

库的代码路径:\frameworks\base\media\libmediaplayerservice

最后编译生成:libmediaplayerservice.so

守护进程的代码路径:\frameworks\base\media\mediaserver

多媒体的实现部分:

 

 

 

 

多媒体的各种业务

多媒体从实现角度看,分为两部分:

输入/输出环节

中间处理环节(文件格式的处理和编解码环节)

例如一个mp3的播放

Mp3格式文件的解析,mp3编码流的解码,pcm输出的播放

 

媒体播放器涉及内容

本地媒体揪放器部分;

PVPlayer(实现的核心部分)

音频视频的编解码

音频输出环节

视频输出环节(surface或者是overlay)

Android.media.mediaplayer

Android.view.surface

Andorid.widget.videoview

 

 

数据流在android媒体播放器中的运行情况是:

上层的java应用程序将媒体的URI设置到媒体播放器中.

Java框架架----->JNI-------->本地框架------->PVPlayer,

PVPlayer解析后,将媒体分为音频流和视频流

经过编码器的处理和同步(AVSync),转换成原始数据(音频是PCM,视频一般是YUV或者是RGB)

 

照相机的统结构

录音机的系统结构

本地媒体框架中的媒体记录器部分

PVPlayer

音频编码模块

音频输入环节

android.media.mediaRecorder

soundRecorder

摄像机的系统结构

本地框加的媒体记录器部分

PVAuthor

音频/视频编码模块

音频输入环节

Camera的本地接口

视频输出环节

android.media.MediaRecorder

Android.view.surface

Andoird.widget.videoview

Music包和camera

 

 

 

多媒体系统的各个层次

libMedia的框架部分

 

 

媒体播放器

头文件的目录

\frameworks\base\include\media

主要的头文件有:

Mediaplayer.h媒体播放器本地部分的上层接口

提供了对上层的调用,通过JNI将接口给java调用,其实都是调用下层的mediaplayer

继承自Bnmediaplayerclient.

部分代码如下:

classMediaPlayer:publicBnMediaPlayerClient,

publicvirtualIMediaDeathNotifier

{

public:

MediaPlayer();

~MediaPlayer();

voiddied();

voiddisconnect();

 

status_tsetDataSource(

constchar*url,//设置数据源url

constKeyedVector<String8,String8>*headers);

 

status_tsetDataSource(intfd,int64_toffset,int64_tlength);//设置数据源文件

status_tsetVideoSurface(constsp<Surface>&surface);//设视频输出界面

status_tsetListener(constsp<MediaPlayerListener>&listener);//设置临听

status_tprepare();//准备播放

status_tprepareAsync();//异部准备播放

status_tstart();//开始

status_tstop();//停止

status_tpause();//暂停

boolisPlaying();//是否正在播放

status_tgetVideoWidth(int*w);//获取视频播放的宽

status_tgetVideoHeight(int*h);//获取视频播放的高

status_tseekTo(intmsec);//跳转到指定位置

status_tgetCurrentPosition(int*msec);//取得当前的播放位置

status_tgetDuration(int*msec);//播放的持续时间(总时长)

status_treset();//复位

status_tsetAudioStreamType(inttype);//设置音频流的格式

status_tsetLooping(intloop);//设置循环

boolisLooping();//是否循环

status_tsetVolume(floatleftVolume,floatrightVolume);//设置音量

voidnotify(intmsg,intext1,intext2);//通知函数

staticsp<IMemory>decode(constchar*url,uint32_t*pSampleRate,int*pNumChannels,int*pFormat);

staticsp<IMemory>decode(intfd,int64_toffset,int64_tlength,uint32_t*pSampleRate,int*pNumChannels,int*pFormat);

status_tinvoke(constParcel&request,Parcel*reply);

status_tsetMetadataFilter(constParcel&filter);

status_tgetMetadata(boolupdate_only,boolapply_filter,Parcel*metadata);

status_tsuspend();

status_tresume();

status_tsetAudioSessionId(intsessionId);

intgetAudioSessionId();

status_tsetAuxEffectSendLevel(floatlevel);

status_tattachAuxEffect(inteffectId);

private:

voidclear_l();

status_tseekTo_l(intmsec);

status_tprepareAsync_l();

status_tgetDuration_l(int*msec);

status_tsetDataSource(constsp<IMediaPlayer>&player);

 

sp<IMediaPlayer>mPlayer;

thread_id_tmLockThreadId;

MutexmLock;

MutexmNotifyLock;

ConditionmSignal;

sp<MediaPlayerListener>mListener;

void*mCookie;

media_player_statesmCurrentState;

intmDuration;

intmCurrentPosition;

intmSeekPosition;

boolmPrepareSync;

status_tmPrepareStatus;

intmStreamType;

boolmLoop;

floatmLeftVolume;

floatmRightVolume;

intmVideoWidth;

intmVideoHeight;

intmAudioSessionId;

floatmSendLevel;

};

 

 

IMeciaplayer.h媒体播和器服务部分的接口(和上层的mediaplay中的接口方法类似)

BnMedaplayer继承,提供Binder通信本地实现基础

部分代码如下:

//继承mediaplayerBase,通过autoFlinger输出

classMediaPlayerInterface:publicMediaPlayerBase{

public:

virtual~MediaPlayerInterface(){}

virtualboolhardwareOutput(){returnfalse;}

virtualvoidsetAudioSink(constsp<AudioSink>&audioSink){mAudioSink=audioSink;}

protected:

sp<AudioSink>mAudioSink;//音频轮输出设备的抽像接口

};

 

//Implementthisclassformediaplayersthatoutputdirectotohardware

//直接从硬功夫件进行音频输出

classMediaPlayerHWInterface:publicMediaPlayerBase//继承mediaplayerBaser

{

public:

virtual~MediaPlayerHWInterface(){}

virtualboolhardwareOutput(){returntrue;}

virtualstatus_tsetVolume(floatleftVolume,floatrightVolume)=0;

virtualstatus_tsetAudioStreamType(intstreamType)=0;

};

mediaplayerInterface.h

PVPlayer.h是媒体播放器实现层的接口(opencore媒体播放器实现的头文件)

继承自MediaPlayerInterface

部分代码如下:

classPVPlayer:publicMediaPlayerInterface

{

public:

PVPlayer();

virtual~PVPlayer();

 

virtualstatus_tinitCheck();

 

virtualstatus_tsetDataSource(

constchar*url,constKeyedVector<String8,String8>*headers);

 

virtualstatus_tsetDataSource(intfd,int64_toffset,int64_tlength);

virtualstatus_tsetVideoSurface(constsp<ISurface>&surface);

virtualstatus_tprepare();

virtualstatus_tprepareAsync();

virtualstatus_tstart();

virtualstatus_tstop();

virtualstatus_tpause();

virtualboolisPlaying();

virtualstatus_tseekTo(intmsec);

virtualstatus_tgetCurrentPosition(int*msec);

virtualstatus_tgetDuration(int*msec);

virtualstatus_treset();

virtualstatus_tsetLooping(intloop);

virtualplayer_typeplayerType(){returnPV_PLAYER;}

virtualstatus_tinvoke(constParcel&request,Parcel*reply);

virtualstatus_tgetMetadata(

constSortedVector<media::Metadata::Type>&ids,

Parcel*records);

 

//makeavailabletoPlayerDriver

voidsendEvent(intmsg,intext1=0,intext2=0){MediaPlayerBase::sendEvent(msg,ext1,ext2);}

 

private:

staticvoiddo_nothing(status_ts,void*cookie,boolcancelled){}

staticvoidrun_init(status_ts,void*cookie,boolcancelled);

staticvoidrun_set_video_surface(status_ts,void*cookie,boolcancelled);

staticvoidrun_set_audio_output(status_ts,void*cookie,boolcancelled);

staticvoidrun_prepare(status_ts,void*cookie,boolcancelled);

staticvoidcheck_for_live_streaming(status_ts,void*cookie,boolcancelled);

 

PlayerDriver*mPlayerDriver;

char*mDataSourcePath;

boolmIsDataSourceSet;

sp<ISurface>mSurface;

intmSharedFd;

status_tmInit;

intmDuration;

 

#ifdefMAX_OPENCORE_INSTANCES

staticvolatileint32_tsNumInstances;

#endif

};

ImeciaplayerClient.h多媒体的客户端(定义了媒体的客户端)主要用作通知函数

Mediaplayer继承ImediaplayerClient所以可以得到下层传弟的信息

部分代码如下:

classIMediaPlayerClient:publicIInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayerClient);

 

virtualvoidnotify(intmsg,intext1,intext2)=0;//通知的信息是个消息

};

Imediaplayerservice.h多媒体的服务(定义了多媒体服务的接口,由下层服务去实现)

部分代码如下:

 

classIMediaPlayerService:publicIInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayerService);

/

virtualsp<IMediaRecorder>createMediaRecorder(pid_tpid)=0;

virtualsp<IMediaMetadataRetriever>createMetadataRetriever(pid_tpid)=0;

/创建IMediaPlayer

virtualsp<IMediaPlayer>create(pid_tpid,constsp<IMediaPlayerClient>&client,

constchar*url,constKeyedVector<String8,String8>*headers=NULL,

intaudioSessionId=0)=0;

virtualsp<IMediaPlayer>create(pid_tpid,constsp<IMediaPlayerClient>&client,

intfd,int64_toffset,int64_tlength,intaudioSessionId)=0;

//用于直接解码

virtualsp<IMemory>decode(constchar*url,uint32_t*pSampleRate,int*pNumChannels,int*pFormat)=0;

virtualsp<IMemory>decode(intfd,int64_toffset,int64_tlength,uint32_t*pSampleRate,int*pNumChannels,int*pFormat)=0;

virtualsp<IOMX>getOMX()=0;

};

 

//----------------------------------------------------------------------------

 

classBnMediaPlayerService:publicBnInterface<IMediaPlayerService>

{

public:

virtualstatus_tonTransact(uint32_tcode,

constParcel&data,

Parcel*reply,

uint32_tflags=0);

};

源文件的目录

\frameworks\base\media\libmedia

 

 

 

媒体记录器

 

头文件和实现文件的代码路径:

\frameworks\base\include\media

主要的头文件有:

MediaRecorder.h媒体记录器的上层拉接口,每个函数都调用IMediaRecord来实现,他也继承了BnMediaPlayerClient用于接收下层返回的通知

部分代码如下:

classMediaRecorder:publicBnMediaRecorderClient,

publicvirtualIMediaDeathNotifier

{

public:

MediaRecorder();

~MediaRecorder();

 

voiddied();

status_tinitCheck();

status_tsetCamera(constsp<ICamera>&camera);//设置camera作为输入设备

status_tsetPreviewSurface(constsp<Surface>&surface);//设置视频预览界面

status_tsetVideoSource(intvs);//视频数据源(枚举值)

status_tsetAudioSource(intas);//音频数据源(同上)

status_tsetOutputFormat(intof);//设置输出格式

status_tsetVideoEncoder(intve);//设置视频编码格式

status_tsetAudioEncoder(intae);//设置音频编码格式

status_tsetOutputFile(constchar*path);//设置输出文件路径

status_tsetOutputFile(intfd,int64_toffset,int64_tlength);//设置输出文件的文件描述符

status_tsetVideoSize(intwidth,intheight);//设置视频尺寸

status_tsetVideoFrameRate(intframes_per_second);//设置视频帧率

status_tsetParameters(constString8&params);//设置其他参数

status_tsetListener(constsp<MediaRecorderListener>&listener);//设置临听

status_tprepare();//准备录制

status_tgetMaxAmplitude(int*max);//获得最大增益

status_tstart();//开始

status_tstop();//停止

status_treset();//复位

status_tinit();//初始化记录器

status_tclose();//关闭记录器

status_trelease();//释放资源

voidnotify(intmsg,intext1,intext2);

 

private:

voiddoCleanUp();

status_tdoReset();

 

sp<IMediaRecorder>mMediaRecorder;

sp<MediaRecorderListener>mListener;

media_recorder_statesmCurrentState;

boolmIsAudioSourceSet;

boolmIsVideoSourceSet;

boolmIsAudioEncoderSet;

boolmIsVideoEncoderSet;

boolmIsOutputFileSet;

MutexmLock;

MutexmNotifyLock;

};

 

};

IMediaRecorder.h媒体记录器的部分实现接口

部分代码如下:

classIMediaRecorder:publicIInterface

{

public:

DECLARE_META_INTERFACE(MediaRecorder);

 

virtual status_t setCamera(constsp<ICamera>&camera)=0;

virtual status_t setPreviewSurface(constsp<ISurface>&surface)=0;

virtual status_t setVideoSource(intvs)=0;

virtual status_t setAudioSource(intas)=0;

virtual status_t setOutputFormat(intof)=0;

virtual status_t setVideoEncoder(intve)=0;

virtual status_t setAudioEncoder(intae)=0;

virtual status_t setOutputFile(constchar*path)=0;

virtual status_t setOutputFile(intfd,int64_toffset,int64_tlength)=0;

virtual status_t setVideoSize(intwidth,intheight)=0;

virtual status_t setVideoFrameRate(intframes_per_second)=0;

virtualstatus_tsetParameters(constString8&params)=0;

virtualstatus_tsetListener(constsp<IMediaRecorderClient>&listener)=0;

virtual status_t prepare()=0;

virtual status_t getMaxAmplitude(int*max)=0;

virtual status_t start()=0;

virtual status_t stop()=0;

virtual status_t reset()=0;

virtualstatus_tinit()=0;

virtualstatus_tclose()=0;

virtual status_t release()=0;

};

 

//----------------------------------------------------------------------------

 

classBnMediaRecorder:publicBnInterface<IMediaRecorder>

{

public:

virtualstatus_tonTransact(uint32_tcode,

constParcel&data,

Parcel*reply,

uint32_tflags=0);

};

 

};

PVMediaRecorder.h下层接口,openCore实现

 

媒体元信息和扫描器

主要的头文件有:

MediaMetadataRetriever.h

部分代码如下;

classMediaMetadataRetriever:publicRefBase

{

public:

MediaMetadataRetriever();

~MediaMetadataRetriever();

voiddisconnect();

status_tsetDataSource(constchar*dataSourceUrl);//设置数据源(url)

status_tsetDataSource(intfd,int64_toffset,int64_tlength);//设置数据源(文件描述符)

sp<IMemory>getFrameAtTime(int64_ttimeUs,intoption);//捕获帧

sp<IMemory>extractAlbumArt();//抽取

constchar*extractMetadata(intkeyCode);//抽取元信息

 

IMediaMetadataRetriever

 

MediaMetadataRetrieverInterface.h实现的接口文件

PVMetadataRetriever.h下层实现的接口

 

 

classMediaMetadataRetrieverBase:publicRefBase{}

classMediaMetadataRetrieverInterface:publicMediaMetadataRetrieverBase{}

classPVMetadataRetriever:publicMediaMetadataRetrieverInterface{}

 

媒体扫描器的头文件

MediaScanner.hscanner的接口扫描一个文件或者一个文件夹取得文件格式,会调用MediaScannerClient

部分代码如下:

structMediaScanner{

MediaScanner();

virtual~MediaScanner();

 

virtualstatus_tprocessFile(

constchar*path,constchar*mimeType,

MediaScannerClient&client)=0;

 

typedefbool(*ExceptionCheck)(void*env);

virtualstatus_tprocessDirectory(

constchar*path,constchar*extensions,

MediaScannerClient&client,

ExceptionCheckexceptionCheck,void*exceptionEnv);

 

voidsetLocale(constchar*locale);

 

//extractsalbumartasablockofdata

virtualchar*extractAlbumArt(intfd)=0;

}

 

 

classMediaScannerClient

{

public:

MediaScannerClient();

virtual~MediaScannerClient();

voidsetLocale(constchar*locale);

voidbeginFile();

booladdStringTag(constchar*name,constchar*value);

voidendFile();

 

virtualboolscanFile(constchar*path,longlonglastModified,longlongfileSize)=0;

virtualboolhandleStringTag(constchar*name,constchar*value)=0;

virtualboolsetMimeType(constchar*mimeType)=0;

virtualbooladdNoMediaFolder(constchar*path)=0;

}

 

 

多媒体服务

他包含媒体揪放器,媒体记录器,媒体元信息管理他和他的调用者是在两个不同的进程中,使用binder进行IPC通信

多媒体服务的守护进程main_mediaserver.cpp

代码中和路径:\frameworks\base\media\mediaserver

部分代码如下:

intmain(intargc,char**argv)

{

sp<ProcessState>proc(ProcessState::self());

sp<IServiceManager>sm=defaultServiceManager();

LOGI("ServiceManager:%p",sm.get());

AudioFlinger::instantiate();//用于声音的混合

MediaPlayerService::instantiate();//用于音频播放

CameraService::instantiate();//摄像头相关服务

AudioPolicyService::instantiate();

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}

audioFlinger是通过defaultServiceMannager获取IServiceMamager接口通过addService方法注册为

Media.audido_flinger

Mediaserver作为一个守护进程,在androidinit.rc中具有如下定义

Servicemedia/system/bin/mediaserver

Usermedia

Groupsystemaudiocameragraphicsinetnet_btnet_bt_admin

由于没有定义oneshot,所以这个进程一直存在,如果被杀死,init会将其重新启动

 

 

多媒体服务的实现

多媒体服务的路径:\frameworks\base\media\libmediaplayerservice

 

mediaPlayerService.h头文件中定义了,IMediaplayer的实现

classMediaPlayerService:publicBnMediaPlayerService{

classAudioOutput:publicMediaPlayerBase::AudioSink{}

classAudioCache:publicMediaPlayerBase::AudioSink{}

classClient:publicBnMediaPlayer{}

}

IMeciaRecorder的实现

classMediaRecorderClient:publicBnMediaRecorder{}

IMediadataRetriever的实现

classMetadataRetrieverClient:publicBnMediaMetadataRetriever{}

 

MediaPlayerService.cpp中定义了取得媒体记录器(IMediaRecorder>)的接口

sp<IMediaRecorder>MediaPlayerService::createMediaRecorder(pid_tpid)

{

sp<MediaRecorderClient>recorder=newMediaRecorderClient(this,pid);

wp<MediaRecorderClient>w=recorder;

Mutex::Autolocklock(mLock);

mMediaRecorderClients.add(w);

LOGV("Createnewmediarecorderclientfrompid%d",pid);

returnrecorder;

}

取得媒体播放器的媒体元信息

sp<IMediaMetadataRetriever>MediaPlayerService::createMetadataRetriever(pid_tpid)

{

sp<MetadataRetrieverClient>retriever=newMetadataRetrieverClient(pid);

LOGV("Createnewmediaretrieverfrompid%d",pid);

returnretriever;

}

 

MediaPlayService类中创建媒体播放器的过程:

 

1

sp<IMediaPlayer>MediaPlayerService::create(pid_tpid,constsp<IMediaPlayerClient>&client,

intfd,int64_toffset,int64_tlength,intaudioSessionId)

{

int32_tconnId=android_atomic_inc(&mNextConnId);

//创建mediaPlayerService::Client

sp<Client>c=newClient(this,pid,connId,client,audioSessionId);

LOGV("Createnewclient(%d)frompid%d,fd=%d,offset=%lld,length=%lld,audioSessionId=%d",

connId,pid,fd,offset,length,audioSessionId);

//设置源的url

if(NO_ERROR!=c->setDataSource(fd,offset,length)){//根据setDataSource()时根据输入的类型创建不同的mediaPlayBase,接着调用下面的createPlayer方法创建不同的player

c.clear();

}else{

wp<Client>w=c;

Mutex::Autolocklock(mLock);

mClients.add(w);

}

::close(fd);

returnc;

}

 

 

 

staticsp<MediaPlayerBase>createPlayer(player_typeplayerType,void*cookie,

notify_callback_fnotifyFunc)

{

sp<MediaPlayerBase>p;

switch(playerType){//根据playerType的类型建立不同的播放器

#ifndefNO_OPENCORE

casePV_PLAYER:

LOGV("createPVPlayer");

p=newPVPlayer();

break;

#endif

caseSONIVOX_PLAYER:

LOGV("createMidiFile");

p=newMidiFile();

break;

caseSTAGEFRIGHT_PLAYER:

LOGV("createStagefrightPlayer");

p=newStagefrightPlayer;

break;

caseTEST_PLAYER:

LOGV("CreateTestPlayerstub");

p=newTestPlayerStub();

break;

}

if(p!=NULL){

if(p->initCheck()==NO_ERROR){

p->setNotifyCallback(cookie,notifyFunc);

}else{

p.clear();

}

}

if(p==NULL){

LOGE("Failedtocreateplayerobject");

}

returnp;

}

 

PVPlayerMidiFileVorbisPlayer三个都继承MediaPlayInterface得到的,MediaPlayerInterface是继承MediaPlayerBase得到,三者具有相同的接口类型,三者在建立之后通过MediaPlayerBase接口来控制他们

媒体播放器的实现结构如下图所示

 

 

 

MediaPlayerService::AudioOutput实现audio输出环节的封装,由Audio系统来实现,主要是调用AudioTrakc的接口

status_tMediaPlayerService::AudioOutput::open(

uint32_tsampleRate,intchannelCount,intformat,intbufferCount,

AudioCallbackcb,void*cookie)

{

mCallback=cb;

mCallbackCookie=cookie;

 

//Checkargument"bufferCount"againstthemininumbuffercount

if(bufferCount<mMinBufferCount){

LOGD("bufferCount(%d)istoosmallandincreasedto%d",bufferCount,mMinBufferCount);

bufferCount=mMinBufferCount;

 

}

LOGV("open(%u,%d,%d,%d,%d)",sampleRate,channelCount,format,bufferCount,mSessionId);

if(mTrack)close();

intafSampleRate;

intafFrameCount;

intframeCount;

 

if(AudioSystem::getOutputFrameCount(&afFrameCount,mStreamType)!=NO_ERROR){

returnNO_INIT;

}

if(AudioSystem::getOutputSamplingRate(&afSampleRate,mStreamType)!=NO_ERROR){

returnNO_INIT;

}

//获得帧数和采样率

frameCount=(sampleRate*afFrameCount*bufferCount)/afSampleRate;

 

AudioTrack*t;

if(mCallback!=NULL){

t=newAudioTrack(

mStreamType,

sampleRate,

format,

(channelCount==2)?AudioSystem::CHANNEL_OUT_STEREO:AudioSystem::CHANNEL_OUT_MONO,

frameCount,

0/*flags*/,

CallbackWrapper,

this,

0,

mSessionId);

}else{

t=newAudioTrack(

mStreamType,

sampleRate,

format,

(channelCount==2)?AudioSystem::CHANNEL_OUT_STEREO:AudioSystem::CHANNEL_OUT_MONO,

frameCount,

0,

NULL,

NULL,

0,

mSessionId);

}

 

if((t==0)||(t->initCheck()!=NO_ERROR)){

LOGE("Unabletocreateaudiotrack");

deletet;

returnNO_INIT;

}

 

LOGV("setVolume");

t->setVolume(mLeftVolume,mRightVolume);

 

mMsecsPerFrame=1.e3/(float)sampleRate;

mLatency=t->latency();

mTrack=t;

 

t->setAuxEffectSendLevel(mSendLevel);

returnt->attachAuxEffect(mAuxEffectId);;

}

 

音频输出的接口

ssize_tMediaPlayerService::AudioOutput::write(constvoid*buffer,size_tsize)

{

LOG_FATAL_IF(mCallback!=NULL,"Don'tcallwriteifsupplyingacallback.");

 

//LOGV("write(%p,%u)",buffer,size);

if(mTrack){

ssize_tret=mTrack->write(buffer,size);

returnret;

}

returnNO_INIT;

}

 

 

 

多媒体的JNI部分

本地调用部分的代码路径为:

Frameworks/base/media/jni

主要文件有:

 

Android23后改用stagefright

\frameworks\base\media\libstagefright

两者的处理机制不同

openCore的处理流程如下: 

 

 

Stagefright部分的处理流程如下:

从上面可以看出

1OpenCoreparserdec是分离的,各行其职,stagefright则是邦在一起作为一个独立的原子操作

2stagefright通过callbackvideoevent来驱动数据输出,openCore是通过sink-node节点控制输出

3Opencoreparser/dec/sink是并行处理的stagefright是串行处理android_media_MediaPlayer.cpp//媒体播放器

android_media_MediaRecorder.cpp//媒体记录器

android_media_MediaMetadataRetriever.cpp//媒体元信息工具

android_media_MediaScanner.cpp//媒体扫描器

这部分内容最终编译成libmedia_jni.so,

设置surface作为视频输出和取景器预览的接口没有对java提供,而是在preapare()函数中直接从环境中得到并设置了。

staticvoid

android_media_MediaPlayer_prepare(JNIEnv*env,jobjectthiz)

{

sp<MediaPlayer>mp=getMediaPlayer(env,thiz);

if(mp==NULL){

jniThrowException(env,"java/lang/IllegalStateException",NULL);

return;

}

setVideoSurface(mp,env,thiz);//调用mediaplayer函数作视频输出设置

process_media_player_call(env,thiz,mp->prepare(),"java/io/IOException","Preparefailed.");

}

 

 

 

staticvoid

android_media_MediaRecorder_prepare(JNIEnv*env,jobjectthiz)

{

LOGV("prepare");

sp<MediaRecorder>mr=getMediaRecorder(env,thiz);

 

jobjectsurface=env->GetObjectField(thiz,fields.surface);

if(surface!=NULL){

constsp<Surface>native_surface=get_surface(env,surface);

 

//Theapplicationmaymisbehaveand

//thepreviewsurfacebecomesunavailable

if(native_surface.get()==0){

LOGE("Applicationlostthesurface");

jniThrowException(env,"java/io/IOException","invalidpreviewsurface");

return;

}

 

LOGI("prepare:surface=%p(identity=%d)",native_surface.get(),native_surface->getIdentity());

//调用mediaplayer函数作视频输出设置

if(process_media_recorder_call(env,mr->setPreviewSurface(native_surface),"java/lang/RuntimeException","setPreviewSurfacefailed.")){

return;

}

}

process_media_recorder_call(env,mr->prepare(),"java/io/IOException","preparefailed.");

}

 

多媒体部分的java部分代码

Java框架类的路径为:

frameworks\base\media\java\android\media

 

主要文介绍;:

MediaFile.java文件提供了媒体文件的文件类型,

MediaPlayerMediaRecorderMediaMetadataRecorder等类基本上和JNI层的内容一一对应

MediaScanner在这里实现有客户端内容比较多

 

其中MedisPlayer中对视频输出和取景器预览的接口

publicvoidsetDisplay(SurfaceHoldersh){

mSurfaceHolder=sh;

if(sh!=null){

mSurface=sh.getSurface();

}else{

mSurface=null;

}

_setVideoSurface();

updateSurfaceScreenOn();

}

MediaRecorder中对视频输出和取景器预览的接口

 

publicvoidsetPreviewDisplay(Surfacesv){

mSurface=sv;

}

 

Java框架层没有直接使用传递参数的方式,而是使用了保存在环境中再传递的方式

 

Android.widgetVideoView.是一个UI元素

代码路径为:frameworks\base\core\java\android\widget

使用该类,可以不用再调用MediaPlayer,节省了一些中间环节

publicclassVideoViewextendsSurfaceViewimplementsMediaPlayerControl{

publicvoidsetVideoPath(Stringpath){}//设置源文件路径

publicvoidsetVideoURI(Uriuri){}//设置视频的URL

publicvoidstart(){}//开始播放

publicvoidstopPlayback(){}//停止播放

publicvoidpause(){}//暂停播放

publicvoidseekTo(intmsec){}//更改播放位置

 

 

多媒体实现的核心部分OpenCore

多媒体系统框架PacketVideo的开源版本OpenCoreandroid多媒体本地实现在的核心

它为android提供的引警如下

 PVPlayer媒体播放器的功能  音频和视频的回放功能
PVAuthor媒体记录器功能音频和视频的录制

 

OpenCore的层次结构

自上而下分为

OSCL(operationsystemcompatibilitylibrary,操作系统兼容库)类似一个基础的c++

PVMF (packetVideoMultimediaFramework多媒体框架)packetVideo的基本框架,例如nodea基类,输入输出的抽象类

文件格式处理,文件解析(parser)和组成(composer)两个部分,

各种Node,是packetVideo中的基本功能模块,

播放器(PlayerEngine)播放器引擎

记录器(authorEngine)媒体记录器引擎

 

注:在openCore2.X之后,开始提供了2-wayengine两路引擎用于构建视频电话

在使用OpenCoreSDK时,需要在应用层实现一个适配器

PVPlaytrPVAuthor就是基于OpenCore的下层功能和接口构建军的应用层的库

 

android系统中OpenCore的代码路径为:externam/opencore/

Stagefright整体框图:

 

Androidfroyo版本对多媒体引擎作了变动.新添加了stagefright框架,但并没有完全抛弃opencore

主要是作了一个omx,仅是对opencoreomx-component部分作了引用,,它在android系统中作为

共享库(libstagefright.so)存在,其中的module--awesomePlayer用来播放video/audio

 

Awesomeplayer提供的API可以供上次的应用(java/JNI)来调用

StageFrigtht数据流封装

1MediaExtractor.cpp根据数据源DataSource生成MediaExtractor

具体实现是通过调用(代码路径为;frameworks\base\media\libstagefright)

sp<MediaExtractor>MediaExtractor::Create(constsp<DataSource>&source,constchar*mime){}

通过DateSourcesource->sniff(&tmp,&confidence,&meta)来探测数据类型

2AwesomePlayer.cpp把音视频轨道分离,生成mVideoTrackMediaSource

部分代码如下:

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

setVideoSource(extractor->getTrack(i));

haveVideo=true;

}elseif(!haveAudio&&!strncasecmp(mime,"audio/",6)){

setAudioSource(extractor->getTrack(i));

haveAudio=true;

 

if(!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_VORBIS)){

//Onlydothisforvorbisaudio,noneoftheotheraudio

//formatsevensupportthisringtonespecifichackand

//retrievingthemetadataonsomeextractorsmayturnout

//tobeveryexpensive.

sp<MetaData>fileMeta=extractor->getMetaData();

int32_tloop;

if(fileMeta!=NULL

&&fileMeta->findInt32(kKeyAutoLoop,&loop)&&loop!=0){

mFlags|=AUTO_LOOPING;

}

}

}

3得到的两个mediaSource只具有parser功能,,没有decode功能,还需要对两个MediaSource做进一步的包装

mAudioSource=OMXCodec::Create(

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

false,//createEncoder

mAudioTrack);

 

mVideoSource=OMXCodec::Create(

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

false,//createEncoder

mVideoTrack,

NULL,flags);

当调用mediaSource.start()方法后,就会开始从数据源获取数据并解析,等到缓冲区满后就停止

awesomePlayer就可以调用mediaSourceread方法读取解码后的数据

对于mVideoSource来说,读取数据mVideoource->read(&mVideoBuffer,&options)交给显示模块进行渲染,mVideoRenderer->render(mVideoBufer)

 

4stageFrightdecode

经过流的封装得到两个MediaSource,其实是两个OMXCodec,

AwesomePlayermAudioPlayer都是从mediaSource中得到数据进行播放,最终需要渲染的原始视频数据,也就是说OMXCodec中得到的是原始数据

部分代码如下:

sp<MediaSource>OMXCodec::Create(

constsp<IOMX>&omx,//OMXNodeInstance对象的实例

constsp<MetaData>&meta,boolcreateEncoder,//MediaSource.getFormat获取得到,

//他的对象成员是一个keyedVector<uint32_t,typed_data>

//里面存放的是代表mediaSource格式信息的键值对

constsp<MediaSource>&source,//mediaExtractor

constchar*matchComponentName,//指定一种codec用于生成omxcodec

uint32_tflags){

//首先调用findMatchingCodecs()方法,找到对应的Codec

findMatchingCodecs(

mime,createEncoder,matchComponentName,flags,&matchingCodecs);

//找到以后为当前的IOMX分配并注册监听事件,

status_terr=omx->allocateNode(componentName,observer,&node);

//这样就得到了OMXCodec

sp<OMXCodec>codec=newOMXCodec(

omx,node,quirks,

createEncoder,mime,componentName,

source);

}

 

AwesomePlayer中得到这个OMXCodec后,首先调用mVideoSource->start()进行初始化,主要有两件事

1openMAX发送命令

err=mOMX->sendCommand(mNode,OMX_CommandStateSet,OMX_StateIdle);

2err=allocateBuffers();分配两个缓冲区,freeBuffersOnPort()分别用于输入和输出

 

awesomePlayer开始播放以后,通过mVideoSource->read(&mVideoBuffer,&options)读取数据

OMXCodec.read分两部来实现数据读取,

1通过调用draininputBuffers()mPortBuffers[kPortindexOutput]进行填充,这一步完成parse

OpenMAX从数据源把demux后的数据读取到输入缓,作为OpenMAX的输入

2通过fillOutputBuffers()mPortBuffers[kPortIndexInput]进行填充,这一步完成decode,

OpenMAX对输入缓冲区的数据进行解码

3AwesomePlayer通过mVideoRenderer->reder()对经过parsedecode处理的数据进行渲染

mVideoRenderer=newAwesomeLocalRenderer(

false,//previewOnly

component,

(OMX_COLOR_FORMATTYPE)format,

mISurface,

mVideoWidth,mVideoHeight,

decodedWidth,decodedHeight,rotationDegrees);

 

 

StageFright的处理流程

AudioplayerawesomePlayer的成员,audioplayer通过callback来驱动数据的获取,

Awesomeplayer则是通过videoevent来驱动,数据获取由mSource->Read()来完成,

Read内部将parsetdecod在一起

两者进行同步部分audio完全是callback驱动数据流,

Video部分在onvideoEvent会读取audio的时间戳,是传统的AV时间戳同步

 

 

AwesomePlayerVideo主要有以下几个成员

mVideoSource(解码视频)

mVideoTeack(从媒体文件中读取视频数据)

mVideoRenderer(对解码好的视频进行格式转换,android使用的格式为RGB565)

mlSurface(重绘图层)

mQueue(event事件对列)

 

Audio部分的抽像流程如下:

设置mUrl路径

启动mQueue,创建一个线程threadEntry(timedEventQueue,这个线程就是event调度器)

打开mUrl指定文件头部,根据不同类型选择不同的分离器(例如:MPEG4Extractor

使用分离器(MPEG4ExtractorMP4进行音视频轨道的分离,返回MPEG4Source类型的视频轨道给mVideoTrack

根据mVideoTrack中的编码类型来选择解码器,avc的编码类型会选择AVCDecoder,并返回给mVideoSource并设置mVideoSource中的mSourcemVideoTrack

插入到onVideoEventqueue,开始解码播放

通过mVideoSource对象来读取解析好的视频buffer,如果解析好的buffer还没到AV时间戳同步的时刻,则推迟到下一轮操作,

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

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

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

 

 

数据源到最终解码后的流程如下

URI,FD------->DataSource---------->MediaExtractor------------>mVideoTrackmAudioTrack(音视频数据流)--------------->mVideoSourcemAudioSource(音视频解码器)

:URI可以为;http://rtsp://

FD是本地文件描述符

 

打开log日志

代码标记Log

依据第4》项StageFright描述的Vide视频播放流程,作Log标记跟踪视频DATA获取、CODEC过程。从AwesomePlayer.cpp中方法着手,步骤如下:

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

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

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

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

n打开Gallery选择视频文件运行,并同步查看log

分享到:
评论

相关推荐

    Android 系统相关学习笔记.zip

    Android 系统相关学习笔记.zip

    android系统模块之Contacts的学习笔记

    android系统模块之Contacts的学习笔记

    android开发学习笔记

    本人做android也有两年了,主要做智能机系统级开发,期间也承包了一些项目,对于如何学好android,以及学好android后如何开启自己的致富之门也能起到抛砖引玉的作用,欢迎大家加入,积极发言讨论,积极解决他人的...

    Android学习笔记.doc Android学习笔记.doc

    Android platform是一个用于开发移动程序的软件包,它包括了操作系统、中间件及一些关键应用。开发者能使用android SDK为Android platform开发应用,这些应用使用JAVA语言书写,运行在虚拟机Dalvik(一个专为手机程序...

    Pro Android学习:Menu

    是Pro Android学习笔记Menu系统的例子代码

    android入门学习笔记-永远不变的helloworld、初识activity

    本资源是上课时的笔记,系统的讲述了android。想学习andorid的新手可以载下来供参考使用

    Android知识系统总结+最佳学习线路图+实例+全程开发笔记

    Android知识系统总结+最佳学习线路图+实例+全程开发笔记Android知识系统总结+最佳学习线路图+实例+全程开发笔记

    Android学习笔记.doc

    Android platform是一个用于开发移动程序的软件包,它包括了操作系统、中间件及一些关键应用。开发者能使用android SDK为Android platform开发应用,这些应用使用JAVA语言书写,运行在虚拟机Dalvik(一个专为手机程序...

    android 系统笔记.zip

    操作系统:LInux、IOS、树莓派、安卓开发、微机操作系统、网络操作系统、分布式操作系统等。此外,还有嵌入式操作系统、智能操作系统等。 网络与通信:数据传输、信号处理、网络协议、网络与通信硬件、网络安全网络...

    android 学习笔记

    使用系统自带意图对象完成: Intent intent=new Intent(); intent.setAction("android.intent.action.Call"); intent.setData(Uri.parse("tel:"+i)); startActivity(Intent); 权限: &lt;uses-permission ...

    黑马程序员之android学习笔记--用户界面 View(一).docx

    黑马程序员之android学习笔记--用户界面 View(一).docx

    Android Map开发基础知识学习笔记

    本教程适用于Android Map学习的初学者,这是一本很平易近人的Android入门书籍,也是开发者及非开发者两相宜的实务书籍,它能陪伴你顺利入门,并驰骋于无限宽广的Android系统和应用领域

    Android知识系统总结

    里面包含7个常见android应用程序源代码,android学习笔记,开发入门实践,入门书籍等很有用的资料。

    第一行代码—Android第二版学习笔记

    Android 第一行代码学习笔记第一章 概述1.1安卓系统架构1.2Android四大组件1.3项目结构1.4app目录结构1.5 项目运行原理1.6 res目录详解1.7日志工具的使用第二章 活动2.1 创建基本活动2.2 使用Intent在活动之间跳转...

    Android学习笔记之——Content Providers

    之前博文《 Android学习笔记之——Android Studio的安装(3.6版本)、Java的基本语法及Android的概述 》曾经介绍过android有四大组件。本博文学习一下Content Providers(内容提供器) 目录 Android运行时 ...

    2021-学习相关-Android 局域网简易云端笔记系统源码.zip

    2021-学习相关-Android 局域网简易云端笔记系统源码.zip

    AOSP Android系统定制裁剪笔记.zip

    操作系统:LInux、IOS、树莓派、安卓开发、微机操作系统、网络操作系统、分布式操作系统等。此外,还有嵌入式操作系统、智能操作系统等。 网络与通信:数据传输、信号处理、网络协议、网络与通信硬件、网络安全网络...

    android移植到特定平台学习笔记

    android移植到Cortex-A8平台,手把手开发步骤,从安装编译器,配置环境变量,编译uboot,kernel,android文件系统详细步骤和修改的文件。最后是将镜像烧入SD卡等详细步骤!好东西不容错过

    Android代码-Android_Learning_Notes

    这是我的安卓学习笔记。 开始时间:2016-9-11 计划:一个半月 文章目录: 基础知识 1、Android01--搭建Android开发环境 2、Android02--认识Activity 3、Android03--Context和Application 4、Android04--Android服务 ...

Global site tag (gtag.js) - Google Analytics