ZigZag Sin
登 陆
上一篇:Box 概述 下一篇:moov Box

ftyp Box

Time
2022-2-21 11:39 阅读 376

具体 Box 分析

ftyp Box

官方介绍定义

image-20211216211238144

​ 传送门:MP4 文档 P4 页

介绍

​ ftyp box 是 MP4 文件的第一个Box,这个 Box 里面包含了视频的编码格式和标准,这个 Box 的作用基本就是 MP4 这种封装格式的特有的标志,一个 MP4 中只有唯一 一个 ftyp Box。ftyp box通常放在文件的开始,通过对该box解析可以让我们的软件(播放器、demux、解析器)知道应该使用哪种协议对这该文件解析,是后续解读的基础。

字段分析:

名称大小(byte)意义说明
Box length4Box 整体的大小包含 Header 和 Data部分
Box type4”ftyp”的ASCII码,表名是 ftyp Boxbox 属性值,通常是固定值
Major brand4商标具体信息参考:http://www.ftyps.com
Minor version4商标版本号
Compatible brand不定,但是可以根据长度算出(Box length - 16)兼容其他的版本号表示可以兼容和遵从那些协议标准,是一个列表。

工具分析:

  1. 再用16进制文本查看器打开这个 MP4文件,如图:

image-20211216213946160

接下来我们根据上图16进制查看器展现出来的值进行分析:

定义实际值(16进制)具体值(10进制 / ASCII)字段位置
Box length(4 byte)0x00 0x00 0x00 0x1824Header
Box type(4 byte)0x66 0x74 0x78 0x70"ftyp"Header
Major brand(4 byte)0x6D 0x70 0x34 0x32"mp42"Data
Minor version(4 byte)0x00 0x00 0x00 0x000Data
Compatible brand(8 byte)上图红框“mp41isom”Data
  1. 我们使用 MP4 Explorer 软件来打开这个 MP4 文件,进行验证,如图:

image-20211216212018463

代码定义:

这里我们有个需求就是打印对应的 Box 信息,那么我们便要重构一下Box Header 和 Base Box

// BaseBox.h  

struct BoxHeader{
    // ...
    
    // 其他都不变,这里就添加一条语句进行对应的Box类型的返回
    BOX_TYPE GetType() {
        if(_h_type[0]=='f'&&_h_type[1]=='t'&&_h_type[2]=='y'&&_h_type[3]=='p') return FTYP;
        return ERROR;
    }
};

class BaseBox{
public:
    
    // ...
    
   	// 其他都不变,就加个虚函数,子Box有打印信息需求就重写这个方法
	virtual void PrintDataInfo() {};
};


class TimeFTYBox : public BaseBox{
public:
	/* 这里你可以把刚刚解析的属性值放在这,但是我认为这些不太重要就先不写了,直接解析里面的data数据
		unsigned int Major_brand;
		unsigned int Minor_version;
		...
	*/
public:
    TimeFTYBox(BoxHeader h);
    TimeFTYBox(BoxHeader h, Timebyte * d): BaseBox(h, d){};
    ~TimeFTYBox();
    void PrintDataInfo() override;
};

实现

// TimeFTYBox.cpp

TimeFTYBox::TimeFTYBox(BoxHeader h) : BaseBox(h) {
    if (h.GetSize()) {
        data = new Timebyte[h.GetSize()];
    }
}


void TimeFTYBox::PrintDataInfo() {
    if (!data) return;
    h.to_string();
    if (h.GetSize() > 16) {
        printf("Major brand: %c%c%c%c\n", data[0], data[1], data[2], data[3]);
        printf("Minor version: %ud\n", data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]);
    }
    printf("Compatible brand: ");
    for (int i = 8; i < h.GetSize() - 8; ++i) {
        printf("%c", data[i]);
    }
    printf("\n");
}

TimeFTYBox::~TimeFTYBox() {

}

接下来我们定义一个用来打开 MP4 文件和解析文件的类,这个大家可以参考

// TimeMP4.h 

#include <iostream>

enum OpenType {
    RB,
    WB
};

class TimeMP4 {
private:
    const char * filePath;
    OpenType t;
    FILE *file;
    TimeFTYBox *ftyBox = nullptr;

public:
    TimeMP4(const char * path, OpenType t=RB);
    ~TimeMP4();
    bool Open();
    void LodingBox();
    void test();

};

实现

//
// Created by Time on 2021/12/9.
//

#include "TimeMP4.h"

TimeMP4::TimeMP4(const char *path, OpenType t)
    :filePath(path), t(t)
{

}

TimeMP4::~TimeMP4() {
    if(ftyBox) {
        delete ftyBox;
        ftyBox = nullptr;
    }
}

bool TimeMP4::Open() {
    int re;
#ifdef _WINDOWS
    if(t == WB)
        re = fopen_s(&file, filePath, "wb+");
    else
        re = fopen_s(&file, filePath, "rb+");
#endif
#ifdef __APPLE__
    if(t == WB)
        file = fopen(filePath, "wb+");
    else
        file = fopen(filePath, "rb+");
    re = file ? 0 : 1;
#endif
    return !re;
}

void TimeMP4::LodingBox() {
    if(!file) return;
    
    while (!feof(file)) {
        BoxHeader header;
        unsigned int len;
        fread(header._h_size, 1, 4, file);
        fread(header._h_type, 1, 4, file);
        if(header.GetSize() == 1) {
            len = 16;
        }else if(header.GetSize() == 0) {
            break;
        }
        len = 8;

        if(header.GetType() == FTYP) {
            ftyBox = new TimeFTYBox(header);
            fread(ftyBox->GetData(),1,header.GetSize()-len, file);
        }else {
            if(header.GetSize() >> 31) {
#ifdef _WINDOWS
                _fseeki64(file, header.GetSize()-len, 1);
#endif
#ifdef __APPLE__
                fread(nullptr, 1, header.GetSize()-len, file);
#endif
            }else {
                fseek(file, header.GetSize()-len, 1);
            }
        }

    }
}

void TimeMP4::test() {
    if(ftyBox) {
        ftyBox->PrintDataInfo();
    }
}


好了现在我们都写好了,进行测试一下

int main(){
    cout << "testMP4" << endl;
	TimeMP4 mp4("../../resource/demo1.mp4");
    if(!mp4.Open()) {
        cout << "open failed" << endl;
        return;
    }
    mp4.LodingBox();
    mp4.test();
}

最后执行情况和我们分析的一样那么这个 Box 的解析就到这里

image-20211216220839690

上一篇:Box 概述 下一篇:moov Box
给我买个键盘吧。。。求打赏。。。
欢迎加群,一起交流~~~