1. 程式人生 > >函式式組合程式設計,完勝類體系程式設計

函式式組合程式設計,完勝類體系程式設計

考慮列印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

在這個例子中,有非常非常複雜的列印組合,比如:

  1. avcC列印完整資訊,而udtafree可以列印簡要或者完整資訊。
  2. stssstsz資料列印方式一樣,但是頭並不相同。
  3. ftyp在頭中也有陣列列印,資料格式是int轉char,元素之間無空格。