毕业设计-AudioVideo(一)

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

(一)音频部分

1.这里采用了Android中的MedioPlayer这个工具来对音乐进行播放。
2.运用Server和Receiver这两大组件来完成音乐的后台持续播放和UI的更新。
3.使用MediaMetadataRetriever该工具类来完成对本地音频文件的解析,获取音频的详细信息。
4.使用通知,将后台播放的音乐信息展示到通知栏。
5.音频的剪辑。
6.其他。

(二)视屏部分

1.SurfaceView结合MediaPlayer完成视屏的播放。
2.弹幕.
3.其他。

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

项目结构

这里写图片描述

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

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值