(由于时间久,忘记原链接,仅把自己现在实现方式写出以供参考:)

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信息前置)相关推荐

  1. php音视频边下边播,视频个别片段加旁白,就是我边播放视频边录制旁白或声音...

    我们平常在看游戏视频.家庭录像.动画等视频都能听到解说(旁白)声音.嘻嘻,想知道这可以用什么软件给视频加旁白么?笔者找了一款最易上手的软件,可以边播放视频边录制旁白或声音.以下附上视频片段加旁白的解决 ...

  2. 0930 视频边下边播/蓝牙库/阿里博客/afnetworking详细/小程序工具

    iOS视频边下边播–缓存播放数据流 简书: http://www.jianshu.com/p/990ee3db0563 简单易用的蓝牙库,基于CoreBluetooth的封装,并兼容ios和mac o ...

  3. [iOS]仿微博视频边下边播之滑动 TableView 自动播放

    注意:框架已经迭代到2.0版本,我重新架构了整个框架,API 也得到了更好的设计,我为 2.0 版本的实现写了一篇文章 [iOS]如何重新架构 JPVideoPlayer ?.此文中的实现思路仍然是一 ...

  4. [iOS]仿微博视频边下边播之滑动TableView自动播放

    Tips:这次的内容分为两篇文章讲述 01.[iOS]仿微博视频边下边播之封装播放器 讲述如何封装一个实现了边下边播并且缓存的视频播放器. 02.[iOS]仿微博视频边下边播之滑动TableView自 ...

  5. 仿微博视频边下边播之封装播放器

    来源:NewPan(@盼盼_HKbuy) 链接:http://www.jianshu.com/p/0d4588a7540f Tips:这次的内容分为两篇文章讲述 01.[iOS]仿微博视频边下边播之封 ...

  6. iOS开发之仿微博视频边下边播之自定义AVPlayer播放器, 边下边播解剖。视频处理流程,建立连接-请求数据-统筹数据-解码数据-视频呈现

    Tips:这次的内容分为两篇文章讲述 01.[iOS]仿微博视频边下边播之封装播放器 讲述如何封装一个实现了边下边播并且缓存的视频播放器. 02.[iOS]仿微博视频边下边播之滑动TableView自 ...

  7. MP4中MOOV信息前置

    MOOV信息前置 import com.ctsi.common.utils.UUIDUtils; import org.apache.commons.fileupload.FileItem; impo ...

  8. Android 视频边下边播,MP4头信息在后调整头信息

    mp4视频有两种格式,一种视频头信息在前,这种直接可以先缓存头信息,然后直接边下边播,还有一种是头信息在最后,这种情况下则需要处理mp4的头信息,并调整mp4的格式. mp4文件的格式如下图 图1 从 ...

  9. php音视频边下边播,封装bilibili播放器,自定义边下边播和缓存功能

    image 本项目使用播放器是ijkplay, 并且进行封装和修改主要功能: 1.重新编辑ijkplay的so库, 使其更精简和支持https协议 2.自定义MediaDataSource, 使用ok ...

最新文章

  1. Linux下为什么ls直接就可以运行,而你的程序要写./dir1/dir2/bin/bwa才可以
  2. Dockerfile文件创建centos:7,配置JDK8的环境变量,与运行springboot的jar包,的镜像
  3. python gpu编程_Python笔记_第四篇_高阶编程_进程、线程、协程_5.GPU加速
  4. ideaspringboot项目上传服务器_PHP中使用 TUS 协议来实现可恢复文件上传
  5. CentOS6.X安装QQ2012
  6. Python getattr
  7. 升级AndrOid4.3,谷歌发布Android 4.3系统 今日开始升级
  8. Java入门-换行输出
  9. html中bottom的属性,css中bottom是什么意思?
  10. iPhone支持杜比的机型
  11. 关于error C2059: 语法错误:“类型”,初学者的一点收获
  12. 像素鸟多线程java_用java Swing做的小游戏像素鸟-Go语言中文社区
  13. Linux U盘分区格式化 fdisk命令
  14. image 微信小程序flex_微信小程序入门教程之二:页面样式
  15. 帝国时代php,依然经典,《帝国时代》WEB版现世
  16. JSP的EL表达式的使用
  17. MySQL运行出错:Could not acquire management access for administration
  18. http://www.microsoft.com/zh-cn/download/details.aspx?id=28358 silverlight tool 工具下载地址
  19. 第二章--第一个Spring程序
  20. 有线热电偶温度验证系统

热门文章

  1. java 数组元素查找_Java在数组中查找指定元素的方法
  2. linux 7 services设定,CentOS 7 systemd service 设置limit,不生效问题
  3. 强化学习与ChatGPT:快速让AI学会玩贪食蛇游戏!
  4. t20天正建筑软件服务器为空,天正建筑T20常见问题(四)
  5. STM32 RTC时钟掉电日期不更新 STM32 HAL库RTC时钟配置
  6. c语言程序设计班车管理系统,班车信息管理系统.doc
  7. java编写一个汽车出租管理程序_怎么用java做汽车出租管理程序
  8. Tiva单片机——麦克风声音数据的储存/回放(Flash读/写)
  9. Git 更改本地分支与远程分支的映射关系
  10. 去水印视频软件免费版,免费去水印的视频软件