热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mp4parser库

功能介绍https:github.comsanniesmp4parserJavaMP4Parser是一个读取和写入MP4容器的javaapi。直接操作容器而不是对音视频进行编解

功能介绍

https://github.com/sannies/mp4parser

Java MP4 Parser是一个读取和写入MP4容器的java api。直接操作容器而不是对音视频进行编解码。

功能:

  • MP4parser的典型功能如下:
  • 混合音频视频到MP4文件中
  • 合并同样编码设置的MP4文件
  • 增加或者改变MP4文件的metadata
  • 通过省略帧的方式分割MP4文件

例子采用的音频编码格式是H264和AAC,这两种格式对于MP4文件来说非常常见。当然也有AC-3格式的,以及并不常用的H263/MPEG-2视频轨道。

不能把两个编码格式不同的MP4文件进行合并。

项目使用


项目集成

在gradle中添加依赖

compile 'com.googlecode.mp4parser:isoparser:1.1.21'

视频合并

File sdDir;if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {sdDir &#61; Environment.getExternalStorageDirectory();}else{sdDir &#61; Environment.getDataDirectory().getParentFile();}String sdpath &#61; sdDir.getAbsolutePath();//获取指定图片路径String v0 &#61; sdpath &#43; File.separator &#43; "1.mp4";String v1 &#61; sdpath &#43; File.separator &#43; "2.mp4";final ArrayList strings &#61; new ArrayList<>();strings.add(v0);strings.add(v1);final File mergeVideoFile &#61; new File(sdpath &#43; File.separator &#43; "merge.mp4");findViewById(R.id.tv_1).setOnClickListener(new View.OnClickListener() {&#64;Overridepublic void onClick(View view) {String s &#61; Mp4ParserUtils.mergeVideo(strings, mergeVideoFile);Toast.makeText(Mp4PaserActivity.this, "合并成功" &#43; s, Toast.LENGTH_LONG).show();}});

视频分割

final double [] times &#61; {0,3}; //剪切1~3秒final String srcVideoPath &#61; sdpath &#43; File.separator &#43; "merge.mp4";final String resVideoPath &#61; sdpath &#43; File.separator;findViewById(R.id.tv_2).setOnClickListener(new View.OnClickListener() {&#64;Overridepublic void onClick(View view) {try {Mp4ParserUtils.cutVideo(srcVideoPath, resVideoPath, times);Toast.makeText(Mp4PaserActivity.this, "剪切成功", Toast.LENGTH_LONG).show();} catch (IOException e) {}}});

工具类

package com.dianping.test;import android.content.Context;import com.coremedia.iso.boxes.Container;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
import com.googlecode.mp4parser.authoring.tracks.AppendTrack;
import com.googlecode.mp4parser.authoring.tracks.CroppedTrack;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;public class Mp4ParserUtils {/*** 合并视频** &#64;param videoList* &#64;param mergeVideoFile* &#64;return*/public static String mergeVideo(ArrayList videoList, File mergeVideoFile) {FileOutputStream fos &#61; null;FileChannel fc &#61; null;try {List sourceMovies &#61; new ArrayList<>();for (String video : videoList) {sourceMovies.add(MovieCreator.build(video));}List videoTracks &#61; new LinkedList<>();List audioTracks &#61; new LinkedList<>();for (Movie movie : sourceMovies) {for (Track track : movie.getTracks()) {if ("soun".equals(track.getHandler())) {audioTracks.add(track);}if ("vide".equals(track.getHandler())) {videoTracks.add(track);}}}Movie mergeMovie &#61; new Movie();if (audioTracks.size() > 0) {mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));}if (videoTracks.size() > 0) {mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));}Container out &#61; new DefaultMp4Builder().build(mergeMovie);fos &#61; new FileOutputStream(mergeVideoFile);fc &#61; fos.getChannel();out.writeContainer(fc);fc.close();fos.close();return mergeVideoFile.getAbsolutePath();} catch (Exception e) {e.printStackTrace();} finally {if (fc !&#61; null) {try {fc.close();} catch (IOException e) {e.printStackTrace();}}if (fos !&#61; null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}return null;}/*** 剪切视频* &#64;param srcVideoPath* &#64;param dstVideoPath* &#64;param times* &#64;throws IOException*/public static void cutVideo(String srcVideoPath, String dstVideoPath, double[] times) throws IOException {int dstVideoNumber &#61; times.length / 2;String[] dstVideoPathes &#61; new String[dstVideoNumber];for (int i &#61; 0; i "cutOutput-" &#43; i &#43; ".mp4";}int timesCount &#61; 0;for (int idst &#61; 0; idst //Movie movie &#61; new MovieCreator().build(new RandomAccessFile("/home/sannies/suckerpunch-distantplanet_h1080p/suckerpunch-distantplanet_h1080p.mov", "r").getChannel());Movie movie &#61; MovieCreator.build(srcVideoPath);List tracks &#61; movie.getTracks();movie.setTracks(new LinkedList());// remove all tracks we will create new tracks from the olddouble startTime1 &#61; times[timesCount];double endTime1 &#61; times[timesCount &#43; 1];timesCount &#61; timesCount &#43; 2;boolean timeCorrected &#61; false;// Here we try to find a track that has sync samples. Since we can only start decoding// at such a sample we SHOULD make sure that the start of the new fragment is exactly// such a framefor (Track track : tracks) {if (track.getSyncSamples() !&#61; null && track.getSyncSamples().length > 0) {if (timeCorrected) {// This exception here could be a false positive in case we have multiple tracks// with sync samples at exactly the same positions. E.g. a single movie containing// multiple qualities of the same video (Microsoft Smooth Streaming file)throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");}startTime1 &#61; correctTimeToSyncSample(track, startTime1, false);endTime1 &#61; correctTimeToSyncSample(track, endTime1, true);timeCorrected &#61; true;}}for (Track track : tracks) {long currentSample &#61; 0;double currentTime &#61; 0;double lastTime &#61; -1;long startSample1 &#61; -1;long endSample1 &#61; -1;for (int i &#61; 0; i long delta &#61; track.getSampleDurations()[i];if (currentTime > lastTime && currentTime <&#61; startTime1) {// current sample is still before the new starttimestartSample1 &#61; currentSample;}if (currentTime > lastTime && currentTime <&#61; endTime1) {// current sample is after the new start time and still before the new endtimeendSample1 &#61; currentSample;}lastTime &#61; currentTime;currentTime &#43;&#61; (double) delta / (double) track.getTrackMetaData().getTimescale();currentSample&#43;&#43;;}//movie.addTrack(new AppendTrack(new ClippedTrack(track, startSample1, endSample1), new ClippedTrack(track, startSample2, endSample2)));movie.addTrack(new CroppedTrack(track, startSample1, endSample1));}long start1 &#61; System.currentTimeMillis();Container out &#61; new DefaultMp4Builder().build(movie);long start2 &#61; System.currentTimeMillis();FileOutputStream fos &#61; new FileOutputStream(String.format(dstVideoPathes[idst]));FileChannel fc &#61; fos.getChannel();out.writeContainer(fc);fc.close();fos.close();long start3 &#61; System.currentTimeMillis();}}private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) {double[] timeOfSyncSamples &#61; new double[track.getSyncSamples().length];long currentSample &#61; 0;double currentTime &#61; 0;for (int i &#61; 0; i long delta &#61; track.getSampleDurations()[i];if (Arrays.binarySearch(track.getSyncSamples(), currentSample &#43; 1) >&#61; 0) {// samples always start with 1 but we start with zero therefore &#43;1timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample &#43; 1)] &#61; currentTime;}currentTime &#43;&#61; (double) delta / (double) track.getTrackMetaData().getTimescale();currentSample&#43;&#43;;}double previous &#61; 0;for (double timeOfSyncSample : timeOfSyncSamples) {if (timeOfSyncSample > cutHere) {if (next) {return timeOfSyncSample;} else {return previous;}}previous &#61; timeOfSyncSample;}return timeOfSyncSamples[timeOfSyncSamples.length - 1];}}

局限性

只支持MP4文件
经过尝试对于一些MP4文件分割不了
功能比较少
目前点评有采用这种方案做视频的合并


推荐阅读
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 在探讨如何在Android的TextView中实现多彩文字与多样化字体效果时,本文提供了一种不依赖HTML技术的解决方案。通过使用SpannableString和相关的Span类,开发者可以轻松地为文本添加丰富的样式和颜色,从而提升用户体验。文章详细介绍了实现过程中的关键步骤和技术细节,帮助开发者快速掌握这一技巧。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 本文深入解析了WCF Binding模型中的绑定元素,详细介绍了信道、信道管理器、信道监听器和信道工厂的概念与作用。从对象创建的角度来看,信道管理器负责信道的生成。具体而言,客户端的信道通过信道工厂进行实例化,而服务端则通过信道监听器来接收请求。文章还探讨了这些组件之间的交互机制及其在WCF通信中的重要性。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • Python 序列图分割与可视化编程入门教程
    本文介绍了如何使用 Python 进行序列图的快速分割与可视化。通过一个实际案例,详细展示了从需求分析到代码实现的全过程。具体包括如何读取序列图数据、应用分割算法以及利用可视化库生成直观的图表,帮助非编程背景的用户也能轻松上手。 ... [详细]
  • 每日前端实战:148# 视频教程展示纯 CSS 实现按钮两侧滑入装饰元素的悬停效果
    通过点击页面右侧的“预览”按钮,您可以直接在当前页面查看效果,或点击链接进入全屏预览模式。该视频教程展示了如何使用纯 CSS 实现按钮两侧滑入装饰元素的悬停效果。视频内容具有互动性,观众可以实时调整代码并观察变化。访问以下链接体验完整效果:https://codepen.io/comehope/pen/yRyOZr。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
author-avatar
x修者x
無限者:www.wuxianzhe.cn
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有