考虑打印MP4各种BOX的实现,一种是类似类体系,用函数重载来实现:
template<typename T>
stringstream& __srs_print_mp4_vector(std::vector<T>& arr, stringstream& ss, int level, bool is_box)
{
for (size_t i = 0; i < arr.size(); i++) {
T elem = arr[i];
if (is_box) {
elem.dumps(ss, level);
} else {
elem.dumps_detail(ss, level);
}
if (i < arr.size() - 1) {
ss << endl;
srs_padding(ss, level);
}
}
return ss;
}
template<typename T>
stringstream& srs_print_mp4_vector(std::vector<T>& arr, stringstream& ss, int level)
{
return __srs_print_mp4_vector(arr, ss, level, false);
}
template<typename T>
stringstream& __srs_print_mp4_vector_ptr(std::vector<T>& arr, stringstream& ss, int level, bool is_box)
{
for (size_t i = 0; i < arr.size(); i++) {
T elem = arr[i];
if (is_box) {
elem->dumps(ss, level);
} else {
elem->dumps_detail(ss, level);
}
if (i < arr.size() - 1) {
ss << endl;
srs_padding(ss, level);
}
}
return ss;
}
template<typename T>
stringstream& srs_print_mp4_vector_ptr(std::vector<T>& arr, stringstream& ss, int level) {
return __srs_print_mp4_vector_ptr(arr, ss, level, false);
}
template<typename T>
stringstream& srs_print_mp4_vector_elem(std::vector<T>& arr, stringstream& ss, int level)
{
for (size_t i = 0; i < arr.size(); i++) {
srs_print_mp4_type(ss, (uint32_t)arr[i]);
if (i < arr.size() - 1) {
ss << ",";
}
}
return ss;
}
template<>
stringstream& srs_print_mp4_vector(std::vector<SrsMp4BoxBrand>& arr, stringstream& ss, int level)
{
return srs_print_mp4_vector_elem(arr, ss, level);
}
template<>
stringstream& srs_print_mp4_vector(std::vector<SrsMp4DataEntryBox*>& arr, stringstream& ss, int level)
{
return srs_print_mp4_vector_ptr(arr, ss, level);
}
template<>
stringstream& srs_print_mp4_vector(std::vector<SrsMp4SampleEntry*>& arr, stringstream& ss, int level)
{
return __srs_print_mp4_vector_ptr(arr, ss, level, true);
}
相当于给不同的类提供不同的函数,不过当打印的方式有很大的差异时,远远不如函数组合的方式更直观和简洁:
template<typename T>
stringstream& srs_dumps_array(std::vector<T>&arr, stringstream& ss, int level, void (*pfn)(T&, stringstream&, int), void (*delimiter)(stringstream&,int))
{
for (size_t i = 0; i < arr.size(); i++) {
T& elem = arr[i];
pfn(elem, ss, level);
if (i < arr.size() - 1) {
delimiter(ss, level);
}
}
return ss;
}
template<typename T>
stringstream& srs_dumps_array(T* arr, int size, stringstream& ss, int level, void (*pfn)(T&, stringstream&, int), void (*delimiter)(stringstream&,int))
{
for (size_t i = 0; i < size; i++) {
T& elem = arr[i];
pfn(elem, ss, level);
if (i < size - 1) {
delimiter(ss, level);
}
}
return ss;
}
void srs_delimiter_inline(stringstream& ss, int level)
{
ss << ",";
}
void srs_delimiter_inlinespace(stringstream& ss, int level)
{
ss << ", ";
}
void srs_delimiter_newline(stringstream& ss, int level)
{
ss << endl;
srs_padding(ss, level);
}
template<typename T>
void srs_pfn_box(T& elem, stringstream& ss, int level)
{
elem.dumps(ss, level);
}
template<typename T>
void srs_pfn_detail(T& elem, stringstream& ss, int level)
{
elem.dumps_detail(ss, level);
}
template<typename T>
void srs_pfn_pbox(T*& elem, stringstream& ss, int level)
{
elem->dumps(ss, level);
}
template<typename T>
void srs_pfn_pdetail(T*& elem, stringstream& ss, int level)
{
elem->dumps_detail(ss, level);
}
template<typename T>
void srs_pfn_elem(T& elem, stringstream& ss, int level)
{
srs_print_mp4_type(ss, (uint32_t)elem);
}
void srs_pfn_stss(uint32_t& elem, stringstream& ss, int level)
{
ss << elem;
}
这个组合可以应付所有的类型了:
stringstream& SrsMp4SampleDescriptionBox::dumps_detail(stringstream& ss, int level)
{
ss << ", " << entries.size() << " childs";
if (!entries.empty()) {
ss << "(+)" << endl;
srs_dumps_array(entries, ss, level + 1, srs_pfn_pbox, srs_delimiter_newline);
}
return ss;
}
stringstream& SrsMp4EditListBox::dumps_detail(stringstream& ss, int level)
{
ss << ", " << entries.size() << " childs";
if (!entries.empty()) {
ss << "(+)" << endl;
srs_padding(ss, level + 1);
srs_dumps_array(entries, ss, level + 1, srs_pfn_detail, srs_delimiter_newline);
}
return ss;
}
可以打印下面所有的类型:
// vector中包含指针
std::vector<SrsMp4SampleEntry*> entries;
// vector中包含实例
std::vector<SrsMp4CttsEntry> entries;
// 直接uint32_t的数组
uint32_t entry_count;
uint32_t* sample_numbers;
// 非vector方式
uint32_t entry_count;
SrsMp4StscEntry* entries;
// 不同的变量名
uint32_t sample_count;
uint32_t* entry_sizes;
以及不同的分割方式:
// 以逗号分割,不换行
ftyp, 32B, brands:isom,512(isom,iso2,avc1,mp41)
// 换行分割每个元素
elst, 40B, 2 childs(+)
Entry, 46TBN, start=-1TBN, rate=1,0
// 以逗号分割,不换行
stss, 452B, count=109
1, 126, 170, 228, 370, 413
// 以换行分割每个元素
ctts, 29784B, 3721 childs (+)
count=2, offset=1280
count=1, offset=3200
Example
最后打印出来的结果:
doc/source.200kbps.768x320.mp4
ftyp, 32B, brands:isom,512(isom,iso2,avc1,mp41)
moov, 165982B, 4 boxes
mvhd, 108B, FB(4B), 210652ms, TBN=1000, nTID=3
trak, 72908B, 3 boxes
mdia, 72760B, 3 boxes
mdhd, 32B, FB(4B), TBN=16000, 3368960TBN, LANG=und
minf, 72675B, 3 boxes
vmhd, 20B, FB(4B,V0,0x01)
dinf, 36B, 1 boxes
dref, 28B, FB(4B), 1 childs(+)
URL: Same file
stbl, 72611B, 7 boxes
stsd, 167B, FB(4B), 1 childs(+)
avc1, 151B, refs#1, size=768x320, 2 boxes
avcC, 49B, AVC Config: 41B
0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19,
0x67, 0x64, 0x00, 0x20, 0xac, 0xd9, 0x40, 0xc0,
0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01,
0x00, 0x00, 0x03, 0x00, 0x32, 0x0f, 0x18, 0x31,
0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2,
0x2c
pasp, 16B, free 8B
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01
stts, 24B, FB(4B), 1 childs (+)
count=5264, delta=640
stss, 452B, FB(4B), count=109
1, 126, 170, 228, 370, 413, 466, 496
ctts, 29784B, FB(4B), 3721 childs (+)
count=2, offset=1280
count=1, offset=3200
count=1, offset=1280
count=1, offset=0
count=1, offset=640
count=1, offset=3200
count=1, offset=1280
count=1, offset=0
stsc, 28B, FB(4B), 1 childs (+)
first=1, samples=1, index=1
stsz, 21076B, FB(4B), size=0, 5264 childs (+)
5132, 127, 984, 50, 57, 20, 188, 35
stco, 21072B, FB(4B), 5264 childs (+)
48, 5267, 5481, 6639, 6863, 7094, 7201, 7563
udta, 98B, total 90B
0x00, 0x00, 0x00, 0x5a, 0x6d, 0x65, 0x74, 0x61
在这个例子中,有非常非常复杂的打印组合,比如:
avcC
打印完整信息,而udta
和free
可以打印简要或者完整信息。stss
和stsz
数据打印方式一样,但是头并不相同。ftyp
在头中也有数组打印,数据格式是int转char,元素之间无空格。