summaryrefslogtreecommitdiff
path: root/test/encode/jpegenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/encode/jpegenc.c')
-rw-r--r--test/encode/jpegenc.c996
1 files changed, 996 insertions, 0 deletions
diff --git a/test/encode/jpegenc.c b/test/encode/jpegenc.c
new file mode 100644
index 0000000..dababdc
--- /dev/null
+++ b/test/encode/jpegenc.c
@@ -0,0 +1,996 @@
+/*
+ * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Simple JPEG encoder based on libVA.
+ *
+ * Usage:
+ * ./jpegenc <width> <height> <input file> <output file> <input filetype 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGB)> q <quality>
+ * Currently supporting only I420 and NV12 input file formats.
+ */
+
+#include "sysdeps.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <time.h>
+
+#include <pthread.h>
+
+#include <va/va.h>
+#include <va/va_enc_jpeg.h>
+#include "va_display.h"
+#include "jpegenc_utils.h"
+
+#ifndef VA_FOURCC_I420
+#define VA_FOURCC_I420 0x30323449
+#endif
+
+#define CHECK_VASTATUS(va_status,func) \
+ if (va_status != VA_STATUS_SUCCESS) { \
+ fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
+ exit(1); \
+ }
+
+
+void show_help()
+{
+ printf("Usage: ./jpegenc <width> <height> <input file> <output file> <fourcc value 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGB)> q <quality>\n");
+ printf("Currently supporting only I420 and NV12 input file formats.\n");
+ printf("Example: ./jpegenc 1024 768 input_file.yuv output.jpeg 0 50\n\n");
+ return;
+}
+
+
+void jpegenc_pic_param_init(VAEncPictureParameterBufferJPEG *pic_param,int width,int height,int quality, YUVComponentSpecs yuvComp)
+{
+ assert(pic_param);
+
+ pic_param->picture_width = width;
+ pic_param->picture_height = height;
+ pic_param->quality = quality;
+
+ pic_param->pic_flags.bits.profile = 0; //Profile = Baseline
+ pic_param->pic_flags.bits.progressive = 0; //Sequential encoding
+ pic_param->pic_flags.bits.huffman = 1; //Uses Huffman coding
+ pic_param->pic_flags.bits.interleaved = 0; //Input format is interleaved (YUV)
+ pic_param->pic_flags.bits.differential = 0; //non-Differential Encoding
+
+ pic_param->sample_bit_depth = 8; //only 8 bit sample depth is currently supported
+ pic_param->num_scan = 1;
+ pic_param->num_components = yuvComp.num_components; // Supporting only upto 3 components maximum
+ //set component_id Ci and Tqi
+ if(yuvComp.fourcc_val == VA_FOURCC_Y800) {
+ pic_param->component_id[0] = 0;
+ pic_param->quantiser_table_selector[0] = 0;
+ } else {
+ pic_param->component_id[0] = pic_param->quantiser_table_selector[0] = 0;
+ pic_param->component_id[1] = pic_param->quantiser_table_selector[1] = 1;
+ pic_param->component_id[2] = 2;
+ pic_param->quantiser_table_selector[2] = 1;
+ }
+
+ pic_param->quality = quality;
+}
+
+void jpegenc_qmatrix_init(VAQMatrixBufferJPEG *quantization_param, YUVComponentSpecs yuvComp)
+{
+ int i=0;
+ quantization_param->load_lum_quantiser_matrix = 1;
+
+ //LibVA expects the QM in zigzag order
+ for(i=0; i<NUM_QUANT_ELEMENTS; i++) {
+ quantization_param->lum_quantiser_matrix[i] = jpeg_luma_quant[jpeg_zigzag[i]];
+ }
+
+
+ if(yuvComp.fourcc_val == VA_FOURCC_Y800) {
+ quantization_param->load_chroma_quantiser_matrix = 0;
+ } else {
+ quantization_param->load_chroma_quantiser_matrix = 1;
+ for(i=0; i<NUM_QUANT_ELEMENTS; i++) {
+ quantization_param->chroma_quantiser_matrix[i] = jpeg_chroma_quant[jpeg_zigzag[i]];
+ }
+ }
+
+}
+
+void jpegenc_hufftable_init(VAHuffmanTableBufferJPEGBaseline *hufftable_param, YUVComponentSpecs yuvComp)
+{
+
+ hufftable_param->load_huffman_table[0] = 1; //Load Luma Hufftable
+ if(yuvComp.fourcc_val == VA_FOURCC_Y800) {
+ hufftable_param->load_huffman_table[1] = 0; //Do not load Chroma Hufftable for Y8
+ } else {
+ hufftable_param->load_huffman_table[1] = 1; //Load Chroma Hufftable for other formats
+ }
+
+ //Load Luma hufftable values
+ //Load DC codes
+ memcpy(hufftable_param->huffman_table[0].num_dc_codes, jpeg_hufftable_luma_dc+1, 16);
+ //Load DC Values
+ memcpy(hufftable_param->huffman_table[0].dc_values, jpeg_hufftable_luma_dc+17, 12);
+ //Load AC codes
+ memcpy(hufftable_param->huffman_table[0].num_ac_codes, jpeg_hufftable_luma_ac+1, 16);
+ //Load AC Values
+ memcpy(hufftable_param->huffman_table[0].ac_values, jpeg_hufftable_luma_ac+17, 162);
+ memset(hufftable_param->huffman_table[0].pad, 0, 2);
+
+
+ //Load Chroma hufftable values if needed
+ if(yuvComp.fourcc_val != VA_FOURCC_Y800) {
+ //Load DC codes
+ memcpy(hufftable_param->huffman_table[1].num_dc_codes, jpeg_hufftable_chroma_dc+1, 16);
+ //Load DC Values
+ memcpy(hufftable_param->huffman_table[1].dc_values, jpeg_hufftable_chroma_dc+17, 12);
+ //Load AC codes
+ memcpy(hufftable_param->huffman_table[1].num_ac_codes, jpeg_hufftable_chroma_ac+1, 16);
+ //Load AC Values
+ memcpy(hufftable_param->huffman_table[1].ac_values, jpeg_hufftable_chroma_ac+17, 162);
+ memset(hufftable_param->huffman_table[1].pad, 0, 2);
+
+ }
+
+}
+
+void jpegenc_slice_param_init(VAEncSliceParameterBufferJPEG *slice_param, YUVComponentSpecs yuvComp)
+{
+ slice_param->restart_interval = 0;
+
+ slice_param->num_components = yuvComp.num_components;
+
+ slice_param->components[0].component_selector = 1;
+ slice_param->components[0].dc_table_selector = 0;
+ slice_param->components[0].ac_table_selector = 0;
+
+ if(yuvComp.num_components > 1) {
+ slice_param->components[1].component_selector = 2;
+ slice_param->components[1].dc_table_selector = 1;
+ slice_param->components[1].ac_table_selector = 1;
+
+ slice_param->components[2].component_selector = 3;
+ slice_param->components[2].dc_table_selector = 1;
+ slice_param->components[2].ac_table_selector = 1;
+ }
+}
+
+
+void populate_quantdata(JPEGQuantSection *quantVal, int type)
+{
+ uint8_t zigzag_qm[NUM_QUANT_ELEMENTS];
+ int i;
+
+ quantVal->DQT = DQT;
+ quantVal->Pq = 0;
+ quantVal->Tq = type;
+ if(type == 0) {
+ for(i=0; i<NUM_QUANT_ELEMENTS; i++) {
+ zigzag_qm[i] = jpeg_luma_quant[jpeg_zigzag[i]];
+ }
+
+ memcpy(quantVal->Qk, zigzag_qm, NUM_QUANT_ELEMENTS);
+ } else {
+ for(i=0; i<NUM_QUANT_ELEMENTS; i++) {
+ zigzag_qm[i] = jpeg_chroma_quant[jpeg_zigzag[i]];
+ }
+ memcpy(quantVal->Qk, zigzag_qm, NUM_QUANT_ELEMENTS);
+ }
+ quantVal->Lq = 3 + NUM_QUANT_ELEMENTS;
+}
+
+void populate_frame_header(JPEGFrameHeader *frameHdr, YUVComponentSpecs yuvComp, int picture_width, int picture_height)
+{
+ int i=0;
+
+ frameHdr->SOF = SOF0;
+ frameHdr->Lf = 8 + (3 * yuvComp.num_components); //Size of FrameHeader in bytes without the Marker SOF
+ frameHdr->P = 8;
+ frameHdr->Y = picture_height;
+ frameHdr->X = picture_width;
+ frameHdr->Nf = yuvComp.num_components;
+
+ for(i=0; i<yuvComp.num_components; i++) {
+ frameHdr->JPEGComponent[i].Ci = i+1;
+
+ if(i == 0) {
+ frameHdr->JPEGComponent[i].Hi = yuvComp.y_h_subsample;
+ frameHdr->JPEGComponent[i].Vi = yuvComp.y_v_subsample;
+ frameHdr->JPEGComponent[i].Tqi = 0;
+
+ } else {
+ //Analyzing the sampling factors for U/V, they are 1 for all formats except for Y8.
+ //So, it is okay to have the code below like this. For Y8, we wont reach this code.
+ frameHdr->JPEGComponent[i].Hi = 1;
+ frameHdr->JPEGComponent[i].Vi = 1;
+ frameHdr->JPEGComponent[i].Tqi = 1;
+ }
+ }
+}
+
+void populate_huff_section_header(JPEGHuffSection *huffSectionHdr, int th, int tc)
+{
+ int i=0, totalCodeWords=0;
+
+ huffSectionHdr->DHT = DHT;
+ huffSectionHdr->Tc = tc;
+ huffSectionHdr->Th = th;
+
+ if(th == 0) { //If Luma
+
+ //If AC
+ if(tc == 1) {
+ memcpy(huffSectionHdr->Li, jpeg_hufftable_luma_ac+1, NUM_AC_RUN_SIZE_BITS);
+ memcpy(huffSectionHdr->Vij, jpeg_hufftable_luma_ac+17, NUM_AC_CODE_WORDS_HUFFVAL);
+ }
+
+ //If DC
+ if(tc == 0) {
+ memcpy(huffSectionHdr->Li, jpeg_hufftable_luma_dc+1, NUM_DC_RUN_SIZE_BITS);
+ memcpy(huffSectionHdr->Vij, jpeg_hufftable_luma_dc+17, NUM_DC_CODE_WORDS_HUFFVAL);
+ }
+
+ for(i=0; i<NUM_AC_RUN_SIZE_BITS; i++) {
+ totalCodeWords += huffSectionHdr->Li[i];
+ }
+
+ huffSectionHdr->Lh = 3 + 16 + totalCodeWords;
+
+ } else { //If Chroma
+ //If AC
+ if(tc == 1) {
+ memcpy(huffSectionHdr->Li, jpeg_hufftable_chroma_ac+1, NUM_AC_RUN_SIZE_BITS);
+ memcpy(huffSectionHdr->Vij, jpeg_hufftable_chroma_ac+17, NUM_AC_CODE_WORDS_HUFFVAL);
+ }
+
+ //If DC
+ if(tc == 0) {
+ memcpy(huffSectionHdr->Li, jpeg_hufftable_chroma_dc+1, NUM_DC_RUN_SIZE_BITS);
+ memcpy(huffSectionHdr->Vij, jpeg_hufftable_chroma_dc+17, NUM_DC_CODE_WORDS_HUFFVAL);
+ }
+
+ }
+}
+
+void populate_scan_header(JPEGScanHeader *scanHdr, YUVComponentSpecs yuvComp)
+{
+
+ scanHdr->SOS = SOS;
+ scanHdr->Ns = yuvComp.num_components;
+
+ //Y Component
+ scanHdr->ScanComponent[0].Csj = 1;
+ scanHdr->ScanComponent[0].Tdj = 0;
+ scanHdr->ScanComponent[0].Taj = 0;
+
+ if(yuvComp.num_components > 1) {
+ //U Component
+ scanHdr->ScanComponent[1].Csj = 2;
+ scanHdr->ScanComponent[1].Tdj = 1;
+ scanHdr->ScanComponent[1].Taj = 1;
+
+ //V Component
+ scanHdr->ScanComponent[2].Csj = 3;
+ scanHdr->ScanComponent[2].Tdj = 1;
+ scanHdr->ScanComponent[2].Taj = 1;
+ }
+
+ scanHdr->Ss = 0; //0 for Baseline
+ scanHdr->Se = 63; //63 for Baseline
+ scanHdr->Ah = 0; //0 for Baseline
+ scanHdr->Al = 0; //0 for Baseline
+
+ scanHdr->Ls = 3 + (yuvComp.num_components * 2) + 3;
+
+}
+
+
+int build_packed_jpeg_header_buffer(unsigned char **header_buffer, YUVComponentSpecs yuvComp, int picture_width, int picture_height, uint16_t restart_interval)
+{
+ bitstream bs;
+ int i=0, j=0;
+
+ bitstream_start(&bs);
+
+ //Add SOI
+ bitstream_put_ui(&bs, SOI, 16);
+
+ //Add AppData
+ bitstream_put_ui(&bs, APP0, 16); //APP0 marker
+ bitstream_put_ui(&bs, 16, 16); //Length excluding the marker
+ bitstream_put_ui(&bs, 0x4A, 8); //J
+ bitstream_put_ui(&bs, 0x46, 8); //F
+ bitstream_put_ui(&bs, 0x49, 8); //I
+ bitstream_put_ui(&bs, 0x46, 8); //F
+ bitstream_put_ui(&bs, 0x00, 8); //0
+ bitstream_put_ui(&bs, 1, 8); //Major Version
+ bitstream_put_ui(&bs, 1, 8); //Minor Version
+ bitstream_put_ui(&bs, 1, 8); //Density units 0:no units, 1:pixels per inch, 2: pixels per cm
+ bitstream_put_ui(&bs, 72, 16); //X density
+ bitstream_put_ui(&bs, 72, 16); //Y density
+ bitstream_put_ui(&bs, 0, 8); //Thumbnail width
+ bitstream_put_ui(&bs, 0, 8); //Thumbnail height
+
+ //Add QTable - Y
+ JPEGQuantSection quantLuma;
+ populate_quantdata(&quantLuma, 0);
+
+ bitstream_put_ui(&bs, quantLuma.DQT, 16);
+ bitstream_put_ui(&bs, quantLuma.Lq, 16);
+ bitstream_put_ui(&bs, quantLuma.Pq, 4);
+ bitstream_put_ui(&bs, quantLuma.Tq, 4);
+ for(i=0; i<NUM_QUANT_ELEMENTS; i++) {
+ bitstream_put_ui(&bs, quantLuma.Qk[i], 8);
+ }
+
+ //Add QTable - U/V
+ if(yuvComp.fourcc_val != VA_FOURCC_Y800) {
+ JPEGQuantSection quantChroma;
+ populate_quantdata(&quantChroma, 1);
+
+ bitstream_put_ui(&bs, quantChroma.DQT, 16);
+ bitstream_put_ui(&bs, quantChroma.Lq, 16);
+ bitstream_put_ui(&bs, quantChroma.Pq, 4);
+ bitstream_put_ui(&bs, quantChroma.Tq, 4);
+ for(i=0; i<NUM_QUANT_ELEMENTS; i++) {
+ bitstream_put_ui(&bs, quantChroma.Qk[i], 8);
+ }
+ }
+
+ //Add FrameHeader
+ JPEGFrameHeader frameHdr;
+ memset(&frameHdr,0,sizeof(JPEGFrameHeader));
+ populate_frame_header(&frameHdr, yuvComp, picture_width, picture_height);
+
+ bitstream_put_ui(&bs, frameHdr.SOF, 16);
+ bitstream_put_ui(&bs, frameHdr.Lf, 16);
+ bitstream_put_ui(&bs, frameHdr.P, 8);
+ bitstream_put_ui(&bs, frameHdr.Y, 16);
+ bitstream_put_ui(&bs, frameHdr.X, 16);
+ bitstream_put_ui(&bs, frameHdr.Nf, 8);
+ for(i=0; i<frameHdr.Nf;i++) {
+ bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Ci, 8);
+ bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Hi, 4);
+ bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Vi, 4);
+ bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Tqi, 8);
+ }
+
+ //Add HuffTable AC and DC for Y,U/V components
+ JPEGHuffSection acHuffSectionHdr, dcHuffSectionHdr;
+
+ for(i=0; (i<yuvComp.num_components && (i<=1)); i++) {
+ //Add DC component (Tc = 0)
+ populate_huff_section_header(&dcHuffSectionHdr, i, 0);
+
+ bitstream_put_ui(&bs, dcHuffSectionHdr.DHT, 16);
+ bitstream_put_ui(&bs, dcHuffSectionHdr.Lh, 16);
+ bitstream_put_ui(&bs, dcHuffSectionHdr.Tc, 4);
+ bitstream_put_ui(&bs, dcHuffSectionHdr.Th, 4);
+ for(j=0; j<NUM_DC_RUN_SIZE_BITS; j++) {
+ bitstream_put_ui(&bs, dcHuffSectionHdr.Li[j], 8);
+ }
+
+ for(j=0; j<NUM_DC_CODE_WORDS_HUFFVAL; j++) {
+ bitstream_put_ui(&bs, dcHuffSectionHdr.Vij[j], 8);
+ }
+
+ //Add AC component (Tc = 1)
+ populate_huff_section_header(&acHuffSectionHdr, i, 1);
+
+ bitstream_put_ui(&bs, acHuffSectionHdr.DHT, 16);
+ bitstream_put_ui(&bs, acHuffSectionHdr.Lh, 16);
+ bitstream_put_ui(&bs, acHuffSectionHdr.Tc, 4);
+ bitstream_put_ui(&bs, acHuffSectionHdr.Th, 4);
+ for(j=0; j<NUM_AC_RUN_SIZE_BITS; j++) {
+ bitstream_put_ui(&bs, acHuffSectionHdr.Li[j], 8);
+ }
+
+ for(j=0; j<NUM_AC_CODE_WORDS_HUFFVAL; j++) {
+ bitstream_put_ui(&bs, acHuffSectionHdr.Vij[j], 8);
+ }
+
+ }
+
+ //Add Restart Interval if restart_interval is not 0
+ if(restart_interval != 0) {
+ JPEGRestartSection restartHdr;
+ restartHdr.DRI = DRI;
+ restartHdr.Lr = 4;
+ restartHdr.Ri = restart_interval;
+
+ bitstream_put_ui(&bs, restartHdr.DRI, 16);
+ bitstream_put_ui(&bs, restartHdr.Lr, 16);
+ bitstream_put_ui(&bs, restartHdr.Ri, 16);
+ }
+
+ //Add ScanHeader
+ JPEGScanHeader scanHdr;
+ populate_scan_header(&scanHdr, yuvComp);
+
+ bitstream_put_ui(&bs, scanHdr.SOS, 16);
+ bitstream_put_ui(&bs, scanHdr.Ls, 16);
+ bitstream_put_ui(&bs, scanHdr.Ns, 8);
+
+ for(i=0; i<scanHdr.Ns; i++) {
+ bitstream_put_ui(&bs, scanHdr.ScanComponent[i].Csj, 8);
+ bitstream_put_ui(&bs, scanHdr.ScanComponent[i].Tdj, 4);
+ bitstream_put_ui(&bs, scanHdr.ScanComponent[i].Taj, 4);
+ }
+
+ bitstream_put_ui(&bs, scanHdr.Ss, 8);
+ bitstream_put_ui(&bs, scanHdr.Se, 8);
+ bitstream_put_ui(&bs, scanHdr.Ah, 4);
+ bitstream_put_ui(&bs, scanHdr.Al, 4);
+
+ bitstream_end(&bs);
+ *header_buffer = (unsigned char *)bs.buffer;
+
+ return bs.bit_offset;
+}
+
+//Upload the yuv image from the file to the VASurface
+void upload_yuv_to_surface(VADisplay va_dpy, FILE *yuv_fp, VASurfaceID surface_id, YUVComponentSpecs yuvComp, int picture_width, int picture_height, int frame_size)
+{
+
+ VAImage surface_image;
+ VAStatus va_status;
+ void *surface_p = NULL;
+ unsigned char newImageBuffer[frame_size];
+ unsigned char *y_src, *u_src, *v_src;
+ unsigned char *y_dst, *u_dst, *v_dst;
+ int y_size = picture_width * picture_height;
+ int u_size = (picture_width >> 1) * (picture_height >> 1);
+ int row, col;
+ size_t n_items;
+
+ memset(newImageBuffer,0,frame_size);
+ do {
+ n_items = fread(newImageBuffer, frame_size, 1, yuv_fp);
+ } while (n_items != 1);
+
+ va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
+ CHECK_VASTATUS(va_status,"vaDeriveImage");
+
+ vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
+ assert(VA_STATUS_SUCCESS == va_status);
+
+ y_src = newImageBuffer;
+ u_src = newImageBuffer + y_size; /* UV offset for NV12 */
+ v_src = newImageBuffer + y_size + u_size;
+
+ y_dst = surface_p + surface_image.offsets[0];
+ u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */
+ v_dst = surface_p + surface_image.offsets[2];
+
+ /* Y plane */
+ for (row = 0; row < surface_image.height; row++) {
+ memcpy(y_dst, y_src, surface_image.width);
+ y_dst += surface_image.pitches[0];
+ y_src += picture_width;
+ }
+
+ if(yuvComp.num_components > 1 ) {
+
+ switch(yuvComp.fourcc_val) {
+
+ case VA_FOURCC_NV12: {
+ for (row = 0; row < surface_image.height/2; row++) {
+ memcpy(u_dst, u_src, surface_image.width);
+ u_dst += surface_image.pitches[1];
+ u_src += (picture_width);
+ }
+ break;
+ }
+
+ case VA_FOURCC_I420: {
+ for (row = 0; row < surface_image.height / 2; row++) {
+ for (col = 0; col < surface_image.width / 2; col++) {
+ u_dst[col * 2] = u_src[col];
+ u_dst[col * 2 + 1] = v_src[col];
+ }
+
+ u_dst += surface_image.pitches[1];
+ u_src += (picture_width / 2);
+ v_src += (picture_width / 2);
+ }
+
+ break;
+ }
+
+ //TO DO: Code for below formats needs to be fixed.
+ //This will come as enhancement to the feature.
+ case VA_FOURCC_UYVY:
+ case VA_FOURCC_YUY2: {
+ const int U = 1;
+ const int V = 2;
+
+ u_dst = surface_p + surface_image.offsets[U];
+ v_dst = surface_p + surface_image.offsets[V];
+
+ for (row = 0; row < surface_image.height / 2; row++) {
+ memcpy(u_dst, u_src, surface_image.width / 2);
+ memcpy(v_dst, v_src, surface_image.width / 2);
+ u_dst += surface_image.pitches[U];
+ v_dst += surface_image.pitches[V];
+ u_src += (picture_width / 2);
+ v_src += (picture_width / 2);
+ }
+
+ break;
+ }
+
+ case VA_FOURCC_444P: {
+ const int U = 1;
+ const int V = 2;
+
+ u_dst = surface_p + surface_image.offsets[U];
+ v_dst = surface_p + surface_image.offsets[V];
+
+ for (row = 0; row < surface_image.height; row++) {
+ memcpy(u_dst, u_src, surface_image.width);
+ memcpy(v_dst, v_src, surface_image.width);
+ u_dst += surface_image.pitches[U];
+ v_dst += surface_image.pitches[V];
+ u_src += (picture_width);
+ v_src += (picture_width);
+ }
+ break;
+ }
+
+ default: {
+ //processing like Y8
+ break;
+ }
+ } //end of switch
+ } //end of if
+
+ vaUnmapBuffer(va_dpy, surface_image.buf);
+ vaDestroyImage(va_dpy, surface_image.image_id);
+
+}
+
+
+
+void init_yuv_component(YUVComponentSpecs *yuvComponent, int yuv_type, int *surface_type, VASurfaceAttrib *fourcc)
+{
+
+ //<fourcc value 0(NV12)/1(UYVY)/2(YUY2)/3(Y8)/4(RGB)>
+ switch(yuv_type)
+ {
+ case 0 : //I420
+ case 1 : { //NV12
+ yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV420;
+ if(yuv_type == 0) {
+ yuvComponent->fourcc_val = VA_FOURCC_I420;
+ fourcc->value.value.i = VA_FOURCC_NV12;
+ } else {
+ yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_NV12;
+ }
+ yuvComponent->num_components = 3;
+ yuvComponent->y_h_subsample = 2;
+ yuvComponent->y_v_subsample = 2;
+ yuvComponent->u_h_subsample = 1;
+ yuvComponent->u_v_subsample = 1;
+ yuvComponent->v_h_subsample = 1;
+ yuvComponent->v_v_subsample = 1;
+ break;
+ }
+
+ case 2: { //UYVY
+ yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV422;
+ yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_UYVY;
+ yuvComponent->num_components = 3;
+ yuvComponent->y_h_subsample = 2;
+ yuvComponent->y_v_subsample = 1;
+ yuvComponent->u_h_subsample = 1;
+ yuvComponent->u_v_subsample = 1;
+ yuvComponent->v_h_subsample = 1;
+ yuvComponent->v_v_subsample = 1;
+ break;
+ }
+
+ case 3: { //YUY2
+ yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV422;
+ yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_YUY2;
+ yuvComponent->num_components = 3;
+ yuvComponent->y_h_subsample = 2;
+ yuvComponent->y_v_subsample = 1;
+ yuvComponent->u_h_subsample = 1;
+ yuvComponent->u_v_subsample = 1;
+ yuvComponent->v_h_subsample = 1;
+ yuvComponent->v_v_subsample = 1;
+ break;
+ }
+
+ case 4: { //Y8
+ yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV400;
+ yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_Y800;
+ yuvComponent->num_components = 1;
+ yuvComponent->y_h_subsample = 1;
+ yuvComponent->y_v_subsample = 0;
+ yuvComponent->u_h_subsample = 0;
+ yuvComponent->u_v_subsample = 0;
+ yuvComponent->v_h_subsample = 0;
+ yuvComponent->v_v_subsample = 0;
+ break;
+ }
+
+ case 5: { //RGB or YUV444
+ yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV444;
+ yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_444P;
+ yuvComponent->num_components = 3;
+ yuvComponent->y_h_subsample = 1;
+ yuvComponent->y_v_subsample = 1;
+ yuvComponent->u_h_subsample = 1;
+ yuvComponent->u_v_subsample = 1;
+ yuvComponent->v_h_subsample = 1;
+ yuvComponent->v_v_subsample = 1;
+ break;
+ }
+
+ default: {
+ printf("Unsupported format:\n");
+ show_help();
+ break;
+ }
+
+ }
+
+}
+
+int encode_input_image(FILE *yuv_fp, FILE *jpeg_fp, int picture_width, int picture_height, int frame_size, int yuv_type, int quality)
+{
+ int num_entrypoints,enc_entrypoint;
+ int major_ver, minor_ver;
+ int surface_type;
+ VAEntrypoint entrypoints[5];
+ VASurfaceAttrib fourcc;
+ VAConfigAttrib attrib[2];
+ VADisplay va_dpy;
+ VAStatus va_status;
+ VAConfigID config_id;
+ VASurfaceID surface_id;
+ VAContextID context_id;
+ VABufferID pic_param_buf_id; /* Picture parameter id*/
+ VABufferID slice_param_buf_id; /* Slice parameter id, only 1 slice per frame in jpeg encode */
+ VABufferID codedbuf_buf_id; /* Output buffer id, compressed data */
+ VABufferID packed_raw_header_param_buf_id; /* Header parameter buffer id */
+ VABufferID packed_raw_header_buf_id; /* Header buffer id */
+ VABufferID qmatrix_buf_id; /* Quantization Matrix id */
+ VABufferID huffmantable_buf_id; /* Huffman table id*/
+ VAEncPictureParameterBufferJPEG pic_param; /* Picture parameter buffer */
+ VAEncSliceParameterBufferJPEG slice_param; /* Slice parameter buffer */
+ VAQMatrixBufferJPEG quantization_param; /* Quantization Matrix buffer */
+ VAHuffmanTableBufferJPEGBaseline hufftable_param; /* Huffmantable buffer */
+ YUVComponentSpecs yuvComponent;
+ int writeToFile = 1;
+
+
+ fourcc.type =VASurfaceAttribPixelFormat;
+ fourcc.flags=VA_SURFACE_ATTRIB_SETTABLE;
+ fourcc.value.type=VAGenericValueTypeInteger;
+
+ init_yuv_component(&yuvComponent, yuv_type, &surface_type, &fourcc);
+
+ /* 1. Initialize the va driver */
+ va_dpy = va_open_display();
+ va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
+ assert(va_status == VA_STATUS_SUCCESS);
+
+ /* 2. Query for the entrypoints for the JPEGBaseline profile */
+ va_status = vaQueryConfigEntrypoints(va_dpy, VAProfileJPEGBaseline, entrypoints, &num_entrypoints);
+ CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
+ // We need picture level encoding (VAEntrypointEncPicture). Find if it is supported.
+ for (enc_entrypoint = 0; enc_entrypoint < num_entrypoints; enc_entrypoint++) {
+ if (entrypoints[enc_entrypoint] == VAEntrypointEncPicture)
+ break;
+ }
+ if (enc_entrypoint == num_entrypoints) {
+ /* No JPEG Encode (VAEntrypointEncPicture) entry point found */
+ assert(0);
+ }
+
+ /* 3. Query for the Render Target format supported */
+ attrib[0].type = VAConfigAttribRTFormat;
+ attrib[1].type = VAConfigAttribEncJPEG;
+ vaGetConfigAttributes(va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture, &attrib[0], 2);
+
+ // RT should be one of below.
+ if(!((attrib[0].value & VA_RT_FORMAT_YUV420) || (attrib[0].value & VA_RT_FORMAT_YUV422)
+ ||(attrib[0].value & VA_RT_FORMAT_YUV444) || (attrib[0].value & VA_RT_FORMAT_YUV400)))
+ {
+ /* Did not find the supported RT format */
+ assert(0);
+ }
+
+ VAConfigAttribValEncJPEG jpeg_attrib_val;
+ jpeg_attrib_val.value = attrib[1].value;
+
+ /* Set JPEG profile attribs */
+ jpeg_attrib_val.bits.arithmatic_coding_mode = 0;
+ jpeg_attrib_val.bits.progressive_dct_mode = 0;
+ jpeg_attrib_val.bits.non_interleaved_mode = 1;
+ jpeg_attrib_val.bits.differential_mode = 0;
+
+ attrib[1].value = jpeg_attrib_val.value;
+
+ /* 4. Create Config for the profile=VAProfileJPEGBaseline, entrypoint=VAEntrypointEncPicture,
+ * with RT format attribute */
+ va_status = vaCreateConfig(va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture,
+ &attrib[0], 2, &config_id);
+ CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
+
+ /* 5. Create Surface for the input picture */
+ va_status = vaCreateSurfaces(va_dpy, surface_type, picture_width, picture_height,
+ &surface_id, 1, &fourcc, 1);
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces");
+
+ //Map the input yuv file to the input surface created with the surface_id
+ upload_yuv_to_surface(va_dpy, yuv_fp, surface_id, yuvComponent, picture_width, picture_height, frame_size);
+
+ /* 6. Create Context for the encode pipe*/
+ va_status = vaCreateContext(va_dpy, config_id, picture_width, picture_height,
+ VA_PROGRESSIVE, &surface_id, 1, &context_id);
+ CHECK_VASTATUS(va_status, "vaCreateContext");
+
+ /* Create buffer for Encoded data to be stored */
+ va_status = vaCreateBuffer(va_dpy, context_id, VAEncCodedBufferType,
+ frame_size, 1, NULL, &codedbuf_buf_id);
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");
+
+ //Initialize the picture parameter buffer
+ pic_param.coded_buf = codedbuf_buf_id;
+ jpegenc_pic_param_init(&pic_param, picture_width, picture_height, quality, yuvComponent);
+
+ /* 7. Create buffer for the picture parameter */
+ va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
+ sizeof(VAEncPictureParameterBufferJPEG), 1, &pic_param, &pic_param_buf_id);
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");
+
+ //Load the QMatrix
+ jpegenc_qmatrix_init(&quantization_param, yuvComponent);
+
+ /* 8. Create buffer for Quantization Matrix */
+ va_status = vaCreateBuffer(va_dpy, context_id, VAQMatrixBufferType,
+ sizeof(VAQMatrixBufferJPEG), 1, &quantization_param, &qmatrix_buf_id);
+ CHECK_VASTATUS(va_status, "vaCreateBuffer");
+
+ //Load the Huffman Tables
+ jpegenc_hufftable_init(&hufftable_param, yuvComponent);
+
+ /* 9. Create buffer for Huffman Tables */
+ va_status = vaCreateBuffer(va_dpy, context_id, VAHuffmanTableBufferType,
+ sizeof(VAHuffmanTableBufferJPEGBaseline), 1, &hufftable_param, &huffmantable_buf_id);
+ CHECK_VASTATUS(va_status, "vaCreateBuffer");
+
+ //Initialize the slice parameter buffer
+ jpegenc_slice_param_init(&slice_param, yuvComponent);
+
+ /* 10. Create buffer for slice parameter */
+ va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType,
+ sizeof(slice_param), 1, &slice_param, &slice_param_buf_id);
+ CHECK_VASTATUS(va_status, "vaCreateBuffer");
+
+ //Pack headers and send using Raw data buffer
+ VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
+ unsigned int length_in_bits;
+ unsigned char *packed_header_buffer = NULL;
+
+ length_in_bits = build_packed_jpeg_header_buffer(&packed_header_buffer, yuvComponent, picture_width, picture_height, slice_param.restart_interval);
+ packed_header_param_buffer.type = VAEncPackedHeaderRawData;
+ packed_header_param_buffer.bit_length = length_in_bits;
+ packed_header_param_buffer.has_emulation_bytes = 0;
+
+ /* 11. Create raw buffer for header */
+ va_status = vaCreateBuffer(va_dpy,
+ context_id,
+ VAEncPackedHeaderParameterBufferType,
+ sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
+ &packed_raw_header_param_buf_id);
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");
+
+ va_status = vaCreateBuffer(va_dpy,
+ context_id,
+ VAEncPackedHeaderDataBufferType,
+ (length_in_bits + 7) / 8, 1, packed_header_buffer,
+ &packed_raw_header_buf_id);
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");
+
+ /* 12. Begin picture */
+ va_status = vaBeginPicture(va_dpy, context_id, surface_id);
+ CHECK_VASTATUS(va_status, "vaBeginPicture");
+
+ /* 13. Render picture for all the VA buffers created */
+ va_status = vaRenderPicture(va_dpy,context_id, &pic_param_buf_id, 1);
+ CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+ va_status = vaRenderPicture(va_dpy,context_id, &qmatrix_buf_id, 1);
+ CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+ va_status = vaRenderPicture(va_dpy,context_id, &huffmantable_buf_id, 1);
+ CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+ va_status = vaRenderPicture(va_dpy,context_id, &slice_param_buf_id, 1);
+ CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+ va_status = vaRenderPicture(va_dpy,context_id, &packed_raw_header_param_buf_id, 1);
+ CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+ va_status = vaRenderPicture(va_dpy,context_id, &packed_raw_header_buf_id, 1);
+ CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+ va_status = vaEndPicture(va_dpy,context_id);
+ CHECK_VASTATUS(va_status, "vaEndPicture");
+
+ if (writeToFile) {
+ VASurfaceStatus surface_status;
+ size_t w_items;
+ VACodedBufferSegment *coded_buffer_segment;
+ unsigned char *coded_mem;
+ int slice_data_length;
+
+ va_status = vaSyncSurface(va_dpy, surface_id);
+ CHECK_VASTATUS(va_status, "vaSyncSurface");
+
+ surface_status = 0;
+ va_status = vaQuerySurfaceStatus(va_dpy, surface_id, &surface_status);
+ CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
+
+ va_status = vaMapBuffer(va_dpy, codedbuf_buf_id, (void **)(&coded_buffer_segment));
+ CHECK_VASTATUS(va_status,"vaMapBuffer");
+
+ coded_mem = coded_buffer_segment->buf;
+
+ if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
+ vaUnmapBuffer(va_dpy, codedbuf_buf_id);
+ printf("ERROR......Coded buffer too small\n");
+ }
+
+
+ slice_data_length = coded_buffer_segment->size;
+
+ do {
+ w_items = fwrite(coded_mem, slice_data_length, 1, jpeg_fp);
+ } while (w_items != 1);
+
+ va_status = vaUnmapBuffer(va_dpy, codedbuf_buf_id);
+ CHECK_VASTATUS(va_status, "vaUnmapBuffer");
+ }
+
+ vaDestroyBuffer(va_dpy, pic_param_buf_id);
+ vaDestroyBuffer(va_dpy, qmatrix_buf_id);
+ vaDestroyBuffer(va_dpy, slice_param_buf_id);
+ vaDestroyBuffer(va_dpy, huffmantable_buf_id);
+ vaDestroyBuffer(va_dpy, codedbuf_buf_id);
+ vaDestroyBuffer(va_dpy, packed_raw_header_param_buf_id);
+ vaDestroyBuffer(va_dpy, packed_raw_header_buf_id);
+ vaDestroySurfaces(va_dpy,&surface_id,1);
+ vaDestroyContext(va_dpy,context_id);
+ vaDestroyConfig(va_dpy,config_id);
+ vaTerminate(va_dpy);
+ va_close_display(va_dpy);
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ FILE *yuv_fp;
+ FILE *jpeg_fp;
+ off_t file_size;
+ clock_t start_time, finish_time;
+ unsigned int duration;
+ unsigned int yuv_type = 0;
+ int quality = 0;
+ unsigned int picture_width = 0;
+ unsigned int picture_height = 0;
+ unsigned int frame_size = 0;
+
+ va_init_display_args(&argc, argv);
+
+ if(argc != 7) {
+ show_help();
+ return -1;
+ }
+
+ picture_width = atoi(argv[1]);
+ picture_height = atoi(argv[2]);
+ yuv_type = atoi(argv[5]);
+ quality = atoi(argv[6]);
+
+ yuv_fp = fopen(argv[3],"rb");
+ if ( yuv_fp == NULL){
+ printf("Can't open input YUV file\n");
+ return -1;
+ }
+
+ fseeko(yuv_fp, (off_t)0, SEEK_END);
+ file_size = ftello(yuv_fp);
+
+ //<input file type: 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGB)>
+ switch(yuv_type)
+ {
+ case 0 : //I420
+ case 1 : { //NV12
+ frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ;
+ break;
+ }
+
+ case 2: //UYVY
+ case 3: { //YUY2
+ frame_size = 2 * (picture_width * picture_height);
+ break;
+ }
+
+ case 4: { //Y8
+ frame_size = picture_width * picture_height;
+ break;
+ }
+
+ case 5: { //RGB or YUV444
+ frame_size = 3 * (picture_width * picture_height) ;
+ break;
+ }
+
+ default: {
+ printf("Unsupported format:\n");
+ show_help();
+ break;
+ }
+
+ }
+
+ if ( (file_size < frame_size) || (file_size % frame_size) ) {
+ fclose(yuv_fp);
+ printf("The YUV file's size is not correct\n");
+ return -1;
+ }
+
+ fseeko(yuv_fp, (off_t)0, SEEK_SET);
+
+ jpeg_fp = fopen(argv[4], "wb");
+ if ( jpeg_fp == NULL) {
+ fclose(yuv_fp);
+ printf("Can't open output destination jpeg file\n");
+ return -1;
+ }
+
+ start_time = clock();
+ encode_input_image(yuv_fp, jpeg_fp, picture_width, picture_height, frame_size, yuv_type, quality);
+ if(yuv_fp != NULL) fclose(yuv_fp);
+ if(jpeg_fp != NULL) fclose(jpeg_fp);
+ finish_time = clock();
+ duration = finish_time - start_time;
+ printf("Encoding finished in %u ticks\n", duration);
+
+ return 0;
+}
+