簡體   English   中英

如何將 memory 中的多個緩沖區壓縮為一個並獲得其壓縮大小?

[英]How to compress multiple buffers in memory with boost into one and get its compressed size?

我想通過 boost 的 zlib 壓縮將多個緩沖區(在我的情況下來自不同來源的視頻幀)壓縮到一個新緩沖區中,然后將所有內容寫入磁盤上的文件中。 我需要這兩個步驟,因為我想在包含壓縮緩沖區的最終大小的文件中添加一個 header (稍后將 function 作為解析器的偏移量)。 我想通過 boost 的 iostreams 庫來實現這一點。

出現了以下相關問題:

a) 我需要使用filtering_streamfiltering_streambuf嗎? 我希望后者已經具有某種緩沖行為。

b)如何關閉filtering_stream(buf)並將其寫入緩沖區?

c) 如何讀取壓縮數據的最終大小? .tellg()沒有為這些過濾流實現(如在 SO 上的其他地方提到的)

d) 你可以有多個來源,即我的三個緩沖區還是我需要將它們組合起來? (見下文我的方法)。

class Frame {
private:
    /* other things */
public:
    float buf1[3];
    float buf2[3];
    float buf3[4];
    /* more things */
};

int main() {
    Frame frame;
    
    using boost::iostreams bio;
    
    bio::filtering_streambuf<bio::input> in;
    in.push(bio::gzip_compressor());
    /* Could you also add the buffers indiviually? */
    in.push(bio::array_source(reinterpret_cast<const char*>(frame.buf1), 3 + 7 + 12 + (sizeof(float) * 3)));
    
    const char *compressed = /* How to close in and write the contents to this buffer? */
    int compressedSize = /* How to get this from in? in.tellg() does not work */
    
    std::stringstream headerInformation;
    headerInformation << "START";
    headerInformation << "END " << compressedSize;
    
    std::ofstream ofs("ouput.data", std::ofstream::out | std::ofstream::binary | std::ofstream::app);
    bio::filtering_ostream out;
    out.push(ofs);
    out.write(headerInformation.str(), headerInformation.str().length());
    out.write(compressed, compressedSize);
    
    boost::iostreams::close(out);
    boost::iostreams::close(in);
    
    return 0;
}

a) 我需要使用filtering_streambuf 的filtering_stream 嗎? 我希望后者已經具有某種緩沖行為。

兩者都會起作用。 stream 添加了標准庫中的文本和區域設置功能。

b)如何關閉過濾流(buf)並將其寫入緩沖區?

You could use an array_sink , back_inserter_device , memory map etc. See https://www.boost.org/doc/libs/1_72_0/libs/iostreams/doc/ ("Models").

c) 如何讀取壓縮數據的最終大小? .tellg() 沒有為這些過濾流實現(如在 SO 上的其他地方提到的)

從您的底層 output 設備/流中檢測它。 在你做之前不要忘記刷新/關閉過濾層。

d) 你可以有多個來源,即我的三個緩沖區還是我需要將它們組合起來? (見下文我的方法)。

你可以做你想做的。

給我看代碼...

我會扭轉主動權,並在寫入output 緩沖區時使過濾器壓縮:

using RawBuffer = std::vector<char>;
using Device = bio::back_insert_device<RawBuffer>;

RawBuffer compressed_buffer; // optionally reserve some size

{
    bio::filtering_ostream filter;
    filter.push(bio::gzip_compressor());
    filter.push(Device{ compressed_buffer });

    filter.write(reinterpret_cast<char const*>(&frame.buf1),
                 sizeof(frame) - offsetof(Frame, buf1));
}

要改用過濾流緩沖區:

{
    bio::filtering_ostreambuf filter;
    filter.push(bio::gzip_compressor());
    filter.push(Device{ compressed_buffer });

    std::copy_n(reinterpret_cast<char const*>(&frame.buf1),
                sizeof(frame) - offsetof(Frame, buf1),
                std::ostreambuf_iterator<char>(&filter));
}

現在你的問題的答案很突出:

const char *compressed = compressed_buffer.data();
int compressedSize = compressed_buffer.size();

我會將剩余的代碼減少為:

{
    std::ofstream ofs("ouput.data", std::ios::binary | std::ios::app);
    ofs << "START";
    ofs << "END " << compressed_buffer.size();
    ofs.write(compressed_buffer.data(), compressed_buffer.size());
}

考慮不要為每一幀重新打開 output stream :)

現場演示

住在科利魯

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <iterator>
#include <fstream>
#include <vector>
namespace bio = boost::iostreams;

class Frame {
private:
    /* other things */
public:
    float buf1[3];
    float buf2[3];
    float buf3[4];
    /* more things */
};

int main() {
    Frame const frames[]{
        {
            { 1, 2, 3 },
            { 4, 5, 6 },
            { 7, 8, 9, 10 },
        },
        {
            { 11, 12, 13 },
            { 14, 15, 16 },
            { 17, 18, 19, 20 },
        },
        {
            { 21, 22, 23 },
            { 24, 25, 26 },
            { 27, 28, 29, 30 },
        },
    };

    // avoiding UB:
    static_assert(std::is_trivial_v<Frame> &&
                  std::is_standard_layout_v<Frame>);

    using RawBuffer = std::vector<char>;
    using Device = bio::back_insert_device<RawBuffer>;

    std::remove("output.data");
    std::ofstream ofs("output.data", std::ios::binary | std::ios::app);

    RawBuffer compressed_buffer; // optionally reserve some size

    for (Frame const& frame : frames) {
        compressed_buffer.clear(); // do not shrink_to_fit optimizing allocation

        {
            bio::filtering_ostreambuf filter;
            filter.push(bio::gzip_compressor());
            filter.push(Device{ compressed_buffer });

            std::copy_n(reinterpret_cast<char const*>(&frame.buf1),
                        sizeof(frame) - offsetof(Frame, buf1),
                        std::ostreambuf_iterator<char>(&filter));
        }

        ofs << "START";
        ofs << "END " << compressed_buffer.size();
        ofs.write(compressed_buffer.data(), compressed_buffer.size());
    }
}

確定性地生成 output.data:

00000000: 5354 4152 5445 4e44 2035 301f 8b08 0000  STARTEND 50.....
00000010: 0000 0000 ff63 6068 b067 6060 7000 2220  .....c`h.g``p." 
00000020: 6e00 e205 407c 0088 1f00 3183 2303 8300  n...@|....1.#...
00000030: 102b 3802 0058 a049 af28 0000 0053 5441  .+8..X.I.(...STA
00000040: 5254 454e 4420 3438 1f8b 0800 0000 0000  RTEND 48........
00000050: 00ff 6360 3070 6460 7000 e200 204e 00e2  ..c`0pd`p... N..
00000060: 0220 6e00 e20e 209e 00c4 3380 7881 2300  . n... ...3.x.#.
00000070: 763b 7371 2800 0000 5354 4152 5445 4e44  v;sq(...STARTEND
00000080: 2034 391f 8b08 0000 0000 0000 ff63 6058   49..........c`X
00000090: e1c8 c0b0 0188 7700 f101 203e 01c4 1780  ......w... >....
000000a0: f806 103f 00e2 1740 fcc1 1100 dfb4 6cde  ...?...@......l.
000000b0: 2800 0000                                (...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM