MediaPlayer 视频播放
来源:互联网 发布:广州淘宝培训 编辑:程序博客网 时间:2024/04/28 14:40
我参考的是android 源码中播放资源的对象VideoView.java, VideoView对象中实现视频播放最重要的对象是MediaPlayer 对象。
VideoView 连接视频资源的时候, 首先需要初始化一个MediaPlayer对象。
public void setVideoURI(Uri uri, Map<String, String> headers) { mUri = uri; mHeaders = headers; mSeekWhenPrepared = 0; openVideo(); requestLayout(); invalidate(); }
在openVideo 的处理中,初始化mediaplayer, 并播放视频。
mMediaPlayer = new MediaPlayer();......mMediaPlayer.setSubtitleAnchor(controller, this);......mMediaPlayer.setOnPreparedListener(mPreparedListener);mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);mMediaPlayer.setOnCompletionListener(mCompletionListener);mMediaPlayer.setOnErrorListener(mErrorListener);mMediaPlayer.setOnInfoListener(mInfoListener);mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);mCurrentBufferPercentage = 0;mMediaPlayer.setDataSource(mContext, mUri, mHeaders);mMediaPlayer.setDisplay(mSurfaceHolder);mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mMediaPlayer.setScreenOnWhilePlaying(true);mMediaPlayer.prepareAsync();
一 MeidiaPlayer 初始化
MediaPlayer 对象以JNI 的方式与 库函数进行交互, MediaPlayer 对象的native 方法在android_media_MediaPlayer.cpp中实现。
以下是MediaPlayer.java 中初始化对象的部分。
static { System.loadLibrary("media_jni"); native_init(); }
public MediaPlayer() { super(new AudioAttributes.Builder().build()); Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else if ((looper = Looper.getMainLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else { mEventHandler = null; } mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ native_setup(new WeakReference<MediaPlayer>(this)); }1) 静态代码块加载media_jni 库, 它会直接调用android_media_MediaPlayer.cpp中init() 方法.
2) MediaPlayer 构造函数 初始化一个Handler 接收底层库函数返回的消息。
然后调用android_media_MediaPlayer.cpp的android_media_MediaPlayer_native_setup方法。
MediaPlayer 和android_media_MediaPlayer.cpp 函数的对应关系如下。
JNI 的介绍请参考我的博文“JNI 与JNIEvn”(http://blog.csdn.net/shizhonghuo19870328/article/details/52402526)
static const JNINativeMethod gMethods[] = { { "nativeSetDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" "[Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSourceAndHeaders }, {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, {"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback }, {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, {"_prepare", "()V", (void *)android_media_MediaPlayer_prepare}, {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, {"_start", "()V", (void *)android_media_MediaPlayer_start}, {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams}, {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams}, {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams}, {"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer_getSyncParams}, {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, {"_release", "()V", (void *)android_media_MediaPlayer_release}, {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, {"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType}, {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer},};
1. android_media_MediaPlayer_native_init(JNIEnv *env)
此方法主要是获得一些C库中需要用到的java 层的参数和方法句柄。
如: fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
2. android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
此方法功能是工厂模式建立指针sp<MediaPlayer>指向MediaPlayer.cpp,android_media_MediaPlayer.cpp的多媒体控制方法都是调用sp<MediaPlayer>实现。
二 获得服务,设置播放资源。
以 android_media_MediaPlayer_setDataSourceFD 为例。 此方法也是调用MediaPlayer.cpp 的setDataSource 方法,如下所以:
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length){ ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService> service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(fd, offset, length))) { player.clear(); } err = attachNewPlayer(player); } return err;}
IMediaDeathNotifier::getMediaPlayerService(){ ALOGV("getMediaPlayerService"); Mutex::Autolock _l(sServiceLock); if (sMediaPlayerService == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { binder = sm->getService(String16("media.player")); if (binder != 0) { break; } ALOGW("Media player service not published, waiting..."); usleep(500000); // 0.5 s } while (true); if (sDeathNotifier == NULL) { sDeathNotifier = new DeathNotifier(); } binder->linkToDeath(sDeathNotifier); sMediaPlayerService = interface_cast<IMediaPlayerService>(binder); } ALOGE_IF(sMediaPlayerService == 0, "no media player service!?"); return sMediaPlayerService;}
1. 用Bind 方法获得进程的MediaPlayerService 服务(MediaPlayerService.cpp)
请参考我的文章“Bind实现进程间通信”(http://blog.csdn.net/shizhonghuo19870328/article/details/53128133)。
首先获得 用以下语句从BinderDriver获得IBinder 对象,
binder = sm->getService(String16("media.player"));
然后将IBinder 转化为MediaPlayerService。
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){ return INTERFACE::asInterface(obj);}
以下代码向BinderDriver 注册 MediaPlayerService 服务 的过程。
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
以上代码是向BinderDriver 注册 MediaPlayerService 服务 的过程。
2. 建立本地播放器
调用MediaPlayerService 去建立本地播放器。 attachNewPlayer(player)方法将建立的本地播放器保存。
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId){ pid_t pid = IPCThreadState::self()->getCallingPid(); int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client( this, pid, connId, client, audioSessionId, IPCThreadState::self()->getCallingUid()); ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid, IPCThreadState::self()->getCallingUid()); wp<Client> w = c; { Mutex::Autolock lock(mLock); mClients.add(w); } return c;}看一下client 的声明,
class Client : public BnMediaPlayer { // IMediaPlayer interface virtual void disconnect(); virtual status_t setVideoSurfaceTexture( const sp<IGraphicBufferProducer>& bufferProducer); virtual status_t prepareAsync(); virtual status_t start(); virtual status_t stop(); virtual status_t pause(); virtual status_t isPlaying(bool* state); virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate); virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */); virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint); virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */, float* videoFps /* nonnull */); 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 setAudioStreamType(audio_stream_type_t type); virtual status_t setLooping(int loop); virtual status_t setVolume(float leftVolume, float rightVolume); virtual status_t invoke(const Parcel& request, Parcel *reply); virtual status_t setMetadataFilter(const Parcel& filter); virtual status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply); virtual status_t setAuxEffectSendLevel(float level); virtual status_t attachAuxEffect(int effectId); virtual status_t setParameter(int key, const Parcel &request); virtual status_t getParameter(int key, Parcel *reply); virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint); virtual status_t getRetransmitEndpoint(struct sockaddr_in* endpoint); virtual status_t setNextPlayer(const sp<IMediaPlayer>& player); sp<MediaPlayerBase> createPlayer(player_type playerType); virtual status_t setDataSource( const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setDataSource(const sp<IStreamSource> &source); virtual status_t setDataSource(const sp<IDataSource> &source); sp<MediaPlayerBase> setDataSource_pre(player_type playerType); void setDataSource_post(const sp<MediaPlayerBase>& p, status_t status); static void notify(void* cookie, int msg, int ext1, int ext2, const Parcel *obj); pid_t pid() const { return mPid; } virtual status_t dump(int fd, const Vector<String16>& args); audio_session_t getAudioSessionId() { return mAudioSessionId; }Client 继承了BnMediaPlayer,也就是本地播放器。同时Client 声明了所有的播放处理方法。
mediaplayer.cpp 中的播放处理方法调用的都是Client 中对应的方法。
三 设置播放资源
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length){ ALOGV("setDataSource fd=%d, offset=%" PRId64 ", length=%" PRId64 "", fd, offset, length); struct stat sb; int ret = fstat(fd, &sb); if (ret != 0) { ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno)); return UNKNOWN_ERROR; } ALOGV("st_dev = %" PRIu64 "", static_cast<uint64_t>(sb.st_dev)); ALOGV("st_mode = %u", sb.st_mode); ALOGV("st_uid = %lu", static_cast<unsigned long>(sb.st_uid)); ALOGV("st_gid = %lu", static_cast<unsigned long>(sb.st_gid)); ALOGV("st_size = %" PRId64 "", sb.st_size); if (offset >= sb.st_size) { ALOGE("offset error"); return UNKNOWN_ERROR; } if (offset + length > sb.st_size) { length = sb.st_size - offset; ALOGV("calculated length = %" PRId64 "\n", length); } player_type playerType = MediaPlayerFactory::getPlayerType(this, fd, offset, length); sp<MediaPlayerBase> p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } // now set data source setDataSource_post(p, p->setDataSource(fd, offset, length)); return mStatus;}其主体部分其实就是setDataSource_pre 和 setDataSource_post(p, p->setDataSource(fd, offset, length))。
1. 建立具体播放器
设置播放资源之前需要根据资源类别建立具体的播放器。
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( player_type playerType){ ALOGV("player type = %d", playerType); // create the right type of player sp<MediaPlayerBase> p = createPlayer(playerType); if (p == NULL) { return p; } sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("media.extractor")); mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH); binder->linkToDeath(mExtractorDeathListener); binder = sm->getService(String16("media.codec")); mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH); binder->linkToDeath(mCodecDeathListener); if (!p->hardwareOutput()) { Mutex::Autolock l(mLock); mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), mPid, mAudioAttributes); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } return p;}
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType){ // determine if we have the right player type sp<MediaPlayerBase> p = mPlayer; if ((p != NULL) && (p->playerType() != playerType)) { ALOGV("delete player"); p.clear(); } if (p == NULL) { p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid); } if (p != NULL) { p->setUID(mUID); } return p;}
利用工厂模式建立具体播放器。 每一种playerType 对应一种MediaplayerFactory, 每一种MediaplayerFactory 建立一种MediaPlayer.
class StagefrightPlayerFactory : public MediaPlayerFactory::IFactory { public:...... virtual sp<MediaPlayerBase> createPlayer() { ALOGV(" create StagefrightPlayer"); return new StagefrightPlayer(); }......
这里我们用StagefrightPlayer为例。
2. 调用具体mediaPlayer 设置播放资源
setDataSource_post(p, p->setDataSource(fd, offset, length));
其实从程序中可以看到,Client 是本地播放器的一个总的接口,所有播放处理方法都需要调用具体的播放器去完成。
所以client::setDataSource() 最后会调用StagefrightPlayer::setDataSource()
从StagefrightPlayer 的构造器可以看到,StagefrightPlayer 中包含一个私有对象AwesomePlayer *mplayer。 AwesomePlayer 是Stagefright 的核心。 大部分Stagefright Player的播放处理方法都要调用AwesomePlayer去实现。
StagefrightPlayer::StagefrightPlayer() : mPlayer(new AwesomePlayer) { ALOGV("StagefrightPlayer"); mPlayer->setListener(this);}
status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) { ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); return mPlayer->setDataSource(dup(fd), offset, length);}0 0
- MediaPlayer/MediaPlayer 视频播放
- MediaPlayer播放网络视频
- mediaplayer播放视频
- Android 视频播放 MediaPlayer
- MediaPlayer播放网络视频
- MediaPlayer播放网络视频
- 使用MediaPlayer播放视频
- mediaPlayer+surefacce播放视频
- Android mediaPlayer 播放视频
- Android MediaPlayer播放视频
- MediaPlayer实现视频播放
- MediaPlayer 视频播放
- MediaPlayer视频播放
- MediaPlayer之视频播放
- android mediaplayer 播放 视频 【转】
- android Mediaplayer 播放音视频
- (ios实战)MediaPlayer播放视频
- 使用MediaPlayer来播放视频
- js定时器
- JNI的使用
- JAVA面试 不使用API情况下,把数字字符串转换成int类型
- js中=,==和===的区别
- Java内存泄露原因详解
- MediaPlayer 视频播放
- 使用PyQt来编写第一个Python GUI程序
- spring切面的实现原理
- sql语句 创建数据库,表与删除数据库,表
- Js_函数的补充
- 使用maven创建web项目
- 小波的秘密9_图像处理应用:图像增强
- 16.11.7
- navicat 快捷键