Memory leak in jpeg compression. Bug or my mistake?

牧云@^-^@ 提交于 2021-02-19 08:04:28

问题


I wrote an npm module for capturing webcam input on linux. The captured frame in yuyv format is converted to rgb24 and after compressed to a jpeg image. In the jpeg compression there appears to be a memory leak. So the usage of memory increases continuously.

 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;
  }

The rgb24 and jpeg buffers are reallocated on every cycle. So it looks like the leak is inside libjpeg layer. Is this true or I simply made a mistake somewhere in the code?

Note: the compressed image shall not be saved as a file, since the data might be used for live streaming.


回答1:


You are using the jpeg_mem_dest in a wrong way - the second parameter is pointer to pointer to char because it is actually set by the library and then you must free it after you are done. Now you are initializing it with a pointer, it gets overwritten and you free the memory region allocated by the library but the original memory region is leaked.

This is how you should change your function:

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;
}

This snippet form jpeg_mem_dest explains the memory management:

  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;
  }

So, if you pass a an empty pointer or a zero sized buffer the library will perform an allocation for you. Thus - another approach is also to set the size correctly and then you can use the originally supplied pointer



来源:https://stackoverflow.com/questions/32123992/memory-leak-in-jpeg-compression-bug-or-my-mistake

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!