毕业设计-AudioVideo(一)

时间:2021-03-10 06:46:14

即将毕业的我,选择了做一款基于Android的音视屏的的软件来作为毕业答卷。在后面我会持续更新,记录下这四年的最后时光^__^。

(一)音频部分

1.这里采用了Android中的MedioPlayer这个工具来对音乐进行播放。

2.运用Server和Receiver这两大组件来完成音乐的后台持续播放和UI的更新。

3.使用MediaMetadataRetriever该工具类来完成对本地音频文件的解析,获取音频的详细信息。

4.使用通知,将后台播放的音乐信息展示到通知栏。

5.音频的剪辑。

6.其他。

(二)视屏部分

1.SurfaceView结合MediaPlayer完成视屏的播放。

2.弹幕.

3.其他。

以上的功能还只是最初的计划,现在还在做,我也不大知道要加哪些功能,做到后面再不断添加。

项目结构

毕业设计-AudioVideo(一)

adapter:适配器相关

bean:数据承载类相关

config:全局常量相关

db:数据库相关

net:网络相关

receiver:广播相关

relect:反射工具相关

server:服务相关

ui:界面相关

util:工具类相关

widget:自定义View相关

网络相关

博客项目中的OkHttp工具(简单级别的)

服务相关

这里考虑到音乐播放是一个长时间的,不依赖于Activity的一种事件,所以我选择的是startServer()这种方式,该服务是独立的,不会与Activity关联的,地方Activity销毁或者pause的时候,服务任然在执行着。

广播相关

这里的广播,分为两种,一种是静态的,一种是动态的。有这样两种情景,一种时控制音乐的播放,暂停,下一曲,上一曲的这种交互需要设置成静态,当有音乐播放的时候就要有该广播,所以要为静态;一种是播放器的播放信息,例如当前歌曲的基本信息,这样的我觉得可以用动态的,当Activity创建的时候注册广播,当Activity销毁的时候就注销广播,这样就节省资源。

音频解析相关

  • TAG_V1部分是MP3文件的最后128byte的内容.期中包括的信息有:
    标签头”TAG” 3字节
    标题 30字节
    作者 30字节
    专辑 30字节
    出品年份 4字节
    备注信息 28字节
    保留 1字节
    音轨 1字节
    类型 1字节

方案一:

  private static void randomReadMusicBasicInfo(File file, List<Musicer> musicerList) {
try {
if (file == null || musicerList == null) return;
byte[] bytes = new byte[128];
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
int p = randomAccessFile.read() << 8 + randomAccessFile.read();
String code = "UTF-8";
byte[] b = new byte[3];
randomAccessFile.read(b);
if (b[0] == -17 && b[1] == -69 && b[2] == -65)
code = "UTF-8";
else
code = "GBK";
randomAccessFile.seek(file.length() - 128);
randomAccessFile.read(bytes);
randomAccessFile.close();
String tga = new String(bytes, 0, 3, code);
Musicer musicer = new Musicer();
musicer.setPath(file.getAbsolutePath());
musicer.setMusictitle(file.getName());
if ("TAG".equalsIgnoreCase(tga)) {
String musictitle = new String(bytes, 3, 30, code);
String author = new String(bytes, 33, 30, code);
String album = new String(bytes, 63, 30, code);
String year = new String(bytes, 93, 4, code);
String memo = new String(bytes, 97, 28, code);
String retain = new String(bytes, 125, 1, code);
String track = new String(bytes, 126, 1, code);
String type = new String(bytes, 127, 1, code);
musicer.setMusictitle(musictitle);
musicer.setAuthor(author);
musicer.setAlbum(album);
musicer.setYear(year);
musicer.setMemo(memo);
musicer.setRetain(retain);
musicer.setTrack(track);
musicer.setType(type);
}
musicerList.add(musicer);
} catch (Exception e) {
e.printStackTrace();
}
}

方案二:

private static void getMusicInfo(File file, List<Musicer> musicerList){
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
try
{
Musicer musicer = new Musicer();
musicer.setPath(file.getAbsolutePath());
musicer.setMusictitle(file.getName());
mmr.setDataSource(file.getAbsolutePath());
String title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
String album = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); // 播放时长单位为毫秒
byte[] pic = mmr.getEmbeddedPicture(); // 图片,可以通过BitmapFactory.decodeByteArray转换为bitmap图
musicer.setMusictitle(title);
musicer.setAuthor(artist);
musicer.setAlbum(album);
musicerList.add(musicer);
}
catch (Exception e)
{
e.printStackTrace();
}
}

这里可能是由于编码的问题和TAG的不统一档案已还存在问题,方案二好一些,这是Android内部实现的一个工具,源码里面是native方法,无法查看,这里也就不再深究。

沉浸状态栏

这里是在Android4.4以上才有效果,将状态栏设置为透明的,在将我们设置的contentView–root设置一个top方向的padding,这样就可以定制我们的状态栏背景了,但是不能兼容到Android4.4以下的版本,状态栏的高度我们可以通过反射拿到这个字段。

 protected  void initStatus(){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
root.setPadding(0,getStatusH(),0,0);
}

public int getStatusH(){
int statusBarHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusBarHeight = getResources().getDimensionPixelSize(height);
return statusBarHeight;
} catch (Exception e) {
e.printStackTrace();
}
return statusBarHeight;
}

返回键相关

大部分音乐播放器软件的back键是被修改了的,当点击返回键我们是不会退出应用的,而是返回到桌面。这样我们的后台音乐才能继续播放。当我们修改back事件后,我们Activity状态是被保存了,但是所有的Activity还是会启动一次,那我就让启动页设置为透明,选择性的跳转到start或者直接跳转到Index。

 @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Intent home = new Intent();
home.setAction(Intent.ACTION_MAIN);
home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
home.addCategory(Intent.CATEGORY_HOME);
startActivity(home);
BaseApplication.getInstance().setNeedStartActivity(false);
return false;
}
return super.onKeyUp(keyCode, event);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);
setContentView(R.layout.activity_start_controal);
if (BaseApplication.getInstance().isNeedStartActivity()){
startActivity(new Intent(this,StartActivity.class));
}else {
startActivity(new Intent(this,IndexPlayActivity.class));
}
finish();
}

通过上述思路,在我们按下back键的时候,应用会回到桌面,再次点击应用图标的时候,我们就会看到,我们的应用恢复到了按下back之前的状态。

好了,目前就这么多,项目地址:https://github.com/yzzAndroid/AudioVideo