[libjpeg-turbo]读取一张raw图(NV12格式),利用libjpeg-turbo压缩为jpg图像。并统计耗时

笔者在网上找到了很多关于图像压缩库的使用,其中包括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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值