做报纸能经常更新网站,网站和服务器是什么,佛山全网优化,运营一个网站要多少钱android 的多媒体系统 多媒体系统的结构和业务
多媒体系统的宏鸡观结构
应用层#xff0c;java框架层,c 语言层,硬件抽像层,其中输入输出由HAL层,处理环节由packetView的OpenCore实现,
多媒体业备有以下几种:
musicPlayer(音频播放器)
viderPlayer(视频播放器)
Camera(照… android 的多媒体系统 多媒体系统的结构和业务
多媒体系统的宏鸡观结构
应用层java框架层,c 语言层,硬件抽像层,其中输入输出由HAL层,处理环节由packetView的OpenCore实现,
多媒体业备有以下几种:
musicPlayer(音频播放器)
viderPlayer(视频播放器)
Camera(照相机)
soundRecord(录音机)
videoCamera (摄像机)
Media metadata(媒体元信息) 核心是媒体的播放和录制分别由下层的OpenCore的PVPlayer和PVAuthor来实现
多媒体的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. 部分代码如下 class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier
{
public: MediaPlayer(); ~MediaPlayer(); void died(); void disconnect(); status_t setDataSource( const char *url,//设置数据源url const KeyedVectorString8, String8 *headers); status_t setDataSource(int fd, int64_t offset, int64_t length);//设置数据源文件 status_t setVideoSurface(const spSurface surface);//设视频输出界面 status_t setListener(const spMediaPlayerListener listener);//设置临听 status_t prepare();//准备播放 status_t prepareAsync();//异部准备播放 status_t start();//开始 status_t stop();//停止 status_t pause();//暂停 bool isPlaying();//是否正在播放 status_t getVideoWidth(int *w);//获取视频播放的宽 status_t getVideoHeight(int *h);//获取视频播放的高 status_t seekTo(int msec);//跳转到指定位置 status_t getCurrentPosition(int *msec);//取得当前的播放位置 status_t getDuration(int *msec);//播放的持续时间(总时长) status_t reset();//复位 status_t setAudioStreamType(int type);//设置音频流的格式 status_t setLooping(int loop);// 设置循环 bool isLooping();//是否循环 status_t setVolume(float leftVolume, float rightVolume);//设置音量 void notify(int msg, int ext1, int ext2);//通知函数 static spIMemory decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); static spIMemory decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); status_t invoke(const Parcel request, Parcel *reply); status_t setMetadataFilter(const Parcel filter); status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata); status_t suspend(); status_t resume(); status_t setAudioSessionId(int sessionId); int getAudioSessionId(); status_t setAuxEffectSendLevel(float level); status_t attachAuxEffect(int effectId);
private: void clear_l(); status_t seekTo_l(int msec); status_t prepareAsync_l(); status_t getDuration_l(int *msec); status_t setDataSource(const spIMediaPlayer player); spIMediaPlayer mPlayer; thread_id_t mLockThreadId; Mutex mLock; Mutex mNotifyLock; Condition mSignal; spMediaPlayerListener mListener; void* mCookie; media_player_states mCurrentState; int mDuration; int mCurrentPosition; int mSeekPosition; bool mPrepareSync; status_t mPrepareStatus; int mStreamType; bool mLoop; float mLeftVolume; float mRightVolume; int mVideoWidth; int mVideoHeight; int mAudioSessionId; float mSendLevel;
}; IMeciaplayer.h 媒体播和器服务部分的接口(和上层的mediaplay 中的接口方法类似) 被BnMedaplayer继承,提供Binder通信本地实现基础 部分代码如下
//继承mediaplayerBase,通过autoFlinger输出 class MediaPlayerInterface : public MediaPlayerBase{
public: virtual ~MediaPlayerInterface() { } virtual bool hardwareOutput() { return false; } virtual void setAudioSink(const spAudioSink audioSink) { mAudioSink audioSink; }
protected: spAudioSink mAudioSink;//音频轮输出设备的抽像接口
}; // Implement this class for media players that output directo to hardware
//直接从硬功夫件进行音频输出
class MediaPlayerHWInterface : public MediaPlayerBase//继承mediaplayerBaser
{
public: virtual ~MediaPlayerHWInterface() {} virtual bool hardwareOutput() { return true; } virtual status_t setVolume(float leftVolume, float rightVolume) 0; virtual status_t setAudioStreamType(int streamType) 0;
}; mediaplayerInterface.h PVPlayer.h是媒体播放器实现层的接口 (是opencore媒体播放器实现的头文件) 继承自MediaPlayerInterface 部分代码如下 class PVPlayer : public MediaPlayerInterface
{
public: PVPlayer(); virtual ~PVPlayer(); virtual status_t initCheck(); virtual status_t setDataSource( const char *url, const KeyedVectorString8, String8 *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setVideoSurface(const spISurface surface); virtual status_t prepare(); virtual status_t prepareAsync(); virtual status_t start(); virtual status_t stop(); virtual status_t pause(); virtual bool isPlaying(); virtual status_t seekTo(int msec); virtual status_t getCurrentPosition(int *msec); virtual status_t getDuration(int *msec); virtual status_t reset(); virtual status_t setLooping(int loop); virtual player_type playerType() { return PV_PLAYER; } virtual status_t invoke(const Parcel request, Parcel *reply); virtual status_t getMetadata( const SortedVectormedia::Metadata::Type ids, Parcel *records); // make available to PlayerDriver void sendEvent(int msg, int ext10, int ext20) { MediaPlayerBase::sendEvent(msg, ext1, ext2); } private: static void do_nothing(status_t s, void *cookie, bool cancelled) { } static void run_init(status_t s, void *cookie, bool cancelled); static void run_set_video_surface(status_t s, void *cookie, bool cancelled); static void run_set_audio_output(status_t s, void *cookie, bool cancelled); static void run_prepare(status_t s, void *cookie, bool cancelled); static void check_for_live_streaming(status_t s, void *cookie, bool cancelled); PlayerDriver* mPlayerDriver; char * mDataSourcePath; bool mIsDataSourceSet; spISurface mSurface; int mSharedFd; status_t mInit; int mDuration; #ifdef MAX_OPENCORE_INSTANCES static volatile int32_t sNumInstances;
#endif
}; ImeciaplayerClient.h 多媒体的客户端(定义了媒体的客户端) 主要用作通知函数 Mediaplayer继承ImediaplayerClient 所以可以得到下层传弟的信息 部分代码如下
class IMediaPlayerClient: public IInterface
{
public: DECLARE_META_INTERFACE(MediaPlayerClient); virtual void notify(int msg, int ext1, int ext2) 0;//通知的信息是个消息
}; Imediaplayerservice.h 多媒体的服务(定义了多媒体服务的接口由下层服务去实现)
部分代码如下 class IMediaPlayerService: public IInterface
{
public: DECLARE_META_INTERFACE(MediaPlayerService);
/ virtual spIMediaRecorder createMediaRecorder(pid_t pid) 0; virtual spIMediaMetadataRetriever createMetadataRetriever(pid_t pid) 0;
/创建IMediaPlayer virtual spIMediaPlayer create(pid_t pid, const spIMediaPlayerClient client, const char* url, const KeyedVectorString8, String8 *headers NULL, int audioSessionId 0) 0; virtual spIMediaPlayer create(pid_t pid, const spIMediaPlayerClient client, int fd, int64_t offset, int64_t length, int audioSessionId) 0;
//用于直接解码 virtual spIMemory decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) 0; virtual spIMemory decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) 0; virtual spIOMX getOMX() 0;
}; // ---------------------------------------------------------------------------- class BnMediaPlayerService: public BnInterfaceIMediaPlayerService
{
public: virtual status_t onTransact( uint32_t code, const Parcel data, Parcel* reply, uint32_t flags 0);
};
源文件的目录
\frameworks\base\media\libmedia 媒体记录器 头文件和实现文件的代码路径:
\frameworks\base\include\media
主要的头文件有 MediaRecorder.h 媒体记录器的上层拉接口,每个函数都调用IMediaRecord来实现, 他也继承了BnMediaPlayerClient用于接收下层返回的通知 部分代码如下 class MediaRecorder : public BnMediaRecorderClient, public virtual IMediaDeathNotifier
{
public: MediaRecorder(); ~MediaRecorder(); void died(); status_t initCheck(); status_t setCamera(const spICamera camera); //设置camera作为输入设备 status_t setPreviewSurface(const spSurface surface); //设置视频预览界面 status_t setVideoSource(int vs); //视频数据源( 枚举值) status_t setAudioSource(int as); //音频数据源 (同上) status_t setOutputFormat(int of); //设置输出格式 status_t setVideoEncoder(int ve); //设置视频编码格式 status_t setAudioEncoder(int ae); //设置音频编码格式 status_t setOutputFile(const char* path); //设置输出文件路径 status_t setOutputFile(int fd, int64_t offset, int64_t length); //设置输出文件的文件描述符 status_t setVideoSize(int width, int height); //设置视频尺寸 status_t setVideoFrameRate(int frames_per_second); //设置视频帧率 status_t setParameters(const String8 params); //设置其他参数 status_t setListener(const spMediaRecorderListener listener); //设置临听 status_t prepare(); //准备录制 status_t getMaxAmplitude(int* max); //获得最大增益 status_t start(); //开始 status_t stop(); //停止 status_t reset(); //复位 status_t init(); //初始化记录器 status_t close(); //关闭记录器 status_t release(); //释放资源 void notify(int msg, int ext1, int ext2); private: void doCleanUp(); status_t doReset(); spIMediaRecorder mMediaRecorder; spMediaRecorderListener mListener; media_recorder_states mCurrentState; bool mIsAudioSourceSet; bool mIsVideoSourceSet; bool mIsAudioEncoderSet; bool mIsVideoEncoderSet; bool mIsOutputFileSet; Mutex mLock; Mutex mNotifyLock;
}; }; IMediaRecorder.h 媒体记录器的部分实现接口 部分代码如下 class IMediaRecorder: public IInterface
{
public: DECLARE_META_INTERFACE(MediaRecorder); virtual status_t setCamera(const spICamera camera) 0; virtual status_t setPreviewSurface(const spISurface surface) 0; virtual status_t setVideoSource(int vs) 0; virtual status_t setAudioSource(int as) 0; virtual status_t setOutputFormat(int of) 0; virtual status_t setVideoEncoder(int ve) 0; virtual status_t setAudioEncoder(int ae) 0; virtual status_t setOutputFile(const char* path) 0; virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) 0; virtual status_t setVideoSize(int width, int height) 0; virtual status_t setVideoFrameRate(int frames_per_second) 0; virtual status_t setParameters(const String8 params) 0; virtual status_t setListener(const spIMediaRecorderClient 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; virtual status_t init() 0; virtual status_t close() 0; virtual status_t release() 0;
}; // ---------------------------------------------------------------------------- class BnMediaRecorder: public BnInterfaceIMediaRecorder
{
public: virtual status_t onTransact( uint32_t code, const Parcel data, Parcel* reply, uint32_t flags 0);
}; }; PVMediaRecorder.h 下层接口,由openCore实现 媒体元信息和扫描器
主要的头文件有
MediaMetadataRetriever.h 部分代码如下 class MediaMetadataRetriever: public RefBase
{
public: MediaMetadataRetriever(); ~MediaMetadataRetriever(); void disconnect(); status_t setDataSource(const char* dataSourceUrl); //设置数据源(url) status_t setDataSource(int fd, int64_t offset, int64_t length); //设置数据源(文件描述符) spIMemory getFrameAtTime(int64_t timeUs, int option); //捕获帧 spIMemory extractAlbumArt(); // 抽取 const char* extractMetadata(int keyCode); //抽取元信息 IMediaMetadataRetriever MediaMetadataRetrieverInterface.h 实现的接口文件
PVMetadataRetriever.h 下层实现的接口 class MediaMetadataRetrieverBase : public RefBase{}
class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase{}
class PVMetadataRetriever : public MediaMetadataRetrieverInterface{} 媒体扫描器的头文件
MediaScanner .h scanner的接口扫描一个文件或者一个文件夹取得文件格式会调用MediaScannerClient 部分代码如下: struct MediaScanner { MediaScanner(); virtual ~MediaScanner(); virtual status_t processFile( const char *path, const char *mimeType, MediaScannerClient client) 0; typedef bool (*ExceptionCheck)(void* env); virtual status_t processDirectory( const char *path, const char *extensions, MediaScannerClient client, ExceptionCheck exceptionCheck, void *exceptionEnv); void setLocale(const char *locale); // extracts album art as a block of data virtual char *extractAlbumArt(int fd) 0;
} class MediaScannerClient
{
public: MediaScannerClient(); virtual ~MediaScannerClient(); void setLocale(const char* locale); void beginFile(); bool addStringTag(const char* name, const char* value); void endFile(); virtual bool scanFile(const char* path, long long lastModified, long long fileSize) 0; virtual bool handleStringTag(const char* name, const char* value) 0; virtual bool setMimeType(const char* mimeType) 0; virtual bool addNoMediaFolder(const char* path) 0;
} 多媒体服务 他包含媒体揪放器, 媒体记录器,媒体元信息管理 他和他的调用者是在两个不同的进程中,使用binder进行IPC通信
多媒体服务的守护进程main_mediaserver.cpp 代码中和路径: \frameworks\base\media\mediaserver 部分代码如下 int main(int argc, char** argv)
{ spProcessState proc(ProcessState::self()); spIServiceManager 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作为一个守护进程在android的init.rc中具有如下定义 Service media /system/bin/mediaserver User media Group system audio camera graphics inet net_bt net_bt_admin
由于没有定义oneshot所以这个进程一直存在如果被杀死init会将其重新启动 多媒体服务的实现 多媒体服务的路径:\frameworks\base\media\libmediaplayerservice mediaPlayerService.h头文件中定义了 ,是IMediaplayer的实现 class MediaPlayerService : public BnMediaPlayerService{ class AudioOutput : public MediaPlayerBase::AudioSink {} class AudioCache : public MediaPlayerBase::AudioSink{} class Client : public BnMediaPlayer {}
}
是IMeciaRecorder的实现
class MediaRecorderClient : public BnMediaRecorder{}
是IMediadataRetriever的实现
class MetadataRetrieverClient : public BnMediaMetadataRetriever{} MediaPlayerService.cpp中定义了取得媒体记录器(IMediaRecorder)的接口
spIMediaRecorder MediaPlayerService::createMediaRecorder(pid_t pid)
{ spMediaRecorderClient recorder new MediaRecorderClient(this, pid); wpMediaRecorderClient w recorder; Mutex::Autolock lock(mLock); mMediaRecorderClients.add(w); LOGV(Create new media recorder client from pid %d, pid); return recorder;
}
取得媒体播放器的媒体元信息
spIMediaMetadataRetriever MediaPlayerService::createMetadataRetriever(pid_t pid)
{ spMetadataRetrieverClient retriever new MetadataRetrieverClient(pid); LOGV(Create new media retriever from pid %d, pid); return retriever;
} MediaPlayService 类中创建媒体播放器的过程 1 spIMediaPlayer MediaPlayerService::create(pid_t pid, const spIMediaPlayerClient client, int fd, int64_t offset, int64_t length, int audioSessionId)
{ int32_t connId android_atomic_inc(mNextConnId); //创建mediaPlayerService::Client类 spClient c new Client(this, pid, connId, client, audioSessionId); LOGV(Create new client(%d) from pid %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 { wpClient w c; Mutex::Autolock lock(mLock); mClients.add(w); } ::close(fd); return c;
} static spMediaPlayerBase createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc)
{ spMediaPlayerBase p; switch (playerType) { //根据playerType的类型建立不同的播放器
#ifndef NO_OPENCORE case PV_PLAYER: LOGV( create PVPlayer); p new PVPlayer(); break;
#endif case SONIVOX_PLAYER: LOGV( create MidiFile); p new MidiFile(); break; case STAGEFRIGHT_PLAYER: LOGV( create StagefrightPlayer); p new StagefrightPlayer; break; case TEST_PLAYER: LOGV(Create Test Player stub); p new TestPlayerStub(); break; } if (p ! NULL) { if (p-initCheck() NO_ERROR) { p-setNotifyCallback(cookie, notifyFunc); } else { p.clear(); } } if (p NULL) { LOGE(Failed to create player object); } return p;
} PVPlayer MidiFile和VorbisPlayer三个都继承MediaPlayInterface得到的MediaPlayerInterface是继承MediaPlayerBase得到, 三者具有相同的接口类型,三者在建立之后通过MediaPlayerBase接口来控制他们
媒体播放器的实现结构如下图所示 MediaPlayerService::AudioOutput实现audio输出环节的封装由Audio系统来实现主要是调用AudioTrakc的接口
status_t MediaPlayerService::AudioOutput::open( uint32_t sampleRate, int channelCount, int format, int bufferCount, AudioCallback cb, void *cookie)
{ mCallback cb; mCallbackCookie cookie; // Check argument bufferCount against the mininum buffer count if (bufferCount mMinBufferCount) { LOGD(bufferCount (%d) is too small and increased to %d, bufferCount, mMinBufferCount); bufferCount mMinBufferCount; } LOGV(open(%u, %d, %d, %d, %d), sampleRate, channelCount, format, bufferCount,mSessionId); if (mTrack) close(); int afSampleRate; int afFrameCount; int frameCount; if (AudioSystem::getOutputFrameCount(afFrameCount, mStreamType) ! NO_ERROR) { return NO_INIT; } if (AudioSystem::getOutputSamplingRate(afSampleRate, mStreamType) ! NO_ERROR) { return NO_INIT; } //获得帧数和采样率 frameCount (sampleRate*afFrameCount*bufferCount)/afSampleRate; AudioTrack *t; if (mCallback ! NULL) { t new AudioTrack( mStreamType, sampleRate, format, (channelCount 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO, frameCount, 0 /* flags */, CallbackWrapper, this, 0, mSessionId); } else { t new AudioTrack( 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(Unable to create audio track); delete t; return NO_INIT; } LOGV(setVolume); t-setVolume(mLeftVolume, mRightVolume); mMsecsPerFrame 1.e3 / (float) sampleRate; mLatency t-latency(); mTrack t; t-setAuxEffectSendLevel(mSendLevel); return t-attachAuxEffect(mAuxEffectId);;
} 音频输出的接口
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
{ LOG_FATAL_IF(mCallback ! NULL, Dont call write if supplying a callback.); //LOGV(write(%p, %u), buffer, size); if (mTrack) { ssize_t ret mTrack-write(buffer, size); return ret; } return NO_INIT;
} 多媒体的JNI部分 本地调用部分的代码路径为 Frameworks/base/media/jni 主要文件有 Android 2。3后改用stagefright
\frameworks\base\media\libstagefright
两者的处理机制不同
openCore 的处理流程如下 Stagefright部分的处理流程如下 从上面可以看出 1 OpenCore的 parser和 dec是分离的各行其职stagefright则是邦在一起作为一个独立的原子操作 2 stagefright通过callback 和videoevent 来驱动数据输出, openCore是通过sink-node节点控制输出 3 Opencore中parser/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()函数中直接从环境中得到并设置了。 static void
android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
{ spMediaPlayer 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, Prepare failed. );
} static void
android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
{ LOGV(prepare); spMediaRecorder mr getMediaRecorder(env, thiz); jobject surface env-GetObjectField(thiz, fields.surface); if (surface ! NULL) { const spSurface native_surface get_surface(env, surface); // The application may misbehave and // the preview surface becomes unavailable if (native_surface.get() 0) { LOGE(Application lost the surface); jniThrowException(env, java/io/IOException, invalid preview surface); 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, setPreviewSurface failed.)) { return; } } process_media_recorder_call(env, mr-prepare(), java/io/IOException, prepare failed.);
} 多媒体部分的java部分代码 Java框架类的路径为: frameworks\base\media\java\android\media 主要文介绍;: MediaFile.java 文件提供了媒体文件的文件类型 MediaPlayer MediaRecorder MediaMetadataRecorder 等类基本上和JNI层的内容一一对应 MediaScanner在这里实现有客户端内容比较多 其中MedisPlayer 中对视频输出和取景器预览的接口 public void setDisplay(SurfaceHolder sh) { mSurfaceHolder sh; if (sh ! null) { mSurface sh.getSurface(); } else { mSurface null; } _setVideoSurface(); updateSurfaceScreenOn(); } MediaRecorder中对视频输出和取景器预览的接口 public void setPreviewDisplay(Surface sv) { mSurface sv; } Java框架层没有直接使用传递参数的方式,而是使用了保存在环境中再传递的方式 Android.widgetVideoView类. 是一个UI元素
代码路径为frameworks\base\core\java\android\widget 使用该类可以不用再调用MediaPlayer类,节省了一些中间环节
public class VideoView extends SurfaceView implements MediaPlayerControl { public void setVideoPath(String path) { }//设置源文件路径 public void setVideoURI(Uri uri) {}//设置视频的URL public void start() {}//开始播放 public void stopPlayback() {}//停止播放
public void pause() { }//暂停播放 public void seekTo(int msec) {}//更改播放位置 多媒体实现的核心部分 OpenCore
多媒体系统框架PacketVideo的开源版本OpenCore是android 多媒体本地实现在的核心
它为android提供的引警如下 PVPlayer 媒体播放器的功能 音频和视频的回放功能 PVAuthor 媒体记录器功能 音频和视频的录制 OpenCore的层次结构 自上而下分为
OSCL (operation system compatibility library ,操作系统兼容库) 类似一个基础的c库
PVMF (packetVideo Multimedia Framework 多媒体框架) packetVideo 的基本框架, 例如nodea基类输入输出的抽象类
文件格式处理, 文件解析parser和组成(composer)两个部分,
各种Node 是packetVideo 中的基本功能模块,
播放器(Player Engine) 播放器引擎
记录器 (author Engine) 媒体记录器引擎 注 在openCore2.X之后 开始提供了2-way engine 两路引擎 用于构建视频电话
在使用OpenCore的SDK时需要在应用层实现一个适配器 PVPlaytr和PVAuthor就是基于OpenCore的下层功能和接口构建军的应用层的库 在android 系统中 OpenCore的代码路径为externam/opencore/ Stagefright整体框图: Android froyo版本对多媒体引擎作了变动.新添加了stagefright框架,但并没有完全抛弃opencore
主要是作了一个omx 层,仅是对opencore的omx-component部分作了引用,,它在android 系统中作为
共享库(libstagefright.so)存在, 其中的module--awesomePlayer用来播放video/audio Awesomeplayer 提供的API可以供上次的应用(java/JNI)来调用 StageFrigtht数据流封装 1 MediaExtractor.cpp根据数据源DataSource生成MediaExtractor 具体实现是通过调用(代码路径为frameworks\base\media\libstagefright) spMediaExtractor MediaExtractor::Create( const spDataSource source, const char *mime) {} 通过DateSource的source-sniff(tmp, confidence, meta)来探测数据类型 2 AwesomePlayer.cpp把音视频轨道分离,生成mVideoTrack 和MediaSource 部分代码如下 if (!haveVideo !strncasecmp(mime, video/, 6)) { setVideoSource(extractor-getTrack(i)); haveVideo true; } else if (!haveAudio !strncasecmp(mime, audio/, 6)) { setAudioSource(extractor-getTrack(i)); haveAudio true; if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { // Only do this for vorbis audio, none of the other audio // formats even support this ringtone specific hack and // retrieving the metadata on some extractors may turn out // to be very expensive. spMetaData fileMeta extractor-getMetaData(); int32_t loop; 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就可以调用mediaSource的read方法读取解码后的数据
对于mVideoSource来说, 读取数据mVideoource-read(mVideoBuffer,options) 交给显示模块进行渲染, mVideoRenderer-render(mVideoBufer) 4 stageFright的decode
经过流的封装得到两个MediaSource ,其实是两个OMXCodec,
AwesomePlayer和mAudioPlayer都是从mediaSource中得到数据进行播放, 最终需要渲染的原始视频数据,也就是说OMXCodec中得到的是原始数据
部分代码如下
spMediaSource OMXCodec::Create( const spIOMX omx, //OMXNodeInstance对象的实例 const spMetaData meta, bool createEncoder, //由MediaSource.getFormat获取得到, //他的对象成员是一个keyedVectoruint32_t,typed_data //里面存放的是代表mediaSource格式信息的键值对 const spMediaSource source, //mediaExtractor const char *matchComponentName, //指定一种codec用于生成omxcodec uint32_t flags) { //首先调用findMatchingCodecs()方法,找到对应的Codec findMatchingCodecs( mime, createEncoder, matchComponentName, flags, matchingCodecs); //找到以后为当前的IOMX分配并注册监听事件, status_t err omx-allocateNode(componentName, observer, node); //这样就得到了OMXCodec spOMXCodec codec new OMXCodec( omx, node, quirks, createEncoder, mime, componentName, source); } 在AwesomePlayer中得到这个OMXCodec后首先调用mVideoSource-start()进行初始化,主要有两件事
1 向openMAX发送命令 err mOMX-sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
2 err allocateBuffers(); 分配两个缓冲区 ,freeBuffersOnPort() 分别用于输入和输出 当awesomePlayer开始播放以后,通过mVideoSource-read(mVideoBuffer,options) 读取数据 OMXCodec.read分两部来实现数据读取, 1 通过调用draininputBuffers()对mPortBuffers[kPortindexOutput]进行填充这一步完成parse 由OpenMAX从数据源把demux后的数据读取到输入缓作为OpenMAX的输入 2 通过fillOutputBuffers()对mPortBuffers[kPortIndexInput]进行填充, 这一步完成decode, 由OpenMAX对输入缓冲区的数据进行解码 3 AwesomePlayer通过mVideoRenderer-reder()对经过parse和decode处理的数据进行渲染 mVideoRenderer new AwesomeLocalRenderer( false, // previewOnly component, (OMX_COLOR_FORMATTYPE)format, mISurface, mVideoWidth, mVideoHeight, decodedWidth, decodedHeight, rotationDegrees); StageFright的处理流程
Audioplayer是awesomePlayer的成员audioplayer通过callback来驱动数据的获取, Awesomeplayer则是通过videoevent来驱动数据获取由mSource-Read()来完成 Read内部将parset和decod 在一起 两者进行同步部分 audio完全是callback驱动数据流 Video部分在onvideoEvent会读取audio的时间戳是传统的AV时间戳同步 AwesomePlayer的Video主要有以下几个成员 mVideoSource(解码视频) mVideoTeack(从媒体文件中读取视频数据) mVideoRenderer(对解码好的视频进行格式转换,android 使用的格式为 RGB565) mlSurface(重绘图层) mQueue(event事件对列) Audio部分的抽像流程如下 设置mUrl路径 启动mQueue,创建一个线程threadEntry(timedEventQueue,这个线程就是event调度器) 打开mUrl指定文件头部根据不同类型选择不同的分离器例如MPEG4Extractor 使用分离器(MPEG4Extractor对MP4进行音视频轨道的分离返回MPEG4Source类型的视频轨道给mVideoTrack 根据mVideoTrack 中的编码类型来选择解码器 avc的编码类型会选择AVCDecoder,并返回给mVideoSource并设置mVideoSource中的mSource为mVideoTrack 插入到onVideoEvent到queue中,开始解码播放 通过mVideoSource对象来读取解析好的视频buffer,如果解析好的buffer还没到AV时间戳同步的时刻则推迟到下一轮操作 mVideoRenderer为空则进行初始化(如果不使用OMX会将mVideoRenderer设置为AwesomeLocalRenderer) 通过mVideoRenderer对象将解析好的视频buffer转换成RGB565格式,并发给display模块进行图像绘制
将onVideoEvent重新插入event调度器来循环 数据源到最终解码后的流程如下 URI,FD-------DataSource----------MediaExtractor------------mVideoTrack mAudioTrack(音视频数据流)---------------mVideoSource mAudioSource(音视频解码器) 注: 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/下运行./adb shell文件再运行logcat n 打开Gallery选择视频文件运行并同步查看log。