1

I'd like to compress a planar 4:2:0 YUV buffer to a jpeg image using libturbojpeg in C, but I'm having trouble using the tjCompressFromYUV() function.

This is my code:

#define PADDING     2
tjhandle tjh;
unsigned long buf_size;
unsigned char *jpegBuf = NULL;
unsigned long jpegSize;
int width = 352;
int height = 288;
int quality = 70;
unsigned char *ucp_frame;
int j;
FILE *fp = NULL;

ucp_frame = malloc(width * height * 3 / 2);
if ( NULL == ucp_frame ) {
    printf("malloc error ucp_frame\n");
    return 0;
}

fp = fopen("planar_352x288.raw", "rb");
if( NULL == fp ) {
    printf("fopen error\n");
    return 0;
}

j = fread( ucp_frame, 1, width * height * 3 / 2, fp);
if( j != width * height * 3 / 2 ) {
    printf("fread error\n");
    return 0;
}
fclose(fp);

tjh = tjInitCompress();
if( NULL == tjh ) {
    printf("tjInitCompress error '%s'\n",  tjGetErrorStr() );
    return 0;
}

buf_size = tjBufSizeYUV2( width, PADDING, height, TJSAMP_420);
jpegBuf = tjAlloc(buf_size);

if( tjCompressFromYUV( tjh, ucp_frame, width, PADDING, height,
                       TJSAMP_420, &jpegBuf, &jpegSize, quality,
                       TJFLAG_NOREALLOC ) ) {
    printf("tjCompressFromYUV error '%s'\n",  tjGetErrorStr() );
}

The error string returned by tjGetErrorStr() is "Bogus input colorspace".

I tried linking libturbojpeg versions 1.4.2 and 1.4.90.

Any help wolud be appreciated,

Thanks

AleA
  • 13
  • 3

3 Answers3

1

Turbojpeg API tjCompressFromYUV allows you such options for jpegBuf:

@param jpegBuf address of a pointer to an image buffer that will receive the JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:

  1. pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and let TurboJPEG grow the buffer as needed,

  2. set *jpegBuf to NULL to tell TurboJPEG to allocate the buffer for you, or

  3. pre-allocate the buffer to a "worst case" size determined by calling tjBufSize(). This should ensure that the buffer never has to be re-allocated (setting #TJFLAG_NOREALLOC guarantees this.)

    If you choose option 1, *jpegSize should be set to the size of your pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC, you should always check *jpegBuf upon return from this function, as it may have changed.

So by using 2-nd option, there is no need to call tjBufSizeYUV2 and tjAlloc, simply have jpegBuf=NULL before calling tjCompressFromYUV and do tjFree after compressing.

om77
  • 36
  • 4
0

Ok it turned out the problem was in the program containing the code I posted, in a smaller test program the tjBufSizeYUV2 call performs as expected.

On a side note it seems that if jpegBuf is pre-allocated before calling tjBufSizeYUV2, the flag argument passed to tjBufSizeYUV2 must contain TJFLAG_NOREALLOC, or else jpegBuf won't be freed even if tjFree(jpegBuf); is later called.

AleA
  • 13
  • 3
-1

#define PADDING 4
jpegBuf = tjAlloc(width*height*3/2);

haskell
  • 1
  • 1
  • 3
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Sep 19 '20 at 10:31
  • 2
    Please follow the [contribution guideline](https://stackoverflow.com/help/how-to-answer) how to answer a question. – flaxel Sep 19 '20 at 11:21