实现视频边下边播(视频MOOV信息前置)
(由于时间久,忘记原链接,仅把自己现在实现方式写出以供参考:)
public class QtFastStart {public static boolean sDEBUG = false; private static void safeClose(Closeable closeable) {if (closeable != null) {try {closeable.close(); } catch (IOException e) {printe(e, "Failed to close file: "); }}}/* package */ static long uint32ToLong(int int32) {return int32 & 0x00000000ffffffffL; }/** * Ensures passed uint32 value in long can be represented as Java int. */ /* package */ static int uint32ToInt(int uint32) throws UnsupportedFileException {if (uint32 < 0) {throw new UnsupportedFileException("uint32 value is too large"); }return uint32; }/** * Ensures passed uint32 value in long can be represented as Java int. */ /* package */ static int uint32ToInt(long uint32) throws UnsupportedFileException {if (uint32 > Integer.MAX_VALUE || uint32 < 0) {throw new UnsupportedFileException("uint32 value is too large"); }return (int) uint32; }/** * Ensures passed uint64 value can be represented as Java long. */ /* package */ static long uint64ToLong(long uint64) throws UnsupportedFileException {if (uint64 < 0) throw new UnsupportedFileException("uint64 value is too large"); return uint64; }private static int fourCcToInt(byte[] byteArray) {return ByteBuffer.wrap(byteArray).order(ByteOrder.BIG_ENDIAN).getInt(); }private static void printf(String format, Object... args) {if (sDEBUG) System.err.println("QtFastStart: " + String.format(format, args)); }private static void printe(Throwable e, String format, Object... args) {printf(format, args); if (sDEBUG) e.printStackTrace(); }private static boolean readAndFill(FileChannel infile, ByteBuffer buffer) throws IOException {buffer.clear(); int size = infile.read(buffer); buffer.flip(); return size == buffer.capacity(); }private static boolean readAndFill(FileChannel infile, ByteBuffer buffer, long position) throws IOException {buffer.clear(); int size = infile.read(buffer, position); buffer.flip(); return size == buffer.capacity(); }/* top level atoms */ private static final int FREE_ATOM = fourCcToInt(new byte[]{'f', 'r', 'e', 'e'}); private static final int JUNK_ATOM = fourCcToInt(new byte[]{'j', 'u', 'n', 'k'}); private static final int MDAT_ATOM = fourCcToInt(new byte[]{'m', 'd', 'a', 't'}); private static final int MOOV_ATOM = fourCcToInt(new byte[]{'m', 'o', 'o', 'v'}); private static final int PNOT_ATOM = fourCcToInt(new byte[]{'p', 'n', 'o', 't'}); private static final int SKIP_ATOM = fourCcToInt(new byte[]{'s', 'k', 'i', 'p'}); private static final int WIDE_ATOM = fourCcToInt(new byte[]{'w', 'i', 'd', 'e'}); private static final int PICT_ATOM = fourCcToInt(new byte[]{'P', 'I', 'C', 'T'}); private static final int FTYP_ATOM = fourCcToInt(new byte[]{'f', 't', 'y', 'p'}); private static final int UUID_ATOM = fourCcToInt(new byte[]{'u', 'u', 'i', 'd'}); private static final int CMOV_ATOM = fourCcToInt(new byte[]{'c', 'm', 'o', 'v'}); private static final int STCO_ATOM = fourCcToInt(new byte[]{'s', 't', 'c', 'o'}); private static final int CO64_ATOM = fourCcToInt(new byte[]{'c', 'o', '6', '4'}); private static final int ATOM_PREAMBLE_SIZE = 8; /** * @param in Input file. * @param out Output file. * @return false if input file is already fast start. * @throws IOException */ public static boolean fastStart(String in, String out) throws IOException, MalformedFileException, UnsupportedFileException {boolean ret = false; FileInputStream inStream = null; FileOutputStream outStream = null; FileChannel infile = null; FileChannel outfile= null; try {inStream = new FileInputStream(in); infile = inStream.getChannel(); outStream = new FileOutputStream(out); outfile = outStream.getChannel(); return ret = fastStartImpl(infile, outfile); } finally {if (!ret) {infile.transferTo(0, infile.size(), outfile);//当转换不成功时(正常是因文件小),直接copy. // out.delete(); }else{ // in.delete(); }safeClose(inStream); safeClose(outStream); }}private static boolean fastStartImpl(FileChannel infile, FileChannel outfile) throws IOException, MalformedFileException, UnsupportedFileException {ByteBuffer atomBytes = ByteBuffer.allocate(ATOM_PREAMBLE_SIZE).order(ByteOrder.BIG_ENDIAN); int atomType = 0; long atomSize = 0; // uint64_t long lastOffset; ByteBuffer moovAtom; ByteBuffer ftypAtom = null; // uint64_t, but assuming it is in int32 range. It is reasonable as int max is around 2GB. Such large moov is unlikely, yet unallocatable :). int moovAtomSize; long startOffset = 0; System.out.println("QtFastStart------"+"开始"); // traverse through the atoms in the file to make sure that 'moov' is at the end while (readAndFill(infile, atomBytes)) {atomSize = uint32ToLong(atomBytes.getInt()); // uint32 atomType = atomBytes.getInt(); // representing uint32_t in signed int // keep ftyp atom if (atomType == FTYP_ATOM) {int ftypAtomSize = uint32ToInt(atomSize); // XXX: assume in range of int32_t ftypAtom = ByteBuffer.allocate(ftypAtomSize).order(ByteOrder.BIG_ENDIAN); atomBytes.rewind(); ftypAtom.put(atomBytes); if (infile.read(ftypAtom) < ftypAtomSize - ATOM_PREAMBLE_SIZE) break; ftypAtom.flip(); startOffset = infile.position(); // after ftyp atom System.out.println("QtFastStart---FTYP_ATOM---atomType:"+atomType); System.out.println("QtFastStart---FTYP_ATOM---atomType:"+String.valueOf(infile.position())); } else { // System.out.println("QtFastStart------atomType:"+atomType); if (atomSize == 1) {/* 64-bit special case */ atomBytes.clear(); if (!readAndFill(infile, atomBytes)) break; atomSize = uint64ToLong(atomBytes.getLong()); // XXX: assume in range of int64_t infile.position(infile.position() + atomSize - ATOM_PREAMBLE_SIZE * 2); // seek System.out.println("QtFastStart--atomSize == 1----atomType:"+atomType); } else {infile.position(infile.position() + atomSize - ATOM_PREAMBLE_SIZE); // seek System.out.println("QtFastStart--else----atomType:"+atomType); System.out.println("QtFastStart--else----atomType:"+String.valueOf(infile.position() + atomSize - ATOM_PREAMBLE_SIZE)); }}if (sDEBUG) printf("%c%c%c%c %10d %d", (atomType >> 24) & 255, (atomType >> 16) & 255, (atomType >> 8) & 255, (atomType >> 0) & 255, infile.position() - atomSize, atomSize); if ((atomType != FREE_ATOM)&& (atomType != JUNK_ATOM)&& (atomType != MDAT_ATOM)&& (atomType != MOOV_ATOM)&& (atomType != PNOT_ATOM)&& (atomType != SKIP_ATOM)&& (atomType != WIDE_ATOM)&& (atomType != PICT_ATOM)&& (atomType != UUID_ATOM)&& (atomType != FTYP_ATOM)) {printf("encountered non-QT top-level atom (is this a QuickTime file?)"); break; }/* The atom header is 8 (or 16 bytes), if the atom size (which * includes these 8 or 16 bytes) is less than that, we won't be * able to continue scanning sensibly after this atom, so break. */ if (atomSize < 8)break; }System.out.println("QtFastStart------"+"第一循环结束atomType:"+atomType); if (atomType != MOOV_ATOM) {printf("last atom in file was not a moov atom"); return false; }// moov atom was, in fact, the last atom in the chunk; load the whole moov atom // atomSize is uint64, but for moov uint32 should be stored. // XXX: assuming moov atomSize <= max vaue of int32 moovAtomSize = uint32ToInt(atomSize); lastOffset = infile.size() - moovAtomSize; // NOTE: assuming no extra data after moov, as qt-faststart.c moovAtom = ByteBuffer.allocate(moovAtomSize).order(ByteOrder.BIG_ENDIAN); if (!readAndFill(infile, moovAtom, lastOffset)) {throw new MalformedFileException("failed to read moov atom"); }// this utility does not support compressed atoms yet, so disqualify files with compressed QT atoms if (moovAtom.getInt(12) == CMOV_ATOM) {throw new UnsupportedFileException("this utility does not support compressed moov atoms yet"); }// crawl through the moov chunk in search of stco or co64 atoms while (moovAtom.remaining() >= 8) {int atomHead = moovAtom.position(); atomType = moovAtom.getInt(atomHead + 4); // representing uint32_t in signed int if (!(atomType == STCO_ATOM || atomType == CO64_ATOM)) {moovAtom.position(moovAtom.position() + 1); continue; }atomSize = uint32ToLong(moovAtom.getInt(atomHead)); // uint32 if (atomSize > moovAtom.remaining()) {throw new MalformedFileException("bad atom size"); }moovAtom.position(atomHead + 12); // skip size (4 bytes), type (4 bytes), version (1 byte) and flags (3 bytes) if (moovAtom.remaining() < 4) {throw new MalformedFileException("malformed atom"); }// uint32_t, but assuming moovAtomSize is in int32 range, so this will be in int32 range int offsetCount = uint32ToInt(moovAtom.getInt()); if (atomType == STCO_ATOM) {printf("patching stco atom..."); if (moovAtom.remaining() < offsetCount * 4) {throw new MalformedFileException("bad atom size/element count"); }for (int i = 0; i < offsetCount; i++) {int currentOffset = moovAtom.getInt(moovAtom.position()); int newOffset = currentOffset + moovAtomSize; // calculate uint32 in int, bitwise addition // current 0xffffffff => new 0x00000000 (actual >= 0x0000000100000000L) if (currentOffset < 0 && newOffset >= 0) {throw new UnsupportedFileException("This is bug in original qt-faststart.c: " + "stco atom should be extended to co64 atom as new offset value overflows uint32, " + "but is not implemented."); }moovAtom.putInt(newOffset); }} else if (atomType == CO64_ATOM) {printf("patching co64 atom..."); if (moovAtom.remaining() < offsetCount * 8) {throw new MalformedFileException("bad atom size/element count"); }for (int i = 0; i < offsetCount; i++) {long currentOffset = moovAtom.getLong(moovAtom.position()); moovAtom.putLong(currentOffset + moovAtomSize); // calculate uint64 in long, bitwise addition }}}infile.position(startOffset); // seek after ftyp atom if (ftypAtom != null) {// dump the same ftyp atom printf("writing ftyp atom..."); ftypAtom.rewind(); outfile.write(ftypAtom); }// dump the new moov atom printf("writing moov atom..."); moovAtom.rewind(); outfile.write(moovAtom); // copy the remainder of the infile, from offset 0 -> (lastOffset - startOffset) - 1 printf("copying rest of file..."); infile.transferTo(startOffset, lastOffset - startOffset, outfile); System.out.println("QtFastStart------"+"处理完成"); return true; }public static class QtFastStartException extends Exception {private QtFastStartException(String detailMessage) {super(detailMessage); }}public static class MalformedFileException extends QtFastStartException {private MalformedFileException(String detailMessage) {super(detailMessage); }}public static class UnsupportedFileException extends QtFastStartException {private UnsupportedFileException(String detailMessage) {super(detailMessage); }}}
其中fastStart是我们需要关注的方法;
(其实本类可以不用重写,直接调用,传入原始与生成路径
boolean success = QtFastStart.fastStart(OriginalPath, Path);
只需要在调用的类中导入下面的包即可实现
import net.ypresto.qtfaststart.QtFastStart;
)
要想实现自己的特殊功能最好重写(自己写)QtFastStart这个类(就像上面重写的这个类);
比如:
我们得需求是把所有视频转换(moov信息前置),而视频急短的话(10秒左右)则不能转换成功,我就把为转换的视频在fastStart()方法的finally里处理,直接copy原视频(急短的视频,不用转换也可边下边播,好像是moov信息本来就在前面)。
实现视频边下边播(视频MOOV信息前置)相关推荐
- php音视频边下边播,视频个别片段加旁白,就是我边播放视频边录制旁白或声音...
我们平常在看游戏视频.家庭录像.动画等视频都能听到解说(旁白)声音.嘻嘻,想知道这可以用什么软件给视频加旁白么?笔者找了一款最易上手的软件,可以边播放视频边录制旁白或声音.以下附上视频片段加旁白的解决 ...
- 0930 视频边下边播/蓝牙库/阿里博客/afnetworking详细/小程序工具
iOS视频边下边播–缓存播放数据流 简书: http://www.jianshu.com/p/990ee3db0563 简单易用的蓝牙库,基于CoreBluetooth的封装,并兼容ios和mac o ...
- [iOS]仿微博视频边下边播之滑动 TableView 自动播放
注意:框架已经迭代到2.0版本,我重新架构了整个框架,API 也得到了更好的设计,我为 2.0 版本的实现写了一篇文章 [iOS]如何重新架构 JPVideoPlayer ?.此文中的实现思路仍然是一 ...
- [iOS]仿微博视频边下边播之滑动TableView自动播放
Tips:这次的内容分为两篇文章讲述 01.[iOS]仿微博视频边下边播之封装播放器 讲述如何封装一个实现了边下边播并且缓存的视频播放器. 02.[iOS]仿微博视频边下边播之滑动TableView自 ...
- 仿微博视频边下边播之封装播放器
来源:NewPan(@盼盼_HKbuy) 链接:http://www.jianshu.com/p/0d4588a7540f Tips:这次的内容分为两篇文章讲述 01.[iOS]仿微博视频边下边播之封 ...
- iOS开发之仿微博视频边下边播之自定义AVPlayer播放器, 边下边播解剖。视频处理流程,建立连接-请求数据-统筹数据-解码数据-视频呈现
Tips:这次的内容分为两篇文章讲述 01.[iOS]仿微博视频边下边播之封装播放器 讲述如何封装一个实现了边下边播并且缓存的视频播放器. 02.[iOS]仿微博视频边下边播之滑动TableView自 ...
- MP4中MOOV信息前置
MOOV信息前置 import com.ctsi.common.utils.UUIDUtils; import org.apache.commons.fileupload.FileItem; impo ...
- Android 视频边下边播,MP4头信息在后调整头信息
mp4视频有两种格式,一种视频头信息在前,这种直接可以先缓存头信息,然后直接边下边播,还有一种是头信息在最后,这种情况下则需要处理mp4的头信息,并调整mp4的格式. mp4文件的格式如下图 图1 从 ...
- php音视频边下边播,封装bilibili播放器,自定义边下边播和缓存功能
image 本项目使用播放器是ijkplay, 并且进行封装和修改主要功能: 1.重新编辑ijkplay的so库, 使其更精简和支持https协议 2.自定义MediaDataSource, 使用ok ...
最新文章
- Linux下为什么ls直接就可以运行,而你的程序要写./dir1/dir2/bin/bwa才可以
- Dockerfile文件创建centos:7,配置JDK8的环境变量,与运行springboot的jar包,的镜像
- python gpu编程_Python笔记_第四篇_高阶编程_进程、线程、协程_5.GPU加速
- ideaspringboot项目上传服务器_PHP中使用 TUS 协议来实现可恢复文件上传
- CentOS6.X安装QQ2012
- Python getattr
- 升级AndrOid4.3,谷歌发布Android 4.3系统 今日开始升级
- Java入门-换行输出
- html中bottom的属性,css中bottom是什么意思?
- iPhone支持杜比的机型
- 关于error C2059: 语法错误:“类型”,初学者的一点收获
- 像素鸟多线程java_用java Swing做的小游戏像素鸟-Go语言中文社区
- Linux U盘分区格式化 fdisk命令
- image 微信小程序flex_微信小程序入门教程之二:页面样式
- 帝国时代php,依然经典,《帝国时代》WEB版现世
- JSP的EL表达式的使用
- MySQL运行出错:Could not acquire management access for administration
- http://www.microsoft.com/zh-cn/download/details.aspx?id=28358 silverlight tool 工具下载地址
- 第二章--第一个Spring程序
- 有线热电偶温度验证系统
热门文章
- java 数组元素查找_Java在数组中查找指定元素的方法
- linux 7 services设定,CentOS 7 systemd service 设置limit,不生效问题
- 强化学习与ChatGPT:快速让AI学会玩贪食蛇游戏!
- t20天正建筑软件服务器为空,天正建筑T20常见问题(四)
- STM32 RTC时钟掉电日期不更新 STM32 HAL库RTC时钟配置
- c语言程序设计班车管理系统,班车信息管理系统.doc
- java编写一个汽车出租管理程序_怎么用java做汽车出租管理程序
- Tiva单片机——麦克风声音数据的储存/回放(Flash读/写)
- Git 更改本地分支与远程分支的映射关系
- 去水印视频软件免费版,免费去水印的视频软件