【问题标题】:libjpeg-turbo segmentation fault when writing scanlines to file c++将扫描线写入文件c ++时出现libjpeg-turbo分段错误
【发布时间】:2021-08-30 20:42:32
【问题描述】:

我在 QT Creator 的 Windows 10 上运行了以下代码,我正在尝试使用 libjpeg-turbo 库将 rgb 格式的数据写入 jpeg 文件

#include <stdio.h>
#include <jpeglib.h>

void writeJpeg(const char *filename, std::vector<unsigned char> &image, uint w, uint h) {
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    FILE *outfile;
    JSAMPROW row_pointer[1];
    int row_stride;

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_compress(&cinfo);

    if ((outfile = fopen(filename, "wb")) == NULL) {
    fprintf(stderr, "can't open %s\n", filename);
    exit(1);
    }
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width = w;
    cinfo.image_height = h;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);

    jpeg_set_quality(&cinfo, 100, true);


    jpeg_start_compress(&cinfo, true);


    row_stride = w * 3;

    JSAMPLE *arr = image.data();


    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }



    jpeg_finish_compress(&cinfo);

    fclose(outfile);


    jpeg_destroy_compress(&cinfo);
}

并在这部分代码中的(void)jpeg_write_scanlines(&amp;cinfo, row_pointer, 1); 上获取SIGSEGV

while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }

我尝试过调试,但我不完全确定最好的方法是什么。

我发现它在循环 15 次迭代后崩溃,我最好的猜测是我将数据从向量转换为指针数组很糟糕。

无论如何,我不知道如何更好地分配内存,或者这是否是问题

任何关于我做错了什么的想法以及关于如何在未来实际调试它的任何提示都将不胜感激。

编辑

我将 true 更改为 TRUE 并像这样打印出数组中的每个字节

while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &arr[cinfo.next_scanline * row_stride];

        QString out = "";
        for (int i = 0; i<row_stride; i++)
            out += QString::number(row_pointer[0][i]) + " ";
        qDebug() << "\n\n==============" << cinfo.next_scanline << "==============\n\n";
        qDebug() << out;


        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }

在逐步执行后,它能够输出所有字节,但仍然在write_jpeg_scanlines上崩溃

我还注意到在每条扫描线的末尾打印出一些随机文本 前任: 255 255 255 25520003200!-�U3 第 12 行

255 255 255 255eencoded�/�Rf 在第 13 行

231 230 230 255,autoder�)�Pu 在第 15 行,它崩溃的数据

不确定这是否只是指针末尾的垃圾,还是 qDebug 的症状,但它可以证实 antons 认为图像数据损坏的想法

【问题讨论】:

  • 你能尝试更小的row_stride 值吗?试试你目前使用的一半,即w * 3。试试( w * 3 ) / 2 。我更感兴趣的是是否停止segfault 然后图像是否正确生成。
  • 我尝试设置 row_stride = (w*3)/2; 并将 while 循环更改为 cinfo.next_scanline &lt; cinfo.image_height/2 两者仍然导致段错误。我还尝试在函数开始时将宽度和高度除以二,这也会导致错误。
  • 我只是尝试在函数开始时将wh 设置为1,并且程序不再在jpeg_write_scanlines 上出错,而​​是在jpeg_finish_compress 处出错

标签: c++ segmentation-fault libjpeg libjpeg-turbo


【解决方案1】:

我发现您的代码没有任何问题,除了在这些调用中传递了 C++ 布尔值 true 而不是 C 值 TRUE

    jpeg_set_quality(&cinfo, 100, true);
    ...
    jpeg_start_compress(&cinfo, true);

有时可能会导致奇怪的崩溃。

另外,在这种情况下我会尝试的第一件事 - 如果只是在某处输出每一行的所有字节arr[cinfo.next_scanline * row_stride] - 它会崩溃吗?如果是这样,可能是您在准备图像数据的其他代码中有错误。

UPD.: 原始代码的问题很可能是#include &lt;jpeglib.h&gt; - 这应该会强制在系统目录而不是 libjpeg-turbo 目录中搜索 jpeglib.h。这可以通过使用#include "jpeglib.h" 并指定编译器的 libjpeg-turbo 包含目录的路径来解决。

【讨论】:

  • 我更新了问题,你认为用数据填充数组的最佳方法是什么,可能是所有 255 个字节,以排除损坏的数据
  • @EthanArmstrong 那么可能这只是 libjpeg 集成本身的一个错误,就像您使用了一个版本的标头和另一个版本的二进制文件
【解决方案2】:

感谢所有的帮助,正如@AntonMalyshev 指出的那样,问题在于 libjpeg 的使用不正确。

首先我安装了libjpeg-turbo,虽然它包含一个libjpeg 的库,但我确信更好的做法是直接安装libjpeg。我最终使用了#include &lt;turbojpeg.h&gt;

其次,我发布的示例代码似乎只与基本libjpeg 兼容使用此postlibjpeg-turbo api 我能够提出一个可行的解决方案。

谢谢,伊森

【讨论】:

  • 很高兴您找到了解决方案。但是,我在 libjpeg-turbo 中使用了与您完全相同的代码,并且它有效。 libjpeg-turbo 包含两个 API 变体 - 一个与 libjpeg ("jpeglib.h) 和它自己的 ("turbojpeg.h") 兼容。但是,当您使用第一个时,您需要确保包含“jpeglib .h" 来自您使用的 libjpeg-turbo 版本,而不是来自系统或其他 libjpeg/libjpeg-turbo 版本。
  • 我用如何修复原始代码的信息更新了答案。
  • 是的,你完全正确,我安装了旧版 libjpeg。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-21
  • 2021-06-14
  • 1970-01-01
  • 2020-09-14
  • 2018-08-06
  • 1970-01-01
相关资源
最近更新 更多