libjpeg-turbo支持直接从JPEG解压成YUV格式,或者反之。这也是我当初想研究它的一个动力。
看了头文件注释,它是支持YUV444(即宏TJSAMP_444),YUV422(即宏TJSAMP_422),YUV420(即宏TJSAMP_420),YUV400(即宏TJSAMP_440),YUV411(即宏TJSAMP_411)。可惜的是,只支持平面格式(plane),对于交织的如UYVY或特别的如NV12(即YUV420SP)或NV16(即YUV422SP),都没看到有支持。在sourceforge上看邮件列表,发现有些描述,但还没研究过,看发布的源码,也未见有说明,估计是不支持的。
本文简单介绍如何从JPEG解压成YUV格式,以及如何将YUV压缩成JPEG。
libjpeg-turbo使用tjBufSizeYUV2函数计算YUV大小,开始时没注意第二个参数pad,默认传递0,发现没效果,而传1或4,却是可以的。解压后的YUV的格式,是由JPEG图片的采样格式决定的,如果JPEG本身是YUV420,则解压得到的YUV,就是YUV420格式。
示例代码如下:
-
int tjpeg2yuv(unsigned char* jpeg_buffer, int jpeg_size, unsigned char** yuv_buffer, int* yuv_size, int* yuv_type)
-
{
-
tjhandle handle =
NULL;
-
int width, height, subsample, colorspace;
-
int flags =
0;
-
int padding =
1;
// 1或4均可,但不能是0
-
int ret =
0;
-
-
handle = tjInitDecompress();
-
tjDecompressHeader3(handle, jpeg_buffer, jpeg_size, &width, &height, &subsample, &colorspace);
-
-
printf(
"w: %d h: %d subsample: %d color: %d\n", width, height, subsample, colorspace);
-
-
flags |=
0;
-
-
*yuv_type = subsample;
-
// 注:经测试,指定的yuv采样格式只对YUV缓冲区大小有影响,实际上还是按JPEG本身的YUV格式来转换的
-
*yuv_size = tjBufSizeYUV2(width, padding, height, subsample);
-
*yuv_buffer =(
unsigned
char *)
malloc(*yuv_size);
-
if (*yuv_buffer ==
NULL)
-
{
-
printf(
"malloc buffer for rgb failed.\n");
-
return
-1;
-
}
-
-
ret = tjDecompressToYUV2(handle, jpeg_buffer, jpeg_size, *yuv_buffer, width,
-
padding, height, flags);
-
if (ret <
0)
-
{
-
printf(
"compress to jpeg failed: %s\n", tjGetErrorStr());
-
}
-
tjDestroy(handle);
-
-
return ret;
-
}
-
-
int tyuv2jpeg(unsigned char* yuv_buffer, int yuv_size, int width, int height, int subsample, unsigned char** jpeg_buffer, unsigned long* jpeg_size, int quality)
-
{
-
tjhandle handle =
NULL;
-
int flags =
0;
-
int padding =
1;
// 1或4均可,但不能是0
-
int need_size =
0;
-
int ret =
0;
-
-
handle = tjInitCompress();
-
-
flags |=
0;
-
-
need_size = tjBufSizeYUV2(width, padding, height, subsample);
-
if (need_size != yuv_size)
-
{
-
printf(
"we detect yuv size: %d, but you give: %d, check again.\n", need_size, yuv_size);
-
return
0;
-
}
-
-
ret = tjCompressFromYUV(handle, yuv_buffer, width, padding, height, subsample, jpeg_buffer, jpeg_size, quality, flags);
-
if (ret <
0)
-
{
-
printf(
"compress to jpeg failed: %s\n", tjGetErrorStr());
-
}
-
-
tjDestroy(handle);
-
-
return ret;
-
}
另外,该库也支持从RGB转换成YUV,或反之。调用相应的函数即可,不再详述。示例代码如下:
-
int trgb2yuv(unsigned char* rgb_buffer, int width, int height, unsigned char** yuv_buffer, int* yuv_size, int subsample)
-
{
-
tjhandle handle =
NULL;
-
int flags =
0;
-
int padding =
1;
// 1或4均可,但不能是0
-
int pixelfmt = TJPF_RGB;
-
int ret =
0;
-
-
handle = tjInitCompress();
-
-
flags |=
0;
-
-
*yuv_size = tjBufSizeYUV2(width, padding, height, subsample);
-
-
*yuv_buffer =(
unsigned
char *)
malloc(*yuv_size);
-
if (*yuv_buffer ==
NULL)
-
{
-
printf(
"malloc buffer for rgb failed.\n");
-
return
-1;
-
}
-
ret = tjEncodeYUV3(handle, rgb_buffer, width,
0, height, pixelfmt, *yuv_buffer, padding, subsample, flags);
-
if (ret <
0)
-
{
-
printf(
"encode to yuv failed: %s\n", tjGetErrorStr());
-
}
-
-
tjDestroy(handle);
-
-
return ret;
-
}
-
-
int tyuv2rgb(unsigned char* yuv_buffer, int yuv_size, int width, int height, int subsample, unsigned char** rgb_buffer, int* rgb_size)
-
{
-
tjhandle handle =
NULL;
-
int flags =
0;
-
int padding =
1;
// 1或4均可,但不能是0
-
int pixelfmt = TJPF_RGB;
-
int need_size =
0;
-
int ret =
0;
-
-
handle = tjInitDecompress();
-
-
flags |=
0;
-
-
need_size = tjBufSizeYUV2(width, padding, height, subsample);
-
if (need_size != yuv_size)
-
{
-
printf(
"we detect yuv size: %d, but you give: %d, check again.\n", need_size, yuv_size);
-
return
-1;
-
}
-
-
*rgb_size = width*height*tjPixelSize[pixelfmt];
-
-
*rgb_buffer =(
unsigned
char *)
malloc(*rgb_size);
-
if (*rgb_buffer ==
NULL)
-
{
-
printf(
"malloc buffer for rgb failed.\n");
-
return
-1;
-
}
-
ret = tjDecodeYUV(handle, yuv_buffer, padding, subsample, *rgb_buffer, width,
0, height, pixelfmt, flags);
-
if (ret <
0)
-
{
-
printf(
"decode to rgb failed: %s\n", tjGetErrorStr());
-
}
-
-
tjDestroy(handle);
-
-
return ret;
-
}
以上代码示例,二级指针均在函数内分配内存,需要调用者自行释放,否则会有内存泄漏。