首页编程androidmediaplayer?安卓开发实现两个mediaplayer同时播放

androidmediaplayer?安卓开发实现两个mediaplayer同时播放

编程之家2023-11-0840次浏览

大家好,今天小编来为大家解答以下的问题,关于androidmediaplayer,安卓开发实现两个mediaplayer同时播放这个很多人还不知道,现在让我们一起来看看吧!

androidmediaplayer?安卓开发实现两个mediaplayer同时播放

android为什么都使用service播放mediaplayer

你所说的关闭activity其实是默认在后台执行的,所以你的音乐会一直运行,但是如果我要求关闭activity后直接从系统进程中去除的话,那就不会在听到你的音乐了。为什么要开一个service,这个大部分人倾向于这样做的,一般的编程模式mvc,大部分人都倾向于把服务性质的功能放到后台去运行。service也有它特定的功能,可以与activity分离同步进行,也可以单独进行。

安卓开发实现两个mediaplayer同时播放

Android的MediaPlayer包含了Audio和video的播放功能

关于MediaPlayer的使用方式:

1.如何获得MediaPlayer实例:

可以使用直接new的方式:

MediaPlayer mp= new MediaPlayer();

androidmediaplayer?安卓开发实现两个mediaplayer同时播放

也可以使用create的方式,如:

MediaPlayer mp= MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了

2.如何设置要播放的文件:

MediaPlayer要播放的文件主要包括3个来源:

a.用户在应用中事先自带的resource资源

例如:MediaPlayer.create(this, R.raw.test);

androidmediaplayer?安卓开发实现两个mediaplayer同时播放

b.存储在SD卡或其他文件路径下的媒体文件

例如:mp.setDataSource("/sdcard/test.mp3");

c.网络上的媒体文件

例如:mp.setDataSource("mp3或者mp4的地址");

3.MediaPlayer常用API

MediaPlayer的setDataSource一共四个方法:

setDataSource(String path)

setDataSource(FileDescriptor fd)

setDataSource(Context context, Uri uri)

setDataSource(FileDescriptor fd, long offset, long length)

4.对播放器的主要控制方法:

Android通过控制播放器的状态的方式来控制媒体文件的播放,其中:

1.prepare()和prepareAsync()提供了同步和异步两种方式设置播放器进入prepare状态,需要注意的是,如果MediaPlayer实例是由create方法创建的,那么第一次启动播放前不需要再调用prepare()了,因为create方法里已经调用过了。

2. start()是真正启动文件播放的方法。

3.pause()和stop()比较简单,起到暂停和停止播放的作用。

4.seekTo()是定位方法,可以让播放器从指定的位置开始播放,需要注意的是该方法是个异步方法,也就是说该方法返回时并不意味着定位完成,尤其是播放的网络文件,真正定位完成时会触发OnSeekComplete.onSeekComplete(),如果需要是可以调用setOnSeekCompleteListener(OnSeekCompleteListener)设置监听器来处理的。

5.release()可以释放播放器占用的资源,一旦确定不再使用播放器时应当尽早调用它释放资源。

6.reset()可以使播放器从Error状态中恢复过来,重新会到Idle状态。

android.media.AsyncPlayer这个类应该怎么用

代码结构:

Open Core的代码在Android代码的 External/Opencore目录中。这个目录是OpenCore

的根目录,其中包含的子目录如下所示:

android:这里面是一个上层的库,它实现了一个为Android使用的音视频采集,播放的接口,和DRM数字版权管理的接口实现。

baselibs:包含数据结构和线程安全等内容的底层库

codecs_v2:音视频的编解码器,基于 OpenMAX实现

engines:核心部分,多媒体引擎的实现

extern_libs_v2:包含了 khronos的 OpenMAX的头文件

fileformats:文件格式的解析( parser)工具

nodes:提供一些PVMF的NODE,主要是编解码和文件解析方面的。

oscl:操作系统兼容库

pvmi:输入输出控制的抽象接口

protocols:主要是与网络相关的 RTSP、 RTP、 HTTP等协议的相关内容

pvcommon: pvcommon库文件的 Android.mk文件,没有源文件。

pvplayer: pvplayer库文件的 Android.mk文件,没有源文件。

pvauthor: pvauthor库文件的 Android.mk文件,没有源文件。

tools_v2:编译工具以及一些可注册的模块。

本文主要介绍Android MediaPlayer的架构,主要由OpenCore里的PV Player来实现的。

1.概述

Android的MediaPlayer包含了Audio和Video的播放功能,Music和Video两个应用程序都是调用MediaPlayer实现的。

代码主要分布在以下的目录中:

JAVA程序的路径:

packages/apps/Music/src/com/android/music/

JAVA类的路径:

frameworks/base/media/java/android/media/MediaPlayer.java

JAVA本地调用部分(JNI):

frameworks/base/media/jni/android_media_MediaPlayer.cpp

编译为 libmedia_jni.so

头文件:

frameworks/base/include/media/

多媒体库:

frameworks/base/media/libmedia/

编译为 libmedia.so

多媒体服务:

frameworks/base/media/libmediaplayerservice/

编译为 libmediaplayerservice.so

具体实现:

external/opencore/

编译为 libopencoreplayer.so

libopencoreplayer.so是主要的实现部分,其他的库基本上都是在其上建立的封装和为建立进程间通讯的机制。

2.框架

在各个库中,libmedia.so位于核心的位置,它对上层的提供的接口主要是MediaPlayer类,libmedia_jni.so通过调用MediaPlayer类提供对JAVA的接口,并且实现了android.media.MediaPlayer类。

libmediaplayerservice.so是Media的服务器,它通过继承libmedia.so的类实现服务器的功能,而libmedia.so中的另外一部分内容则通过进程间通讯和libmediaplayerservice.so进行通讯。libmediaplayerservice.so的真正功能通过调用PV

Player来完成。

MediaPlayer部分的头文件在frameworks/base/include/media/目录中,这个目录是和libmedia.so库源文件的目录frameworks/base/media/libmedia/相对应的。主要的头文件有以下几个:

IMediaPlayer.h

IMediaPlayerClient.h

IMediaPlayerService.h

mediaplayer.h

MediaPlayerInterface.h

mediaplayer.h提供了对上层的接口,而其他的几个头文件都是提供一些接口类(即包含了纯虚函数的类),这些接口类必须被实现类继承才能够使用。

整个MediaPlayer库和调用的关系如下图所示:

运行的时候,大致可以分成Client和Server两个部分,分别在两个进程中运行,使用Binder机制实现IPC通讯。从框架结构上来看,IMediaPlayerService.h、IMediaPlayerClient.h和MediaPlayer.h三个类定义了MeidaPlayer的接口和架构,MediaPlayerService.cpp和mediaplayer.cpp两个文件用于MeidaPlayer架构的实现,MeidaPlayer的具体功能在PVPlayer(库libopencoreplayer.so)中的实现。

2.1 IMediaPlayerClient.h

描述一个MediaPlayer客户端的接口

class IMediaPlayerClient: public IInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayerClient);

virtual void notify(int msg, int ext1, int ext2)= 0;

};

class BnMediaPlayerClient: public BnInterface

{

public:

virtual status_t onTransact( uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags= 0);

};

在定义中,IMediaPlayerClient类继承IInterface,并定义了一个MediaPlayer客户端的接口,BnMediaPlayerClient继承了BnInterface,这是为基于Android的基础类Binder机制实现在进程通讯而构建的。事实上,根据BnInterface类模版的定义,BnInterface类相当于双继承了BnInterface和ImediaPlayerClient,这是Android一种常用的定义方式。

2.2 mediaplayer.h

对外的接口类,它最主要是定义了一个MediaPlayer类:

class MediaPlayer: public BnMediaPlayerClient

{

public:

MediaPlayer();

~MediaPlayer();

void onFirstRef();

void disconnect();

status_t setDataSource(const char*url);

status_t setDataSource(int fd, int64_t offset, int64_t length);

status_t setVideoSurface(const sp& surface);

status_t setListener(const sp& 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);

status_t setVolume(float leftVolume, float rightVolume);

void notify(int msg, int ext1, int ext2);

static sp decode(const char* url, uint32_t*pSampleRate, int*

pNumChannels);

static sp decode(int fd, int64_t offset, int64_t length, uint32_t

*pSampleRate, int* pNumChannels);

//……

}

从接口中可以看出MediaPlayer类刚好实现了一个MediaPlayer的基本操作,例如播放(start)、停止(stop)、暂停(pause)等。

另外的一个类DeathNotifier在MediaPlayer类中定义,它继承了IBinder类中的DeathRecipient类:

class DeathNotifier: public IBinder:: DeathRecipient

{

public:

DeathNotifier(){}

virtual~DeathNotifier();

virtual void binderDied(const wp& who);

};

事实上,MediaPlayer类正是间接地继承了IBinder,而MediaPlayer:: DeathNotifier类继承了IBinder::

DeathRecipient,这都是为了实现进程间通讯而构建的。

2.3 IMediaPlayer.h

主要的的内容是一个实现MediaPlayer功能的接口:

class IMediaPlayer: public IInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayer);

virtual void disconnect()= 0;

virtual status_t setVideoSurface(const sp& surface)= 0;

virtual status_t prepareAsync()= 0;

virtual status_t start()= 0;

virtual status_t stop()= 0;

virtual status_t pause()= 0;

virtual status_t isPlaying(bool* state)= 0;

virtual status_t getVideoSize(int* w, int* h)= 0;

virtual status_t seekTo(int msec)= 0;

virtual status_t getCurrentPosition(int* msec)= 0;

virtual status_t getDuration(int* msec)= 0;

virtual status_t reset()= 0;

virtual status_t setAudioStreamType(int type)= 0;

virtual status_t setLooping(int loop)= 0;

virtual status_t setVolume(float leftVolume, float rightVolume)= 0;

};

class BnMediaPlayer: public BnInterface

{

public:

virtual status_t onTransact( uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags= 0);

};

在IMediaPlayer类中,主要定义MediaPlayer的功能接口,这个类必须被继承才能够使用。值得注意的是,这些接口和MediaPlayer类的接口有些类似,但是它们并没有直接的关系。事实上,在MediaPlayer类的各种实现中,一般都会通过调用IMediaPlayer类的实现类来完成。

2.4头文件IMediaPlayerService.h

描述一个MediaPlayer的服务,定义方式如下所示:

class IMediaPlayerService: public IInterface

{

public:

DECLARE_META_INTERFACE(MediaPlayerService);

virtual sp create(pid_t pid, const

sp& client, const char* url)= 0;

virtual sp create(pid_t pid, const

sp& client, int fd, int64_t offset, int64_t length)=

0;

virtual sp decode(const char* url, uint32_t*pSampleRate, int*

pNumChannels)= 0;

virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t

*pSampleRate, int* pNumChannels)= 0;

};

class BnMediaPlayerService: public BnInterface

{

public:

virtual status_t onTransact( uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags= 0);

};

由于有纯虚函数,IMediaPlayerService

以及BnMediaPlayerService必须被继承实现才能够使用,在IMediaPlayerService定义的create和decode等接口,事实上是必须被继承者实现的内容。注意,create的返回值的类型是sp,这个IMediaPlayer正是提供实现功能的接口。

3实现

3.1 App

在packages/apps/Music/src/com/android/music/里的MediaPlaybackService.java文件中,包含了对MediaPlayer的调用。

在MediaPlaybackService.java中包含对包的引用:

import android.media.MediaPlayer;

在MediaPlaybackService类的内部,定义了MultiPlayer类:

private class MultiPlayer{

private MediaPlayer mMediaPlayer= new MediaPlayer();

}

MultiPlayer类中使用了MediaPlayer类,其中有一些对这个MediaPlayer的调用,调用的过程如下所示:

mMediaPlayer.reset();

mMediaPlayer.setDataSource(path);

mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

reset,setDataSource和setAudioStreamType等接口就是通过JAVA本地调用(JNI)来实现的。

3.2 Jni

在frameworks/base/media/jni/android_media_MediaPlayer.cpp中实现,其中android_media_MediaPlayer_reset函数的实现如下所示:

static void android_media_MediaPlayer_reset(JNIEnv*env, jobject thiz)

{

sp mp= getMediaPlayer(env, thiz);

if(mp== NULL){

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

return;

}

process_media_player_call( env, thiz, mp->reset(), NULL, NULL);

}

先获取一个MediaPlayer指针,通过对它的调用来实现实际的功能。

register_android_media_MediaPlayer用于将gMethods注册为的类"android/media/MediaPlayer",其实现如下所示。

static int register_android_media_MediaPlayer(JNIEnv*env)

{

jclass clazz;

clazz= env->FindClass("android/media/MediaPlayer");

//......

return AndroidRuntime::registerNativeMethods(env,

"android/media/MediaPlayer", gMethods, NELEM(gMethods));

}

"android/media/MediaPlayer"对应JAVA的类android.media.MediaPlayer。

3.3 libmedia.so

frameworks/base/media/libmedia/mediaplayer.cpp文件实现mediaplayer.h提供的接口,其中一个重要的片段如下所示:

const sp& MediaPlayer::getMediaPlayerService()

{

Mutex::Autolock _l(mServiceLock);

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

sp sm= defaultServiceManager();

sp binder;

do{

binder= sm->getService(String16("media.player"));

if(binder!= 0)

break;

LOGW("MediaPlayerService not published, waiting...");

usleep(500000);// 0.5 s

} while(true);

if(mDeathNotifier== NULL){

mDeathNotifier= new DeathNotifier();

}

binder->linkToDeath(mDeathNotifier);

mMediaPlayerService= interface_cast(binder);

}

LOGE_IF(mMediaPlayerService==0,"no MediaPlayerService!?");

return mMediaPlayerService;

}

其中最重要的一点是binder=

sm->getService(String16("media.player"));这个调用用来得到一个名称为"media.player"的服务,这个调用返回值的类型为IBinder,根据实现将其转换成类型IMediaPlayerService使用。

一个具体的函数setDataSource如下所示:

status_t MediaPlayer::setDataSource(const char*url)

{

LOGV("setDataSource(%s)", url);

status_t err= UNKNOWN_ERROR;

if(url!= NULL){

const sp& service(getMediaPlayerService());

if(service!= 0){

sp player(service->create(getpid(), this, url));

err= setDataSource(player);

}

}

return err;

}

关于androidmediaplayer,安卓开发实现两个mediaplayer同时播放的介绍到此结束,希望对大家有所帮助。

小程序示例(小程序在哪找啊)计算机程序设计艺术,计算机设计专业有哪些