纯JAVA实现MP4文件边下载边播放,论坛唯一解决方案,附带mp4info小工具

背景

客户提出有部分Mp4视频需要完全加载完才能播放,体验很差,尤其是视频相对较大网速不太好的时候,毕竟现在都是边下载边播放模式.导致这种情况出现的原因是有些Mp4文件中的moov信息在文件末尾.只要将moov信息移动到视频信息前面,前端就可以实现边下边放.
https://gitee.com/chenjin0827/mp4Demo.git

写了个demo给各位同学参考

https://gitee.com/chenjin0827/mp4Demo.git

大致介绍下Mp4的格式

MP4文件主要由ftyp,mdat,moov三部分组成。三部分的主要职责:

  1. ftyp ,记录了mp4格式,编码格式之类的一些基本信息;
  2. mdat,记录了视频媒体信息(mdat的体积往往非常的大,几乎等于MP4总大小);
  3. moov,如同检索表一样的存在,里面记录了每一帧对应的数据在哪里等等;

前期弯路

介绍下前期考虑的方案踩过的坑供大家参考,想直接看最终纯Java解决方案的可以跳过

  1. 使用ffmpeg处理 ffmpeg -i G:\Download\bad2.mp4 -c copy -movflags faststart -map_metadata -1 G:\Download\good2.mp4
    命令解释:
    -i 指定输入文件: G:\Download\bad2.mp4
    -c copy处理方式: 复制所有流而不重新编码 ,很重要,不加会被重新编码,输出文件可能会变大。
    -movflags faststart优化选项: 将 moov atom 移动到文件开头。
    -map_metadata -1元数据处理: 移除所有元数据,也可以轻微减小生成文件大小 。
    输出文件: G:\Download\good2.mp4
    说明:该命令可以实现Mp4文件的转换,实现边下边播.缺点就是需要在服务端安装ffmpeg工具,然后使用java命令调用它,不够轻量
  2. 使用python处理(未进行尝试,各位同学自行体会)
  3. 前期使用java版本踩坑
	<dependency>
        <groupId>com.googlecode.mp4parser</groupId>
        <artifactId>isoparser</artifactId>
        <version>1.1.22</version>
    </dependency>

上面是旧版本,推荐使用迁移后的新版本,见下方

使用mp4parser完成Mp4的转换

原理就是读入Mp4,重新生成个,新生成的默认moov在前面

  1. 导入包
   	<dependency>
           <groupId>org.mp4parser</groupId>
           <artifactId>muxer</artifactId>
           <version>1.9.27</version>
       </dependency>
  1. 这里传入的MultipartFile 是来自SpringMVC传入来的值,返回的byte可以生成文件,各位同学自行处理
 private byte[] generateNewMp4(MultipartFile file) {
   
        File outPutFile = null;
        // 创建临时文件
        File convFile = null;
        List<Track> tracks = new ArrayList<>();
        try {
   
            outPutFile = File.createTempFile("tempOut", file.getOriginalFilename());
            convFile = File.createTempFile("tempIn", file.getOriginalFilename());
            file.transferTo(convFile);
            // 创建Movie对象 CustomMovieCreator是自定义,后面讲为什么
            Movie movie = CustomMovieCreator.build(convFile.getPath());
            // 获取所有轨道
            tracks = movie.getTracks();
            // 创建一个新的Movie对象
            Movie newMovie = new Movie();
            for (Track track : tracks) {
   
                newMovie.addTrack(track);
            }
            // 构建 MP4 文件
            try (FileOutputStream fos = new FileOutputStream(outPutFile);
                 FileChannel fc2 = fos.getChannel()) {
   
                 //这里有个坑,要使用FragmentedMp4Builder,不能使用默认DefaultMp4Builder,DefaultMp4Builder的注释说Creates a plain MP4 file from a video. Plain as plain can be.大概意思是创建个简化的Mp4,这个会导致你在本地浏览器能播放,但是浏览器会因为缺失了头文件等信息无法播放
                Container mp4file = new FragmentedMp4Builder().build(newMovie);
                mp4file.writeContainer(fc2);
            }
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值