jpeg压缩中的内存泄漏。错误或我的错误?

时间:2015-08-20 16:53:14

标签: c++ libjpeg

我写了一个npm module来捕获linux上的网络摄像头输入。以yuyv格式捕获的帧将转换为 rgb24 ,并在压缩为 jpeg 图像后。在jpeg压缩中,似乎存在内存泄漏。因此,内存的使用不断增加。

 Image* rgb24_to_jpeg(Image *img, Image *jpeg) { // img = RGB24
    jpeg_compress_struct cinfo;
    jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);
    jerr.trace_level = 10;
    jpeg_create_compress(&cinfo);

    unsigned char *imgd = new unsigned char[img->size];
    long unsigned int size = 0;
    jpeg_mem_dest(&cinfo, &imgd, &size);

    cinfo.image_width = img->width;
    cinfo.image_height = img->height;
    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);
    int row_stride = cinfo.image_width * 3;
    JSAMPROW row_pointer[1];
    while (cinfo.next_scanline < cinfo.image_height) {
      row_pointer[0] = &img->data[cinfo.next_scanline * row_stride];
      jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
//    size += 512; // TODO: actual value to expand jpeg buffer... JPEG header?
    if (jpeg->data == NULL) {
      jpeg->data = (unsigned char *) malloc(size);
    } else {
      jpeg->data = (unsigned char *) realloc(jpeg->data, size);
    }
    memcpy(jpeg->data, imgd, size);
    delete[] imgd;
    jpeg->size = size;
    return jpeg;
  }

每个周期都会重新分配rgb24和jpeg缓冲区。所以看起来泄漏是在libjpeg层内。这是真的还是我在代码中的某个地方犯了错误?

注意:压缩图像不应保存为文件,因为数据可能用于实时流式传输。

2 个答案:

答案 0 :(得分:3)

您正在以错误的方式使用jpeg_mem_dest - 第二个参数是指向char的指针,因为它实际上是由库设置的,然后您必须在完成后释放它。现在你用一个指针初始化它,它被覆盖并释放库分配的内存区域,但原始内存区域被泄露。

这是你应该如何改变你的功能:

Image* rgb24_to_jpeg(Image *img, Image *jpeg) { // img = RGB24
    jpeg_compress_struct cinfo;
    jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);
    jerr.trace_level = 10;
    jpeg_create_compress(&cinfo);

    unsigned char *imgd = 0;
    long unsigned int size = 0;
    cinfo.image_width = img->width;
    cinfo.image_height = img->height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, 100, true);
    jpeg_mem_dest(&cinfo, &imgd, &size); // imgd will be set by the library
    jpeg_start_compress(&cinfo, true);
    int row_stride = cinfo.image_width * 3;
    JSAMPROW row_pointer[1];
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &img->data[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    //    size += 512; // TODO: actual value to expand jpeg buffer... JPEG header?
    if (jpeg->data == NULL) {
        jpeg->data = (unsigned char *) malloc(size);
    } else if (jpeg->size != size) {
        jpeg->data = (unsigned char *) realloc(jpeg->data, size);
    }
    memcpy(jpeg->data, imgd, size);
    free(imgd); // dispose of imgd when you are done
    jpeg->size = size;
    return jpeg;
}

此代码段形式jpeg_mem_dest解释了内存管理:

  if (*outbuffer == NULL || *outsize == 0) {
    /* Allocate initial buffer */
    dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);
    if (dest->newbuffer == NULL)
      ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
    *outsize = OUTPUT_BUF_SIZE;
  }

因此,如果传递空指针或零大小的缓冲区,库将为您执行分配。因此 - 另一种方法也是正确设置大小,然后您可以使用最初提供的指针

答案 1 :(得分:-1)

在我的情况下,我没有用之前的答案解决问题,没有办法释放内存图像指针,唯一的方法是为图像保留足够的内存,这样库就不会保留内存和我可以控制内存并且在我的应用程序的同一个堆上,而不是在库的堆上,这是我的例子:

//previous code...
struct jpeg_compress_struct cinfo;

//reserving the enough memory for my image (width * height)
unsigned char* _image = (unsigned char*)malloc(Width * Height);

//putting the reserved size into _imageSize
_imageSize = Width * Height;

//call the function like this:
jpeg_mem_dest(&cinfo, &_image, &_imageSize);
................
//releasing the reserved memory
free(_image);

注意:如果你把 _imageSize = 0,库会假设你没有保留内存,而自己的库会这样做..所以你需要在 _imageSize 中放入 _image 中保留的字节数

这样您就可以完全控制保留的内存,并且可以随时在软件中释放它..