函数式组合编程,完胜类体系编程

考虑打印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,元素之间无空格。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

winlinvip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值