首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解压缩MP4文件中的time-To-Sample表(STTS)

解压缩MP4文件中的time-To-Sample表(STTS)
EN

Stack Overflow用户
提问于 2015-12-11 17:01:29
回答 1查看 2.5K关注 0票数 0

我有一个mp4视频字节数组,我需要使用它的中间帧为它生成一个缩略图(例如,如果视频长度是10秒,那么我需要从5秒开始获取图片)。

我设法解析了文件并提取了它的盒子(atom)。我还设法从mvhd盒子里拿到了视频长度。我还设法从stts box中提取了1.采样时间表,2. stcs box中的sample- to -Chunk表,3. stco box中的块偏移表,4. stsz box中的样本大小表,5. stss box中的同步样本表。

我知道所有实际的媒体都在mdat框中,我需要关联上面的表来找到文件中确切的帧偏移量,但我的问题是如何找到?表数据似乎是压缩的(特别是采样时间表),但我不知道如何解压缩它们。

任何帮助都是非常感谢的。

下面是代码示例

将字节转换为十六进制的代码

代码语言:javascript
复制
public static char[] bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for ( int j = 0; j < bytes.length; j++ ) {
        int v = bytes[j] & 0xFF;

        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];            
    }
    return hexChars;
}

获取盒子偏移量的代码

代码语言:javascript
复制
final static String MOOV                          = "6D6F6F76";
final static String MOOV_MVHD                     = "6D766864";
final static String MOOV_TRAK                     = "7472616B";
final static String MOOV_TRAK_MDIA                = "6D646961";
final static String MOOV_TRAK_MDIA_MINF           = "6D696E66";
final static String MOOV_TRAK_MDIA_MINF_STBL      = "7374626C";
final static String MOOV_TRAK_MDIA_MINF_STBL_STSD = "73747364";
final static String MOOV_TRAK_MDIA_MINF_STBL_STTS = "73747473";
final static String MOOV_TRAK_MDIA_MINF_STBL_STSS = "73747373";
final static String MOOV_TRAK_MDIA_MINF_STBL_STSC = "73747363";
final static String MOOV_TRAK_MDIA_MINF_STBL_STCO = "7374636F";
final static String MOOV_TRAK_MDIA_MINF_STBL_STSZ = "7374737A";

static int getBox(char[] s, int offset, String type) {
    int typeOffset = -1;
    for (int i = offset*2; i<s.length; ) {
        String sizeHex = new String(Arrays.copyOfRange(s, i, i + 8));
        String typeHex = new String(Arrays.copyOfRange(s, i + 8, i + 16));
        int size = Integer.parseInt(sizeHex, 16);

        if (typeHex.equals(type)) {
            typeOffset = (i/2);
            break;
        } else if (typeHex.equals(MOOV) 
            || typeHex.equals(MOOV_TRAK) 
            || typeHex.equals(MOOV_TRAK_MDIA) 
            || typeHex.equals(MOOV_TRAK_MDIA_MINF)
            || typeHex.equals(MOOV_TRAK_MDIA_MINF_STBL)) {
            int x = (i/2) + 8;
            typeOffset = getBox(s, x, type);
            if (typeOffset>-1) {
                break;
            } 
        }
        i+=(size*2);
    }

    return typeOffset;
}

获取持续时间和时间刻度的代码

代码语言:javascript
复制
static int[] getDuration(char[] s) {
    int mvhdOffset = getBox(s, 0, MOOV_MVHD);
    int timeScaleStart = (mvhdOffset*2) + (4 + 4 + 1 + 3 + 4 + 4)*2;
    int timeScaleEnd   = (mvhdOffset*2) + (4 + 4 + 1 + 3 + 4 + 4 + 4)*2;

    int durationStart  = (mvhdOffset*2) + (4 + 4 + 1 + 3 + 4 + 4 + 4)*2;
    int durationEnd    = (mvhdOffset*2) + (4 + 4 + 1 + 3 + 4 + 4 + 4 + 4)*2;

    String timeScaleHex = new String(Arrays.copyOfRange(s, timeScaleStart, timeScaleEnd));
    String durationHex = new String(Arrays.copyOfRange(s, durationStart, durationEnd));

    int timeScale = Integer.parseInt(timeScaleHex, 16);
    int duration = Integer.parseInt(durationHex, 16);

    int[] result = {duration, timeScale};
    return result;
}

获取time- to -Sample表的代码

代码语言:javascript
复制
static int[][] getTimeToSampleTable(char[] s, int trakOffset) {
    int offset = getBox(s, trakOffset, MOOV_TRAK_MDIA_MINF_STBL_STTS);
    int sizeStart = offset*2;
    int sizeEnd   = offset*2 + (4)*2;

    int typeStart = offset*2 + (4)*2;
    int typeEnd   = offset*2 + (4 + 4)*2;

    int noOfEntriesStart = offset*2 + (4 + 4 + 1 + 3)*2;
    int noOfEntriesEnd   = offset*2 + (4 + 4 + 1 + 3 + 4)*2;

    String sizeHex = new String(Arrays.copyOfRange(s, sizeStart, sizeEnd));
    String typeHex = new String(Arrays.copyOfRange(s, typeStart, typeEnd));
    String noOfEntriesHex = new String(Arrays.copyOfRange(s, noOfEntriesStart, noOfEntriesEnd));

    int size = Integer.parseInt(sizeHex, 16);
    int noOfEntries = Integer.parseInt(noOfEntriesHex, 16);

    int[][] timeToSampleTable = new int[noOfEntries][2];

    for (int i = 0; i<noOfEntries; i++) {
        int sampleCountStart = noOfEntriesEnd + ((i)*((4 + 4)*2));
        int sampleCountEnd   = noOfEntriesEnd + ((i)*((4 + 4)*2)) + (4)*2;

        int sampleDurationStart = noOfEntriesEnd + ((i)*((4 + 4)*2)) + (4)*2;
        int sampleDurationEnd   = noOfEntriesEnd + ((i)*((4 + 4)*2)) + (4 + 4)*2;

        String sampleCountHex = new String(Arrays.copyOfRange(s, sampleCountStart, sampleCountEnd));
        String sampleDurationHex = new String(Arrays.copyOfRange(s, sampleDurationStart, sampleDurationEnd));

        timeToSampleTable[i][0] = Integer.parseInt(sampleCountHex, 16);
        timeToSampleTable[i][1] = Integer.parseInt(sampleDurationHex, 16);
    }

    return timeToSampleTable;
} 
EN

回答 1

Stack Overflow用户

发布于 2016-05-30 20:34:03

ISO/IEC 14496-12标准描述了您需要的所有步骤。附录7提供了解码步骤。第8节介绍了这些表。

希望这能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34219596

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档