使用libjpeg进行编码之二:对I420YUV实现编码


#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sys/stat.h> 
#include <string> 
#include <string.h>

using namespace std;
  
extern  "C" {
#include <jpeglib.h> 
#include <setjmp.h>
#include <jerror.h>
}
  
#define WIDTH 320
#define HEIGHT 240
#define QUALITY 80
#define BUFFER_SZIE (WIDTH*HEIGHT*3/2)
  
/* The following declarations and 5 functions are jpeg related 
 * functions used by put_jpeg_grey_memory and put_jpeg_yuv420p_memory
 */
typedef struct {
    struct jpeg_destination_mgr pub;
    JOCTET *buf;
    size_t bufsize;
    size_t jpegsize;
} mem_destination_mgr;
  
typedef mem_destination_mgr *mem_dest_ptr;
  
  
METHODDEF(void) init_destination(j_compress_ptr cinfo)
{
    mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
    dest->pub.next_output_byte = dest->buf;
    dest->pub.free_in_buffer = dest->bufsize;
    dest->jpegsize = 0;
}
  
METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo)
{
    mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
    dest->pub.next_output_byte = dest->buf;
    dest->pub.free_in_buffer = dest->bufsize;
  
    return FALSE;
}
  
METHODDEF(void) term_destination(j_compress_ptr cinfo)
{
    mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
    dest->jpegsize = dest->bufsize - dest->pub.free_in_buffer;
}
  
static GLOBAL(void) jpeg_mem_dest(j_compress_ptr cinfo, JOCTET* buf, size_t bufsize)
{
    mem_dest_ptr dest;
  
    if (cinfo->dest == NULL) {
        cinfo->dest = (struct jpeg_destination_mgr *)
            (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT,
            sizeof(mem_destination_mgr));
    }
  
    dest = (mem_dest_ptr) cinfo->dest;
  
    dest->pub.init_destination    = init_destination;
    dest->pub.empty_output_buffer = empty_output_buffer;
    dest->pub.term_destination    = term_destination;
  
    dest->buf      = buf;
    dest->bufsize  = bufsize;
    dest->jpegsize = 0;
}
  
static GLOBAL(int) jpeg_mem_size(j_compress_ptr cinfo)
{
    mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
    return dest->jpegsize;
}
  
  
  
/* put_jpeg_yuv420p_memory converts an input image in the YUV420P format into a jpeg image and puts
 * it in a memory buffer.
 * Inputs:
 * - input_image is the image in YUV420P format.
 * - width and height are the dimensions of the image
 * Output:
 * - dest_image is a pointer to the jpeg image buffer
 * Returns buffer size of jpeg image     
 */
static int put_jpeg_yuv420p_memory(unsigned char *dest_image,
                                   unsigned char *input_image, int width, int height)
{
    int i, j, jpeg_image_size;
  
    JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane)
    JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5
  
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
  
    data[0] = y;
    data[1] = cb;
    data[2] = cr;
  
    cinfo.err = jpeg_std_error(&jerr);  // errors get written to stderr 
      
    jpeg_create_compress(&cinfo);
    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    jpeg_set_defaults (&cinfo);
  
    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
  
    cinfo.raw_data_in = TRUE;                  // supply downsampled data
    cinfo.do_fancy_downsampling = FALSE;       // fix segfaulst with v7
    cinfo.comp_info[0].h_samp_factor = 2;
    cinfo.comp_info[0].v_samp_factor = 2;
    cinfo.comp_info[1].h_samp_factor = 1;
    cinfo.comp_info[1].v_samp_factor = 1;
    cinfo.comp_info[2].h_samp_factor = 1;
    cinfo.comp_info[2].v_samp_factor = 1;
  
    jpeg_set_quality(&cinfo, QUALITY, TRUE);
    cinfo.dct_method = JDCT_FASTEST;
  
    jpeg_mem_dest(&cinfo, dest_image, BUFFER_SZIE);    // data written to mem
      
    jpeg_start_compress (&cinfo, TRUE);
  
    for (j = 0; j < height; j += 16) {
        for (i = 0; i < 16; i++) {
            y[i] = input_image + width * (i + j);
            if (i%2 == 0) {
                cb[i/2] = input_image + width * height + width / 2 * ((i + j) / 2);
                cr[i/2] = input_image + width * height + width * height / 4 + width / 2 * ((i + j) / 2);
            }
        }
        jpeg_write_raw_data(&cinfo, data, 16);
    }
  
    jpeg_finish_compress(&cinfo);
    jpeg_image_size = jpeg_mem_size(&cinfo);
    jpeg_destroy_compress(&cinfo);
      
    return jpeg_image_size;
}
  
  
int main( int argc, char **argv )
{
    FILE *fyuv=NULL;
	FILE *fyuvjpg=NULL;
    unsigned char *pSrc =NULL ;
	unsigned char *pDst =NULL;
    int  lSize = 0;
	
	std::string input_yuv_name="";
	if (NULL!=argv[1])
	{
		input_yuv_name = argv[1];
	}
	else
	{
		std::cout<<"Input YUV is NULL!!"<<std::endl;
		return -1;
	}
  
  
    fyuv = fopen(input_yuv_name.c_str(),"r");
	

    pSrc =  (unsigned char *)malloc (BUFFER_SZIE);
    pDst = (unsigned char *)malloc (BUFFER_SZIE);
	memset(pSrc,BUFFER_SZIE, 0 );
	memset(pDst,BUFFER_SZIE, 0 );

	if( fread(pSrc, BUFFER_SZIE,1 ,fyuv) >1)
    {
       std::cerr<<"Error occur in stat function !!"<<std::endl;
    }
	
    lSize = put_jpeg_yuv420p_memory(pDst, pSrc , WIDTH ,HEIGHT);
	std::string output_yuv_name="Encoded.jpeg";
    fyuvjpg =fopen(output_yuv_name.c_str(),"w");
	fwrite(pDst,BUFFER_SZIE, 1 ,fyuvjpg);
	
	if (NULL != pSrc)
	{
		free(pSrc);
	    pSrc=NULL;
	}
	if (NULL != pDst)
	{
		free(pDst);
	    pDst=NULL;
	}
 
    fclose(fyuv);
    fclose(fyuvjpg);
    return 0;
}


linux  make file:

#Make file for JPEG encoder
#target type and test program directory
TARGET_TYPE = EXECUTABLE
#compiler
COMPILER = g++
                                                           

PRJ_PATH = /home/dahu/development/libjpeg/SourceCode/dev-code/encoder
test := encode420
                                               
                                                           
#flags
LIBS:=   -lpthread -lm -lgcc -lstdc++  -L/usr/local/lib/ -ljpeg

INCLS :=  -I/usr/local/include/ 
CFLAGS := -g -O0 -Wall -DDEBUG_ONLY                                                   
#files


#target control
ifeq ($(TARGET_TYPE),EXECUTABLE)
 TARGET = Jpeg420Encoder
 CLIENT_SOURCES := $(test).cpp  
 CLIENT_OBJS := $(CLIENT_SOURCES:.cpp=.o)     
 TARGETCMD = $(COMPILER)  $(INCLS) $(CFLAGS) -o $@ $^ $(LIBS)
else
 @echo "ERROR !! You have to assign right TARGET_TYPE= EXECUTABLE!"
endif


.PHONY: all  
all: $(TARGET)
                                                     
$(TARGET):$(CLIENT_OBJS)
 $(TARGETCMD)
 
#clean
clean:
 @rm -rfv  Jpeg420Encoder *.o 


运行:

./Jpeg420Encoder jpeg_320_240_420.0.yuv

可在当前目录下找到编好的jpeg文件

要将一个yuv图像编码jpeg文件,可以使用libjpeg-turbo库提供的API。以下是一个基本的示例: ```c #include <stdio.h> #include <jpeglib.h> #define WIDTH 640 #define HEIGHT 480 void encode_jpeg(unsigned char* yuv_data, const char* filename) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; int row_stride; FILE* outfile = fopen(filename, "wb"); if (outfile == NULL) { fprintf(stderr, "Error opening output jpeg file %s\n", filename); return; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = WIDTH; cinfo.image_height = HEIGHT; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo, TRUE); row_stride = WIDTH * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &yuv_data[cinfo.next_scanline * row_stride]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); } ``` 在这个示例中,我们创建了一个`encode_jpeg()`函数,它接收一个指向yuv数据的指针和一个输出文件名。函数中使用libjpeg-turbo库提供的API来将yuv数据编码jpeg文件。 首先,我们创建了`jpeg_compress_struct`结构体和`jpeg_error_mgr`结构体,用于存储压缩参数和错误信息。然后,我们打开输出文件并将输出流绑定到`jpeg_compress_struct`结构体中。接下来,我们设置了图像宽度、高度、输入组件数量和颜色空间等参数,并使用`jpeg_set_defaults()`函数设置了默认的压缩参数。然后,我们开始压缩过程,并在while循环中逐行写入扫描线数据。最后,我们完成了压缩过程,关闭输出文件并销毁`jpeg_compress_struct`结构体。 要使用这个函数,我们只需要将yuv数据和输出文件名作为参数传递给它即可。例如: ```c int main() { unsigned char yuv_data[WIDTH * HEIGHT * 3]; // fill yuv_data with actual data encode_jpeg(yuv_data, "output.jpg"); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值