Android的MediaPlayer架构介绍

article/2025/10/2 0:06:43
本文主要介绍的是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的架构。对于Android这样一个完整又相对复杂的系统,一个MediaPlayer功能的实现不在其具体的功能,而是具体功能如何适应Android系统Android MediaPlayer的主要具体实现在OpenCore的Player中,这部分不是本文的关注点。本文关注的是MediaPlayer系统的架构,其他的一些Android的应用程序也使用类似的架构。

第一部分 MediaPlayer概述
    Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的。
     MediaPlayer在底层是基于 OpenCore(PacketVideo)的库实现的,为了构建一个MediaPlayer程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。
    以开源的Android为例, 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/
    文件为mediaplayerservice.h和mediaplayerservice.cpp
    这部分内容被编译成库 libmediaplayerservice.so
     基于OpenCore的多媒体播放器部分 
    external/opencore/

    这部分内容被编译成库 libopencoreplayer.so

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

第二部分 MediaPlayer的接口与架构
2.1 整体框架图

    MediaPlayer的各个库之间的结构比较复杂,可以用下图的表示


    在各个库中,libmedia.so位于核心的位置,它对上层的提供的接口主要是MediaPlayer类,类libmedia_jni.so通过调用MediaPlayer类提供对JAVA的接口,并且实现了android.media.MediaPlayer类。
    libmediaplayerservice.so是Media的服务器,它通过继承libmedia.so的类实现服务器的功能,而libmedia.so中的另外一部分内容则通过进程间通讯和libmediaplayerservice.so进行通讯。libmediaplayerservice.so的真正功能通过调用OpenCore Player来完成。
    MediaPlayer部分的头文件在frameworks/base/include/media/目录中,这个目录是和libmedia.so库源文件的目录frameworks/base/media/libmedia/相对应的。主要的头文件有以下几个:
    IMediaPlayerClient.h
    mediaplayer.h 
    IMediaPlayer.h
    IMediaPlayerService.h
    MediaPlayerInterface.h


    在这些头文件mediaplayer.h提供了对上层的接口,而其他的几个头文件都是提供一些接口类(即包含了纯虚函数的类),这些接口类必须被实现类继承才能够使用。
    整个MediaPlayer库和调用的关系如下图所示:


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


2.2 头文件IMediaPlayerClient.h    
    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<IMediaPlayerClient>
{
public:virtual status_t  onTransact( uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags = 0);
};
    在定义中,IMediaPlayerClient类继承IInterface,并定义了一个MediaPlayer客户端的接口,BnMediaPlayerClient继承了BnInterface<IMediaPlayerClient>,这是为基于Android的基础类Binder机制实现在进程通讯而构建的。事实上,根据BnInterface类模版的定义BnInterface<IMediaPlayerClient>类相当于双继承了BnInterface和ImediaPlayerClient。这是Android一种常用的定义方式。

2.3 头文件mediaplayer.h
    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>& surface);status_t    setListener(const sp<MediaPlayerListener>& 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<IMemory>    decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);static    sp<IMemory>    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<IBinder>& who);
};
    事实上,MediaPlayer类正是间接地继承了IBinder,而MediaPlayer:: DeathNotifier类继承了IBinder:: DeathRecipient,这都是为了实现进程间通讯而构建的。

2.4 头文件IMediaPlayer.h
    IMediaPlayer.h主要的的内容是一个实现MediaPlayer功能的接口,它的主要定义如下所示:
class IMediaPlayer: public IInterface
{
public:DECLARE_META_INTERFACE(MediaPlayer);virtual void    disconnect() = 0;virtual status_t    setVideoSurface(const sp<ISurface>& 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<IMediaPlayer>
{
public:virtual status_t    onTransact( uint32_t code,const Parcel& data,    Parcel* reply,uint32_t flags = 0);
};
    在IMediaPlayer类中,主要定义MediaPlayer的功能接口,这个类必须被继承才能够使用。值得注意的是,这些接口和MediaPlayer类的接口有些类似,但是它们并没有直接的关系。事实上,在MediaPlayer类的各种实现中,一般都会通过调用IMediaPlayer类的实现类来完成。

2.5 头文件IMediaPlayerService.h
    IMediaPlayerService.h用于描述一个MediaPlayer的服务,定义方式如下所示:
class IMediaPlayerService: public IInterface
{
public:DECLARE_META_INTERFACE(MediaPlayerService);virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0;virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0;
};
class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
{
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>,这个IMediaPlayer正是提供实现功能的接口。


第三部分 MediaPlayer的主要实现分析

3.1 JAVA程序部分

    在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 MediaPlayer的JAVA本地调用部分
    MediaPlayer的JAVA本地调用部分在目录frameworks/base/media/jni/的android_media_MediaPlayer.cpp中的文件中实现。
    android_media_MediaPlayer.cpp之中定义了一个JNINativeMethod(JAVA本地调用方法)类型的数组gMethods,如下所示:
static JNINativeMethod gMethods[] = {{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},{"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},{"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},{"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},{"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
}
    JNINativeMethod的第一个成员是一个字符串,表示了JAVA本地调用方法的名称,这个名称是在JAVA程序中调用的名称;第二个成员也是一个字符串,表示JAVA本地调用方法的参数和返回值;第三个成员是JAVA本地调用方法对应的C语言函数。
    其中android_media_MediaPlayer_reset函数的实现如下所示:
static void android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
{sp<MediaPlayer> mp = getMediaPlayer(env, thiz);if (mp == NULL ) {jniThrowException(env, "java/lang/IllegalStateException", NULL);return;}process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
}
    在android_media_MediaPlayer_reset的调用中,得到一个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 mediaplayer的核心库libmedia.so
    libs/media/mediaplayer.cpp文件用于实现mediaplayer.h提供的接口,其中一个重要的片段如下所示:
const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
{Mutex::Autolock _l(mServiceLock);if (mMediaPlayerService.get() == 0) {sp<IServiceManager> sm = defaultServiceManager();sp<IBinder> 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<IMediaPlayerService>(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<IMediaPlayerService>& service(getMediaPlayerService());if (service != 0) {sp<IMediaPlayer> player(service->create(getpid(), this, url));err = setDataSource(player);}}return err;
}
    在函数setDataSource函数中,调用getMediaPlayerService得到了一个IMediaPlayerService,又从IMediaPlayerService中得到了IMediaPlayer类型的指针,通过这个指针进行着具体的操作。
    其他一些函数的实现也与setDataSource类似。
    libmedia.so中的其他一些文件与头文件的名称相同,它们是:
    libs/media/IMediaPlayerClient.cpp
    libs/media/IMediaPlayer.cpp
    libs/media/IMediaPlayerService.cpp 

    为了实现Binder的具体功能,在这些类中还需要实现一个BpXXX的类,例如IMediaPlayerClient.cpp的实现如下所示:l
class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
{
public:BpMediaPlayerClient(const sp<IBinder>& impl): BpInterface<IMediaPlayerClient>(impl){}virtual void notify(int msg, int ext1, int ext2){Parcel data, reply;data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());data.writeInt32(msg);data.writeInt32(ext1);data.writeInt32(ext2);remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);}
};
    还需要实现定义宏IMPLEMENT_META_INTERFACE,这个宏将被展开,生成几个函数:
IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
    以上的实现都是基于Binder框架的实现方式,只需要按照模版实现即可。其中BpXXX的类为代理类(proxy),BnXXX的类为本地类(native)。代理类的transact函数和本地类的onTransact函数实现对应的通讯。

3.4 media服务libmediaservice.so
    frameworks/base/media\libmediaplayerservice目录中的MediaPlayerService.h和MediaPlayerService.cpp用于实现一个
servers/media/的服务,MediaPlayerService是继承BnMediaPlayerService的实现,在这个类的内部又定义了类Client,MediaPlayerService::Client继承了BnMediaPlayer。
    class MediaPlayerService : public BnMediaPlayerService{class Client : public BnMediaPlayer}
    在MediaPlayerService中具有如下一个静态函数instantiate:
    void MediaPlayerService::instantiate() {defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());}
    在instantiate函数中,调用IServiceManager的一个函数addService,向其中增加了一个名为"media.player"的服务。
    这个名为"media.player"的服务和mediaplayer.cpp中调用getService中得到的使用一样名称。因此,在这里调用addService增加服务在mediaplayer.cpp中可以按照名称"media.player"来使用。这就是使用Binder实现进程间通讯的(IPC)的作用,事实上这个MediaPlayerService类是在服务中运行的,而mediaplayer.cpp调用的功能在应用中运行,二者并不是一个进程。但是在mediaplayer.cpp却像一个进程的调用一样调用MediaPlayerService的功能。
    在MediaPlayerService.cpp中的createPlayer函数如下所示:
static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc)
{sp<MediaPlayerBase> p;switch (playerType) {case PV_PLAYER:LOGV(" create PVPlayer");p = new PVPlayer();break;case SONIVOX_PLAYER:LOGV(" create MidiFile");p = new MidiFile();break;case VORBIS_PLAYER:LOGV(" create VorbisPlayer");p = new VorbisPlayer();break;}//……return p;
}
    在这里根据playerType的类型建立不同的播放器:对于大多数情况,类型将是PV_PLAYER,这时会调用了new PVPlayer()建立一个PVPlayer,然后将其指针转换成MediaPlayerBase来使用;对于Mini文件的情况,类型为SONIVOX_PLAYER,将会建立一个MidiFile;对于Ogg Vorbis格式的情况,将会建立一个VorbisPlayer。
    (OGG Vobis是一种音频压缩格式,与MP3等的音乐格式类似,它具有完全免费、开放和没有专利限制的特点。)
    值得注意的是PVPlayer、MidiFile和VorbisPlayer三个类都是继承MediaPlayerInterface得到的,而MediaPlayerInterface又是继承MediaPlayerBase得到的,因此三者具有相同接口类型。只有建立的时候会调用各自的构造函数,在建立之后,将只通过MediaPlayerBase接口来MediaPlayerBase控制它们。
    在frameworks/base/media/libmediaplayerservice目录中,MidiFile.h和MidiFile.cpp的实现MidiFile,VorbisPlayer.h和VorbisPlayer.cpp实现一个VorbisPlayer。

3.5 OpenCorePlayer的实现libopencoreplayer.so 
    OpenCore Player在external/opencore/中实现,这个实现是一个基于OpenCore的Player的实现。具体实现的文件为playerdriver.cpp。其中实现了两个类:PlayerDriver和PVPlayer。PVPlayer通过调用PlayerDriver的函数实现具体的功能。


http://chatgpt.dhexx.cn/article/10GjKjuS.shtml

相关文章

Android之MediaPlayer详解

文章转自&#xff1a;http://www.cnblogs.com/gansc23/archive/2011/04/08/2009868.html MediaPlayer类可用于控制音频/视频文件或流的播放。关于如何使用这个类的方法还可以阅读VideoView类的文档。 1&#xff0e;状态图 对播放音频/视频文件和流的控制是通过一个状态机来…

Android MediaPlayer播放视频详细步骤

MediaPlayer类是媒体框架最重要的组成部分之一&#xff0c;此类的对象能够获取&#xff0c;解码以及播放音频和视频&#xff0c;而且只需极少量设置&#xff0c;它支持多种不同的媒体源&#xff0c;例如&#xff1a; 本地资源 内部Url&#xff0c;例如您可能从内容解析器获取U…

Android MediaPlayer

最近在做游戏状态的保存时&#xff0c;需要存储背景音乐是否静音了&#xff0c;一直不成功&#xff0c;并且总是报出如下错误&#xff1a; ERROR/MediaPlayer(9974): start called in state 64 ERROR/MediaPlayer(9974): error (-38, 0) ERROR/MediaPlayer(9974): Error (-38…

MediaPlayer类播放音频

一、MediaPlayer类 1、常用方法 方法名称功能setDataSource()设置要播放的音频文件prepare()在开始播放前。调用该方法准备播放start()开始播放或者继续播放音频pause()暂停播放reset()重置MediaPlayer对象seekTo()从指定位置播放stop()停止播放&#xff0c;调用后MediaPlaye…

Android提高第一篇之MediaPlayer

本文来自http://blog.csdn.net/hellogv/ &#xff0c;引用必须注明出处&#xff01; 前面写了十四篇关于界面的入门文章&#xff0c;大家都看完和跟着练习之后&#xff0c;对于常用的Layout和View都会有一定的了解了,接下来的文章就不再强调介绍界面了&#xff0c;而是针对具体…

Android中的MediaPlayer的使用详解

今天本文介绍的是Andriod系统自带的Mediaplayer,和VideoView实现简单的音乐和视频的播放&#xff0c;至于想做出如酷狗音乐这样的APP的话&#xff0c;只要想做&#xff0c;应该也不难&#xff0c;都是基于此实现了功能的扩展。 Android的MediaPlayer包含了Audio和Video的播放功…

MediaPlayer详解和使用

Android多媒体相关的API&#xff0c;网上基本都能找到很多相关的文章&#xff0c;使用起来也很简单&#xff0c;一直在犹豫要不要写这方面的内容&#xff0c;后来决定还是写一写&#xff0c;一方面算是一个归纳总结&#xff0c;另一方面&#xff0c;也方便以后查阅。这一篇就写…

MediaPlayer的使用

MediaPlayer的使用 MediaPlayer的使用&#xff08;2019.07.16&#xff09;1.视频播放器的原理2.Android系统自带的MediaPlay状态机详解&#xff08;MediaPlay的生命周期&#xff09;3.如何使用MediaPlayer播放音频与视频&#xff08;一 &#xff09;播放音频&#xff08;二&…

MediaPlayer使用以及常见问题

前面已经写过一篇类似的文章&#xff0c;但是还不够细致&#xff1a; 采用Android的MediaPlayerSurfaceView设计视频播放器 这里我们重新理一下&#xff0c;并记录一点实际运用时遇到的问题。 MediaPlayer特性 MediaPlayer类用于控制音频文件、视频文件和流的播放。 Media…

Android MediaPlayer类

1. MediaPlayer方法 MediaPlayer创建 可以直接调用构造函数&#xff0c;利用setDataSource()方法设置资源。MediaPlayer mp new MediaPlayer(); // path可以是本地路径&#xff0c;也可以是网络地址 mp.setDataSource(String path);也可以调用create()方法&#xff0c;create…

MediaPlayer状态图及生命周期

MediaPlayer状态图及生命周期 MediaPlayer是Android中的uoge多媒体播放类&#xff0c;我们能通过它控制音视频流或本地音视频资源的播放过程。 这一片博客主要介绍MediaPlayer状态图及生命周期。先看一张官网很经典的MediaPlayer状态机的图片。 其中椭圆代表MediaPlayer驻留…

Android 使用MediaPlayer播放音频详解

目录 一、官方资料 二、简单介绍 三、MediaPlayer使用 1.创建MediaPlayer实例 2.重要API 3.状态图 4.代码 5.常用API 6.辅助效果 总结 一、官方资料 MediaPlayer 概览https://developer.android.google.cn/guide/topics/media/mediaplayer?hlzh_cn MediaPlayer 文…

Android -- 多媒体播放之MediaPlayer基础简介

Android -- MediaPlayer基础简介 MediaPlayer是Android中的一个多媒体播放类&#xff0c;我们能通过它控制音视频流或本地音视频资源的播放过程。 这段时间查阅了Android官方文档对MediaPlayer的介绍&#xff0c;同时也看了一些书籍介绍。现在把MediaPlayer的基础内容在此做一…

网易雷火9.18笔试题

3小时的题 我迟到了1个小时&#xff0c;提前了40分钟润&#xff0c;花了1个小时20分钟&#xff08;中途有点其他事&#xff09;&#xff0c;a了2道&#xff0c;第三题没思路&#xff0c;第4题不想看&#xff0c;就这样吧 #include <iostream> using namespace std; int…

网易笔试题总结

var string string; var number 0; var bool true; console.log(number || string); console.log(number && string); console.log(bool || number); console.log(bool && number); 输出结果 如果换下string和num的位置呢 var string string1; var numbe…

网易2019笔试题

1.苹果分堆 计算累加小组成员数&#xff0c;结合二分查找&#xff0c;复杂度O( min(n, mlogn) ) package wangyi123;import java.util.Scanner;public class groupNum {public static void main(String[] args) {Scanner sc new Scanner(System.in);while (sc.hasNext()) {i…

2022-08-20-网易笔试题

写在前面 题目收集来源自网络&#xff0c;前四题是开发岗的&#xff0c;后四题是算法岗的&#xff0c;因为代码无处提交&#xff0c;不一定正确&#xff0c;就不贴出来了&#xff0c;这里只写一下我的思路吧~欢迎大家一起讨论~~ 1、 思路&#xff1a;因为最大1e9&#xff0c…

网易游戏策划笔试-20190404

1-7题为文案题&#xff08;答题时请勿参考其他作品&#xff09;&#xff0c;8-23题为数值系统题&#xff0c; 两个方向分别计算分数&#xff0c;最终选择分数更高的方向作为最终成绩&#xff0c;建议优先选择自己擅长或感兴趣的方向进行答题。 8、&#xff08;无需过程&#xf…

JESD204接口调试总结——JESD204+In-system-ibert

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 JESD204接口调试总结——JESD204In-system-ibert 前言IP核的设置IP核连线调试jtag界面总结 前言 之前我们在讲serdes的时候讲到了使用in-system-ibert来进行眼图的扫描&…

JESD204B IP核的配置与使用

一、JESD204 配置方式&#xff1a; Configuration 1、Transmit or Receive: 选择是作为接收机还是发射机 2、LFMC : 默认值 3、Number of lanes : 传输的通道数&#xff0c;根据实际需求选择 4、pattern&#xff1a;模式的选择&#xff0c;正常情况下两个都不选 5、clocki…