【发布时间】:2014-04-16 20:26:38
【问题描述】:
我的目标是使用 C/C++ 将 32 位位图 (BGRA) 缓冲区实时转换为 png 图像。为了实现它,我使用 libpng 库来转换位图缓冲区,然后写入 png 文件。然而,在目标臂板(四核处理器)上以单线程执行似乎需要大量时间(约 5 秒)。在分析时,我发现 libpng 压缩过程(放气算法)占用了 90% 以上的时间。所以我试图通过以某种方式使用并行化来减少它。这里的最终目标是至少在 0.5 秒内完成。
现在因为一个 png 可以有多个 IDAT 块,所以我想用多个 IDAT 并行编写 png。采用以下方法编写具有多个 IDAT 的自定义 png 文件
1. Write PNG IHDR chunk
2. Write IDAT chunks in parallel
i. Split input buffer in 4 parts.
ii. compress each part in parallel using zlib "compress" function.
iii. compute CRC of chunk { "IDAT"+zlib compressed data }.
iv. create IDAT chunk i.e. { "IDAT"+zlib compressed data+ CRC}.
v. Write length of IDAT chunk created.
vi. Write complete chunk in sequence.
3. write IEND chunk
现在的问题是通过此方法创建的 png 文件无效或损坏。谁能指出
- 我做错了什么?
- 是否有任何 zlib 压缩或多线程 png 创建的快速实现,最好是在 C/C++ 中?
- 还有其他实现目标的替代方法吗?
注意:PNG specification 后面是创建块
更新: 此方法适用于并行创建 IDAT
1. add one filter byte before each row of input image.
2. split image in four equal parts. <-- may not be required passing pointer to buffer and their offsets
3. Compress Image Parts in parallel
(A)for first image part
--deflateinit(zstrm,Z_BEST_SPEED)
--deflate(zstrm, Z_FULL_FLUSH)
--deflateend(zstrm)
--store compressed buffer and its length
--store adler32 for current chunk, {a1=zstrm->adler} <--adler is of uncompressed data
(B)for second and third image part
--deflateinit(zstrm,Z_BEST_SPEED)
--deflate(zstrm, Z_FULL_FLUSH)
--deflateend(zstrm)
--store compressed buffer and its length
--strip first 2-bytes, reduce length by 2
--store adler32 for current chunk zstrm->adler,{a2,a3 similar to A} <--adler is of uncompressed data
(C) for last image part
--deflateinit(zstrm,Z_BEST_SPEED)
--deflate(zstrm, Z_FINISH)
--deflateend(zstrm)
--store compressed buffer and its length
--strip first 2-bytes and last 4-bytes of buffer, reduce length by 6
--here last 4 bytes should be equal to ztrm->adler,{a4=zstrm->adler} <--adler is of uncompressed data
4. adler32_combine() all four parts i.e. a1,a2,a3 & a4 <--last arg is length of uncompressed data used to calculate adler32 of 2nd arg
5. store total length of compressed buffers <--to be used in calculating CRC of complete IDAT & to be written before IDaT in file
6. Append "IDAT" to Final chunk
7. Append all four compressed parts in sequence to Final chunk
8. Append adler32 checksum computed in step 4 to Final chunk
9. Append CRC of Final chunk i.e.{"IDAT"+data+adler}
To be written in png file in this manner: [PNG_HEADER][PNG_DATA][PNG_END]
where [PNG_DATA] ->Length(4-bytes)+{"IDAT"(4-bytes)+data+adler(4-bytes)}+CRC(4-bytes)
【问题讨论】:
-
@timrau 我看过前面提到的帖子。在那篇文章中,作者实现了压缩并在 png 文件中仅创建了单个 IDAT 块,而在我的情况下,我正在尝试并行化并编写多个 IDAT。所以我想知道用多个IDAT并行编写png文件的正确方法是什么?
-
对步骤的评论:您不需要第 3 步,因为这些已在每个线程中计算,并且是您要剥离的三组四个字节。只是不要丢弃那些。然后当前步骤 4 将移动到当前步骤 5 之后。
-
您应该显示
deflateInit、deflate、deflateEnd的代码。 -
我不明白您在步骤 6-9 中的确切含义。另请注意,您需要一个块 CRC。
标签: c++ multithreading algorithm zlib libpng