函式式組合程式設計,完勝類體系程式設計
阿新 • • 發佈:2019-01-03
考慮列印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,元素之間無空格。