`

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学习笔记 完整版

    Android学习笔记是Android开发者的必读书籍,书中涵盖了Android系统架构、Activity、Intent、资源管理等多方面的知识。本笔记对应的学习资源《第一行代码》是Android开发者的入门必读书籍,书中系统地介绍了Android...

    Android基础学习笔记

    Android基础学习笔记主要涵盖了一系列关于Android开发的基本概念和关键组件,以下是这些知识点的详细解析: 1. **Activity**: 是Android应用程序的基本单元,它代表用户在屏幕上看到的一个界面。每个Activity都必须...

    Android Studio 学习笔记-新手入门-(1)第一个案例

    这篇学习笔记将引导新手入门,通过创建第一个简单的案例来了解Android Studio的基本操作。 首先,让我们了解一下Android Studio的核心功能。它基于IntelliJ IDEA,具备代码自动补全、重构、调试等强大的开发特性。...

    Android Activity学习笔记

    Android Activity学习笔记 Android Activity是Android系统中最基本的组件之一,它负责处理用户交互和显示用户界面。本文将深入讲解Activity的生命周期、Activity之间的数据交互、Activity启动模式、Task和BackStack...

    Android学习新手笔记

    - Android系统基于Linux系统开发,拥有开放源码。 - Android系统框架由多个组件构成,其中包括Activity、Intent、Service、ContentProvider、View和BroadcastReceiver。 - Activity作为组件容器,主要负责用户...

    java学习细节 android学习笔记

    根据给定的信息,我们可以从Java和Android学习笔记中提取出一系列重要的知识点,下面将逐一进行详细解释。 ### Java基础知识 #### 1. 命令行基础操作 - **`javacmd`**: 这个命令是Java命令行工具的一部分,用于...

    Android+学习笔记

    ### Android学习笔记知识点详解 #### 一、简介与背景 Android作为全球最受欢迎的移动操作系统之一,自2007年谷歌发布以来,迅速占领市场并持续引领移动技术的发展。随着移动互联网的兴起和发展,Android应用开发...

    Android_学习笔记

    ### Android学习笔记——从HelloWorld开始 #### 一、Google的Android SDK介绍 自从Google发布了Android SDK以来,这款开源移动操作系统迅速吸引了众多开发者的关注。Android SDK为开发者提供了丰富的工具和API,...

    android全程学习笔记

    Android全程学习笔记旨在提供一个详尽且全面的指南,涵盖了Android开发中的关键技术点和实践案例。以下是关于Android开发的一些核心知识点: 1. **第一个Android应用**:开发Android应用的起点通常是从创建并运行你...

    Android 学习笔记

    这篇学习笔记主要涵盖了关于布局的一些基本概念,特别是`fill_parent`和`wrap_content`这两种尺寸指定方式,以及如何通过XML布局文件来精确控制组件的位置。 首先,`fill_parent`和`wrap_content`是Android布局中的...

    Android_学习笔记.zip

    这个"Android_学习笔记.zip"文件很可能包含了一个详细的Android开发学习路径和关键知识点的总结。下面将基于这个主题,详细讲解Android开发的一些核心概念和技术。 首先,Android是Google开发的一款开源操作系统,...

    Android 系统相关学习笔记.zip

    在Android系统相关学习笔记中,我们可以深入探讨这个广泛而复杂的移动操作系统的核心概念和技术。Android以其开源性和灵活性,吸引了大量的开发者和爱好者。以下是一些关键的知识点: 1. **Android架构**:Android...

    android 很好的学习笔记

    【Android学习笔记详解】 在移动应用开发领域,Android操作系统占据着重要的地位,为开发者提供了...通过系统学习并实践其中的内容,你将能够逐步掌握Android开发的核心技能,为你的Android开发者之路打下坚实的基础。

    Android PreferenceActivity 学习笔记

    这篇学习笔记将深入探讨PreferenceActivity的使用方法、功能以及与源码相关的知识。 首先,PreferenceActivity是Android SDK提供的一种特殊类型的Activity,它允许开发者快速构建具有可配置选项的界面,类似于系统...

    Android开发学习笔记

    ### Android开发学习笔记知识点梳理 #### 一、Android概述与架构 - **定义与发布**:Android是由Google在2007年11月5日宣布的基于Linux平台的开源手机操作系统。它不仅用于智能手机,还广泛应用于平板电脑、可穿戴...

    Android入门学习笔记

    Android入门学习笔记主要涵盖了Android开发的基础知识,包括平台概述、环境搭建、基本概念以及实际应用开发的各个方面。这里我们将深入探讨这些关键知识点。 一、Android平台概述 Android是由Google主导开发的一款...

Global site tag (gtag.js) - Google Analytics