笔者在网上找到了很多关于图像压缩库的使用,其中包括libjpeg和libjpeg-turbo,后者据说是在前者的基础上改进了算法,速度提升很大。然而,真正去搜索libjpeg-turbo时,还是会有很多内容是libjpeg的,导致最初误以为是turbo版,结果耗时较大。
最终,折腾了几天,重新改用了turbo的接口,安装了新版本的库,跑出来新的速度确实比libjpeg快不少。
也希望后续用到的朋友能够少走点弯路!
1.encode_by_turbo.h
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <turbojpeg.h>
int tyuv2jpeg(unsigned char* yuv_buffer, int yuv_size, int width, int height,unsigned char** jpeg_buf, unsigned long* jpeg_size,int quality) ;
void convertNV12toYUV420P(const unsigned char* srcData, unsigned char* dstData, int width, int height);
int read_Image_from_raw_by_iostream(const std::string filename, unsigned char **buffer,int *yuvsize);
2.encode_by_turbo.cpp
#include "encode_by_turbo.h"
int tyuv2jpeg(unsigned char* yuv_buffer, int yuv_size, int width, int height,unsigned char** jpeg_buf, unsigned long* jpeg_size,int quality)
{
tjhandle handle = NULL;
int flags = 0;
int padding = 1; //must be 1 or 4
int need_size = 0;
int ret = 0;
int subsample=TJSAMP_420;
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_buf, jpeg_size, quality, flags);
if (ret < 0)
{
printf("compress to jpeg failed: %s\n", tjGetErrorStr());
}
tjDestroy(handle);
return ret;
}
void convertNV12toYUV420P(const unsigned char* srcData, unsigned char* dstData, int width, int height)
{
int frameSize = width * height;
int qFrameSize = frameSize / 4;
const unsigned char* srcY = srcData;
const unsigned char* srcUV = srcData + frameSize;
unsigned char* dstY = dstData;
unsigned char* dstU = dstData + frameSize;
unsigned char* dstV = dstData + frameSize + qFrameSize;
// Convert Y
for (int i = 0; i < frameSize; i++)
{
*dstY++ = *srcY++;
}
// Convert U and V
for (int i = 0; i < qFrameSize; i++)
{
*dstU++ = *srcUV++;
*dstV++ = *srcUV++;
}
}
int read_Image_from_raw_by_iostream(const std::string filename, unsigned char **buffer,int *yuvsize)
{
// open raw data
std::ifstream fin;
// 注意,这里要指定binary读取模式
fin.open(filename, std::ios::binary);
if (!fin) {
std::cerr << "open failed: " << filename << std::endl;
}
// seek函数会把标记移动到输入流的结尾
fin.seekg(0, fin.end);
// tell会告知整个输入流(从开头到标记)的字节数量
int length = fin.tellg();
// 再把标记移动到流的开始位置
fin.seekg(0, fin.beg);
//std::cout << "file length: " << length << std::endl;
// load buffer
char* temp_buf = new char [length];
// read函数读取(拷贝)流中的length各字节到buffer
fin.read(temp_buf, length);
*buffer=reinterpret_cast<u_char *>(temp_buf);
*yuvsize=length;
return 0;
}
3.main.cpp
#include "encode_by_turbo.h"
#include <algorithm>
#include <chrono>
struct Rawimage_t {
size_t input_w, input_h;
unsigned char *yuv420sp;
unsigned char *yuv420p;
};
int main()
{
unsigned char *jpeg_buf = NULL;
unsigned long jpeg_size = 0;
int yuv_size=0;
Rawimage_t image;
image.input_w=3840;
image.input_h=2176;
read_Image_from_raw_by_iostream("test.raw",&image.yuv420sp,&yuv_size);
image.yuv420p = (unsigned char *)malloc(yuv_size+1);
if(image.yuv420p == NULL)
{
printf("lpr_jpeg_save malloc failed\n");
return -1;
}
auto start = std::chrono::high_resolution_clock::now();
convertNV12toYUV420P(image.yuv420sp,image.yuv420p,image.input_w,image.input_h);
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
std::cout << "Time taken by : " << duration.count() /1000.0<< " ms" << std::endl;
start = std::chrono::high_resolution_clock::now();
tyuv2jpeg(image.yuv420p,yuv_size,image.input_w,
image.input_h,&jpeg_buf,&jpeg_size,60); //60:quality
stop = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
std::cout << "Time taken by function: " << duration.count() /1000.0<< " ms" << std::endl;
// 保存压缩后的 JPEG 数据
FILE* outFile = fopen("output.jpg", "wb");
fwrite(jpeg_buf, jpeg_size, 1, outFile);
fclose(outFile);
free(image.yuv420sp);
free(image.yuv420p);
}
free(jpeg_buf);
return 0;
}
4.Makefile
a : main.cpp encode_by_turbo.cpp
g++ main.cpp encode_by_turbo.cpp -I/opt/libjpeg-turbo/include -L/opt/libjpeg-turbo/lib64 -lturbojpeg