Added a JPEG HW encoder's wrapper into libmix.

BZ: 150063

Issue: facilitating LibVA JPEG HW capability's users.

Solution: added that capability's wrapper into libmix.

Change-Id: I6218db6c1459278a0d4b89ef5bafe42288a11de5
Signed-off-by: SUN,Jing <jing.a.sun@intel.com>
diff --git a/Android.mk b/Android.mk
index 1b7383d..2639e2b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -9,6 +9,9 @@
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/videodecoder/Android.mk
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/videoencoder/Android.mk
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/imagedecoder/Android.mk
+ifneq ($(TARGET_BOARD_PLATFORM),baytrail)
+include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/imageencoder/Android.mk
+endif
 ifeq ($(ENABLE_IMG_GRAPHICS),)
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/videovpp/Android.mk
 endif
diff --git a/imageencoder/Android.mk b/imageencoder/Android.mk
new file mode 100644
index 0000000..ff5b01b
--- /dev/null
+++ b/imageencoder/Android.mk
@@ -0,0 +1,44 @@
+###############################################
+#             libmix_imageencoder             #
+###############################################
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= ImageEncoder.cpp
+
+LOCAL_C_INCLUDES += \
+    $(TARGET_OUT_HEADERS)/libva
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    liblog \
+    libva \
+    libva-android \
+    libva-tpi
+
+LOCAL_COPY_HEADERS_TO  := libmix_imageencoder
+
+LOCAL_COPY_HEADERS := ImageEncoder.h
+
+LOCAL_MODULE := libmix_imageencoder
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_SHARED_LIBRARY)
+
+
+###############################################
+#   libmix_imageencoder's Test Application    #
+###############################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= test/main.cpp
+
+LOCAL_C_INCLUDES += \
+    $(TARGET_OUT_HEADERS)/libva \
+    $(TARGET_OUT_HEADERS)/libmix_imageencoder
+
+LOCAL_SHARED_LIBRARIES := \
+    libmix_imageencoder
+
+LOCAL_MODULE := libmix_imageencoder_tester
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
diff --git a/imageencoder/ImageEncoder.cpp b/imageencoder/ImageEncoder.cpp
new file mode 100644
index 0000000..ae9232b
--- /dev/null
+++ b/imageencoder/ImageEncoder.cpp
@@ -0,0 +1,594 @@
+/*#define LOG_NDEBUG 0*/
+#define LOG_TAG "IntelImageEncoder"
+
+#include <cutils/log.h>
+#include "ImageEncoder.h"
+
+IntelImageEncoder::IntelImageEncoder(void)
+{
+	/* Initialize variables */
+	encoder_status = LIBVA_UNINITIALIZED;
+	quality = INTEL_IMAGE_ENCODER_DEFAULT_QUALITY;
+
+	va_dpy = NULL;
+	memset((void *)&va_configattrib, 0, sizeof(va_configattrib));
+
+	images_count = 0;
+	memset((void *)va_surfaceid, 0x0, sizeof(va_surfaceid));
+	memset((void *)surface_width, 0x0, sizeof(surface_width));
+	memset((void *)surface_height, 0x0, sizeof(surface_height));
+	memset((void *)surface_fourcc, 0x0, sizeof(surface_fourcc));
+
+	va_configid = 0;
+	va_contextid = 0;
+	context_width = 0;
+	context_height = 0;
+	context_fourcc = 0;
+	va_codedbufferid = 0;
+	coded_buf_size = 0;
+
+	reserved_image_seq = -1;
+
+	LOGV("IntelImageEncoder: done\n");
+}
+
+int IntelImageEncoder::initializeEncoder(void)
+{
+	int i =0;
+	VAStatus va_status;
+	int display_num = 0;
+	int major_version = -1, minor_version = -1;
+	const char *driver_version = NULL;
+	VAEntrypoint va_entrypoints[5];
+	int va_entrypoints_count = 0;
+
+	if (encoder_status != LIBVA_UNINITIALIZED) {
+		LOGE("initializeEncoder: already initialized!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	/* Get display */
+	va_dpy = vaGetDisplay(&display_num);
+	if (NULL == va_dpy) {
+		LOGE("initializeEncoder: vaGetDisplay failed!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	/* Initialize */
+	va_status = vaInitialize(va_dpy, &major_version, &minor_version);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("initializeEncoder: vaInitialize failed (%d)!\n", va_status);
+		return va_status;
+	}
+	LOGV("initializeEncoder: LibVA version: %d.%d\n", major_version, minor_version);
+
+	/* Query driver version */
+	driver_version = vaQueryVendorString(va_dpy);
+	if (NULL == driver_version) {
+		LOGE("initializeEncoder: vaQueryVendorString failed!\n");
+		vaTerminate(va_dpy);
+		va_dpy = NULL;
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+	LOGV("initializeEncoder: Driver version: %s\n", driver_version);
+
+	/* Query JPEG baseline encoding's entrypoint */
+	va_status = vaQueryConfigEntrypoints(va_dpy, VAProfileJPEGBaseline, va_entrypoints,
+										&va_entrypoints_count);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("initializeEncoder: vaQueryConfigEntrypoints failed (%d)!\n", va_status);
+		vaTerminate(va_dpy);
+		va_dpy = NULL;
+		return va_status;
+	}
+
+	for (i=0; i < va_entrypoints_count; ++i) {
+		if (VAEntrypointEncPicture == va_entrypoints[i])
+			break;
+	}
+	if (i == va_entrypoints_count) {
+		LOGE("initializeEncoder: no JPEG Baseline encoding entrypoint was found!\n");
+		vaTerminate(va_dpy);
+		va_dpy = NULL;
+		return VA_STATUS_ERROR_UNIMPLEMENTED;
+	}
+
+	/* Get supported configuration attributes */
+	va_configattrib.type = VAConfigAttribRTFormat;
+	va_status = vaGetConfigAttributes(va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture,
+									&va_configattrib, 1);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("initializeEncoder: vaGetConfigAttributes failed (%d)!\n", va_status);
+		vaTerminate(va_dpy);
+		va_dpy = NULL;
+		memset((void *)&va_configattrib, 0x0, sizeof(va_configattrib));
+		return va_status;
+	}
+
+	encoder_status = LIBVA_INITIALIZED;
+	LOGV("initializeEncoder: done\n");
+	return VA_STATUS_SUCCESS;
+}
+
+int IntelImageEncoder::createSourceSurface(int source_type, void *source_buffer,
+						unsigned int width,unsigned int height,
+						unsigned int stride, unsigned int fourcc,
+						int *image_seqp)
+{
+	int i =0;
+	VAStatus va_status;
+	VASurfaceAttribExternalBuffers va_surfacebuf;
+	VASurfaceAttrib va_surfaceattrib[2];
+	unsigned long ptr = 0;
+
+	if (LIBVA_UNINITIALIZED == encoder_status) {
+		LOGE("createSourceSurface: uninitialized, not ready to create surface!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if (images_count > INTEL_IMAGE_ENCODER_MAX_BUFFERS) {
+		LOGE("createSourceSurface: the max supported count was already reached!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if ((source_type != SURFACE_TYPE_USER_PTR) &&
+	(source_type != SURFACE_TYPE_GRALLOC)) {
+		LOGE("createSourceSurface: buffer type 0x%x was not supported!\n", source_type);
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	if (NULL == source_buffer) {
+		LOGE("createSourceSurface: the input buffer address can't be null!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	} else if ((unsigned int)source_buffer & 0xFFF) {
+		LOGE("createSourceSurface: the input buffer wasn't aligned to 4096!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	if (stride % INTEL_IMAGE_ENCODER_REQUIRED_STRIDE) {
+		LOGE("createSourceSurface: the stride value %d is not alligned to %d!\n",
+			stride, INTEL_IMAGE_ENCODER_REQUIRED_STRIDE);
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	if ((width % 2) || (height % 2)) {
+		LOGE("createSourceSurface: only even dimensions were supportd!\n");
+		return VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED;
+	}
+
+	if (((fourcc != VA_RT_FORMAT_YUV420) && (fourcc != VA_RT_FORMAT_YUV422)) ||
+		!(fourcc & va_configattrib.value)) {
+		/* Currently supported image formats:
+		 * #define VA_RT_FORMAT_YUV420	0x00000001
+		 * #define VA_RT_FORMAT_YUV422	0x00000002
+		 */
+		LOGE("createSourceSurface: the image format %d was not supported!\n", fourcc);
+		return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
+	}
+
+	/* Find the first available image sequential number */
+	for (i=0; i<INTEL_IMAGE_ENCODER_MAX_BUFFERS; ++i) {
+		if (0 == va_surfaceid[i]) { /* Empty */
+			break;
+		}
+	}
+
+	/* Allocate a source surface */
+	if (VA_RT_FORMAT_YUV420 == fourcc)
+		va_surfacebuf.pixel_format = VA_FOURCC_NV12;
+	else if (VA_RT_FORMAT_YUV422 == fourcc)
+		va_surfacebuf.pixel_format = VA_FOURCC_YV16;
+	va_surfacebuf.width = width;
+	va_surfacebuf.height = height;
+	va_surfacebuf.data_size = stride * height * 1.5;
+	va_surfacebuf.num_buffers = 1;
+	va_surfacebuf.num_planes = 3;
+	va_surfacebuf.pitches[0] = stride;
+	va_surfacebuf.pitches[1] = stride;
+	va_surfacebuf.pitches[2] = stride;
+	va_surfacebuf.pitches[3] = 0;
+	va_surfacebuf.offsets[0] = 0;
+	va_surfacebuf.offsets[1] = stride * height;
+	va_surfacebuf.offsets[2] = va_surfacebuf.offsets[1];
+	va_surfacebuf.offsets[3] = 0;
+	va_surfacebuf.buffers = (unsigned long *)&ptr;
+	*(va_surfacebuf.buffers) = (unsigned long)source_buffer;
+	va_surfacebuf.flags = 0;
+	va_surfacebuf.private_data = NULL;
+	va_surfaceattrib[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
+	va_surfaceattrib[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
+	va_surfaceattrib[0].value.type = VAGenericValueTypeInteger;
+	va_surfaceattrib[0].value.value.i = source_type;
+	va_surfaceattrib[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
+	va_surfaceattrib[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
+	va_surfaceattrib[1].value.type = VAGenericValueTypePointer;
+	va_surfaceattrib[1].value.value.p = (void *)&va_surfacebuf;
+
+	va_status = vaCreateSurfaces(va_dpy, fourcc, width, height,
+					&va_surfaceid[i], 1, va_surfaceattrib, 2);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("createSourceSurface: vaCreateSurfaces failed (%d)!\n", va_status);
+		va_surfaceid[i] = 0;
+		return va_status;
+	}
+
+	surface_width[i] = width;
+	surface_height[i] = height;
+	surface_fourcc[i] = fourcc;
+
+	*image_seqp = i;
+	++images_count;
+
+	return VA_STATUS_SUCCESS;
+}
+
+int IntelImageEncoder::createContext(int first_image_seq, unsigned int *max_coded_sizep)
+{
+	VAStatus va_status;
+	VAConfigAttrib va_cur_configattrib;
+
+	*max_coded_sizep = 0;
+
+	if (LIBVA_UNINITIALIZED == encoder_status) {
+		LOGE("createContext: uninitialized, not ready to create context!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	} else if (encoder_status >= LIBVA_CONTEXT_CREATED) {
+		LOGE("createContext: there already is an active context!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if ((first_image_seq < 0) ||
+		(first_image_seq >= INTEL_IMAGE_ENCODER_MAX_BUFFERS) ||
+		(0 == va_surfaceid[first_image_seq])) {
+		LOGE("createContext: invalid image sequential number!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	context_width = surface_width[first_image_seq];
+	context_height = surface_height[first_image_seq];
+	context_fourcc = surface_fourcc[first_image_seq];
+
+	/* Create a config */
+	va_cur_configattrib.type = VAConfigAttribRTFormat;
+	va_cur_configattrib.value = context_fourcc;
+	va_status = vaCreateConfig(va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture,
+								&va_cur_configattrib, 1, &va_configid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("createContext: vaCreateConfig failed (%d)!\n", va_status);
+		va_configid = 0;
+		return va_status;
+	}
+
+	/* Create a context */
+	va_status = vaCreateContext(va_dpy, va_configid, context_width, context_height,
+					VA_PROGRESSIVE, &va_surfaceid[first_image_seq], 1, &va_contextid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("createContext: vaCreateContext failed (%d)!\n", va_status);
+		va_contextid = 0;
+		vaDestroyConfig(va_dpy, va_configid);
+		va_configid = 0;
+		return va_status;
+	}
+
+
+	/* Create a coded buffer */
+	coded_buf_size = (((context_width+15)/16)*((context_height+15)/16)*160) + 640;
+	coded_buf_size = (coded_buf_size+0xf) & ~0xf;
+	va_status = vaCreateBuffer(va_dpy, va_contextid, VAEncCodedBufferType, coded_buf_size,
+					1, NULL, &va_codedbufferid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("createContext: vaCreateBuffer VAEncCodedBufferType failed (%d)!\n", va_status);
+		vaDestroyContext(va_dpy, va_contextid);
+		va_contextid = 0;
+		vaDestroyConfig(va_dpy, va_configid);
+		va_configid = 0;
+		va_codedbufferid = 0;
+		return va_status;
+	}
+
+	*max_coded_sizep = coded_buf_size;
+
+	encoder_status = LIBVA_CONTEXT_CREATED;
+	LOGV("createContext: done\n");
+	return VA_STATUS_SUCCESS;
+}
+
+int IntelImageEncoder::setQuality(unsigned int new_quality)
+{
+	if (quality == new_quality) {
+		return VA_STATUS_SUCCESS;
+	}
+
+	if (LIBVA_ENCODING == encoder_status) {
+		LOGE("setQuality: can't update quality while encoding!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if ((new_quality > INTEL_IMAGE_ENCODER_MAX_QUALITY) ||
+		(new_quality < INTEL_IMAGE_ENCODER_MIN_QUALITY)) {
+		LOGE("setQuality: invalid new quality value, not updated!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	quality = new_quality;
+
+	LOGV("setQuality: quality was updated to %d\n", quality);
+	return VA_STATUS_SUCCESS;
+}
+
+int IntelImageEncoder::encode(int image_seq, unsigned int new_quality)
+{
+	VAStatus va_status;
+	VAEncPictureParameterBufferJPEG va_picparabuffer;
+	VABufferID va_picparabufferid = 0;
+
+	if (encoder_status < LIBVA_CONTEXT_CREATED) {
+		LOGE("encode: no context created to perform encoding!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	} else if (encoder_status > LIBVA_CONTEXT_CREATED) {
+		LOGE("encode: there already is an active encoding task!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if ((image_seq < 0) ||
+		(image_seq >= INTEL_IMAGE_ENCODER_MAX_BUFFERS) ||
+		(0 == va_surfaceid[image_seq])) {
+		LOGE("encode: invalid image sequential number!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	} else if ((context_width != surface_width[image_seq]) ||
+				(context_height != surface_height[image_seq]) ||
+				(context_fourcc != surface_fourcc[image_seq])) {
+		LOGE("encode: the input image didn't fit in the current context!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	/* Update quality */
+	if (setQuality(new_quality) != VA_STATUS_SUCCESS) {
+		LOGE("encode: the input quality value was invalid, encoding aborted!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	/* Begin picture */
+	va_status = vaBeginPicture(va_dpy, va_contextid, va_surfaceid[image_seq]);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("encode: vaBeginPicture failed (%d)!\n", va_status);
+		return va_status;
+	}
+
+	/* Create a picture-parameter buffer */
+	va_picparabuffer.picture_width  = context_width;
+	va_picparabuffer.picture_height = context_height;
+	va_picparabuffer.reconstructed_picture= 0;
+	va_picparabuffer.coded_buf = va_codedbufferid;
+	va_picparabuffer.pic_flags.bits.profile = 0; /* Baseline */
+	va_picparabuffer.pic_flags.bits.progressive = 0; /* Sequential */
+	va_picparabuffer.pic_flags.bits.huffman = 1; /* Huffman */
+	va_picparabuffer.pic_flags.bits.interleaved = 0; /* Non-interleaved */
+	va_picparabuffer.pic_flags.bits.differential = 0; /* Non-differential */
+	va_picparabuffer.sample_bit_depth = 8; /* 8-bits */
+	va_picparabuffer.num_components = 3; /* 3-components */
+	va_picparabuffer.quality = quality; /* JPEG ENC quality */
+	va_status = vaCreateBuffer(va_dpy, va_contextid, VAEncPictureParameterBufferType,
+					sizeof(va_picparabuffer), 1, &va_picparabuffer,&va_picparabufferid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("encode: vaCreateBuffer VAEncPictureParameterBufferType failed (%d)!\n", va_status);
+		return va_status;
+	}
+
+	/* Render picture */
+	va_status = vaRenderPicture(va_dpy, va_contextid, &va_picparabufferid, 1);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("encode: vaRenderPicture failed (%d)!\n", va_status);
+		vaDestroyBuffer(va_dpy, va_picparabufferid);
+		return va_status;
+	}
+
+	/* Destroy the used picture-parameter buffer */
+	vaDestroyBuffer(va_dpy, va_picparabufferid);
+
+	/* End picture */
+	va_status = vaEndPicture(va_dpy, va_contextid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("encode: vaEndPicture failed (%d)!\n", va_status);
+		vaDestroyBuffer(va_dpy, va_picparabufferid);
+		return va_status;
+	}
+
+	reserved_image_seq = image_seq;
+	encoder_status = LIBVA_ENCODING;
+	LOGV("encode: done\n");
+	return VA_STATUS_SUCCESS;
+}
+
+int IntelImageEncoder::getCoded(void *user_coded_buf,
+					unsigned int user_coded_buf_size,
+					unsigned int *coded_data_sizep)
+{
+	VAStatus va_status;
+	VACodedBufferSegment *va_codedbuffersegment = NULL;
+
+	if ((NULL == user_coded_buf) ||
+		(NULL == coded_data_sizep)) {
+		LOGE("getCoded: invalid NULL pointer as input paramter!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	}
+
+	if (user_coded_buf_size < coded_buf_size) {
+		LOGE("getCoded: the coded buffer was too small!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if (encoder_status != LIBVA_ENCODING) {
+		LOGE("getCoded: no encoding active to get coded data!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if (0 == va_surfaceid[reserved_image_seq]) {
+		LOGE("getCoded: invalid image, probably already destroyed!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	/* Sync surface */
+	va_status = vaSyncSurface(va_dpy, va_surfaceid[reserved_image_seq]);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("getCoded: vaSyncSurface failed (%d)!\n", va_status);
+		reserved_image_seq = -1;
+		encoder_status = LIBVA_CONTEXT_CREATED;
+		return va_status;
+	}
+
+	/* Map the coded buffer */
+	va_status = vaMapBuffer(va_dpy, va_codedbufferid, (void **)&va_codedbuffersegment);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("getCoded: vaMapBuffer failed (%d)!\n", va_status);
+		reserved_image_seq = -1;
+		encoder_status = LIBVA_CONTEXT_CREATED;
+		return va_status;
+	}
+
+	/* Mark the coded buffer empty */
+	*coded_data_sizep = 0;
+
+	/* Get the total size of coded data */
+	while (va_codedbuffersegment != NULL) {
+		memcpy((void *)((unsigned int)user_coded_buf+*coded_data_sizep),
+				va_codedbuffersegment->buf,
+				va_codedbuffersegment->size);
+		*coded_data_sizep += va_codedbuffersegment->size;
+		va_codedbuffersegment = (VACodedBufferSegment *)va_codedbuffersegment->next;
+	}
+
+	va_status = vaUnmapBuffer(va_dpy, va_codedbufferid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("getCoded: vaUnmapBuffer failed (%d)!\n", va_status);
+	}
+
+	reserved_image_seq = -1;
+	encoder_status = LIBVA_CONTEXT_CREATED;
+
+	LOGV("getCoded: done\n");
+	return va_status;
+}
+
+int IntelImageEncoder::destroySourceSurface(int image_seq)
+{
+	VAStatus va_status;
+
+	if ((image_seq < 0) || ((unsigned int)image_seq >= images_count) ||
+		(0 == va_surfaceid[image_seq])) {
+		LOGE("destroySourceSurface: invalid image sequential number!\n");
+		return VA_STATUS_ERROR_INVALID_PARAMETER;
+	} else if (image_seq == reserved_image_seq) {
+		LOGE("destroySourceSurface: Image %d was under encoding and can't be destroyed!\n",
+			image_seq);
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if (LIBVA_UNINITIALIZED == encoder_status) {
+		LOGE("destroySourceSurface: uninitialized, not ready to destroy surface!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	/* Destroy a source surface */
+	va_status = vaDestroySurfaces(va_dpy, &va_surfaceid[image_seq], 1);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("destroySourceSurface: vaDestroySurfaces failed (%d)!\n", va_status);
+	}
+
+	va_surfaceid[image_seq] = 0;
+	surface_width[image_seq] = 0;
+	surface_height[image_seq] = 0;
+	surface_fourcc[image_seq] = 0;
+
+	--images_count;
+
+	return va_status;
+}
+
+int IntelImageEncoder::destroyContext(void)
+{
+	VAStatus va_status, va_final_status;
+
+	if (0 == va_contextid) {
+		LOGE("destroyContext: no context to destroy!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if (LIBVA_ENCODING == encoder_status) {
+		LOGE("destroyContext: encoding was ongoing, can't destroy context!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	/* Destroy the coded buffer */
+	va_status = vaDestroyBuffer(va_dpy, va_codedbufferid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("createContext: vaDestroyBuffer VAEncCodedBufferType failed (%d)!\n", va_status);
+	}
+	va_final_status = va_status;
+	va_codedbufferid = 0;
+	coded_buf_size = 0;
+
+	/* Destroy context */
+	va_status = vaDestroyContext(va_dpy, va_contextid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("destroyContext: vaDestroyContext failed (%d)!\n", va_status);
+	}
+	va_final_status |= va_status;
+	va_contextid = 0;
+	context_width = 0;
+	context_height = 0;
+	context_fourcc = 0;
+
+	/* Destroy config */
+	va_status = vaDestroyConfig(va_dpy, va_configid);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("destroyContext: vaDestroyConfig failed (%d)!\n", va_status);
+	}
+	va_final_status |= va_status;
+	va_configid = 0;
+
+	encoder_status = LIBVA_INITIALIZED;
+
+	LOGV("destroyContext: done\n");
+	return va_final_status;
+}
+
+int IntelImageEncoder::deinitializeEncoder(void)
+{
+	int i;
+	VAStatus va_status;
+
+	if (NULL == va_dpy) {
+		LOGE("deinitializeEncoder: no LibVA display to deinitialized!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	}
+
+	if (LIBVA_ENCODING == encoder_status) {
+		LOGE("deinitializeEncoder: encoding was ongoing, can't deinitialize LibVA!\n");
+		return VA_STATUS_ERROR_OPERATION_FAILED;
+	} else if (LIBVA_CONTEXT_CREATED == encoder_status) {
+		/* Destroy context if it exists */
+		destroyContext();
+	}
+
+	if (images_count > 0) {
+		for (i=0; i<INTEL_IMAGE_ENCODER_MAX_BUFFERS; ++i) {
+			if (va_surfaceid[i]) {
+				/* Destroy any surface if it exists */
+				destroySourceSurface(i);
+			}
+		}
+	}
+
+	va_status = vaTerminate(va_dpy);
+	if (va_status != VA_STATUS_SUCCESS) {
+		LOGE("deinitializeEncoder: vaTerminate failed (%d)!\n", va_status);
+	}
+
+	memset((void *)&va_configattrib, 0, sizeof(va_configattrib));
+	va_dpy = NULL;
+	encoder_status = LIBVA_UNINITIALIZED;
+
+	LOGV("deinitializeEncoder: done\n");
+	return va_status;
+}
diff --git a/imageencoder/ImageEncoder.h b/imageencoder/ImageEncoder.h
new file mode 100644
index 0000000..0d1aebf
--- /dev/null
+++ b/imageencoder/ImageEncoder.h
@@ -0,0 +1,90 @@
+#ifndef __LIBMIX_INTEL_IMAGE_ENCODER_H__
+#define __LIBMIX_INTEL_IMAGE_ENCODER_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <va/va.h>
+#include <va/va_android.h>
+#include <va/va_tpi.h>
+#include <va/va_enc_jpeg.h>
+
+#define INTEL_IMAGE_ENCODER_DEFAULT_QUALITY 90
+#define INTEL_IMAGE_ENCODER_MAX_QUALITY 100
+#define INTEL_IMAGE_ENCODER_MIN_QUALITY 1
+#define INTEL_IMAGE_ENCODER_MAX_BUFFERS 64
+#define INTEL_IMAGE_ENCODER_REQUIRED_STRIDE 64
+#ifndef VA_FOURCC_YV16
+#define VA_FOURCC_YV16 0x36315659
+#endif
+#define SURFACE_TYPE_USER_PTR 0x00000004
+#define SURFACE_TYPE_GRALLOC 0x00100000
+
+class IntelImageEncoder {
+public:
+	IntelImageEncoder(void);
+	~IntelImageEncoder(void) {};
+	int initializeEncoder(void);
+	int createSourceSurface(int source_type, void *source_buffer,
+				unsigned int width,unsigned int height,
+				unsigned int stride, unsigned int fourcc,
+				int *image_seqp);
+	int createContext(int first_image_seq, unsigned int *max_coded_sizep);
+	int createContext(unsigned int *max_coded_sizep)
+	{
+		return this->createContext(0, max_coded_sizep);
+	}
+	int setQuality(unsigned int new_quality);
+	int encode(int image_seq, unsigned int new_quality);
+	int encode(int image_seq)
+	{
+		return this->encode(image_seq, quality);
+	}
+	int encode(void)
+	{
+		return this->encode(0, quality);
+	}
+	int getCoded(void *user_coded_buf,
+			unsigned int user_coded_buf_size,
+			unsigned int *coded_data_sizep);
+	int destroySourceSurface(int image_seq);
+	int destroyContext(void);
+	int deinitializeEncoder(void);
+
+private:
+	typedef enum {
+		LIBVA_UNINITIALIZED = 0,
+		LIBVA_INITIALIZED,
+		LIBVA_CONTEXT_CREATED,
+		LIBVA_ENCODING,
+	}IntelImageEncoderStatus;
+
+	/* Valid since LIBVA_UNINITIALIZED */
+	IntelImageEncoderStatus encoder_status;
+	unsigned int quality;
+
+	/* Valid Since LIBVA_INITIALIZED */
+	VADisplay va_dpy;
+	VAConfigAttrib va_configattrib;
+
+	/* Valid if a surface is created */
+	unsigned int images_count;
+	VASurfaceID va_surfaceid[INTEL_IMAGE_ENCODER_MAX_BUFFERS];
+	unsigned int surface_width[INTEL_IMAGE_ENCODER_MAX_BUFFERS];
+	unsigned int surface_height[INTEL_IMAGE_ENCODER_MAX_BUFFERS];
+	unsigned int surface_fourcc[INTEL_IMAGE_ENCODER_MAX_BUFFERS];
+
+	/* Valid since LIBVA_CONTEXT_CREATED */
+	VAConfigID va_configid;
+	VAContextID va_contextid;
+	unsigned int context_width;
+	unsigned int context_height;
+	unsigned int context_fourcc;
+	VABufferID va_codedbufferid;
+	unsigned int coded_buf_size;
+
+	/* Valid since LIBVA_ENCODING */
+	int reserved_image_seq;
+};
+
+#endif /* __LIBMIX_INTEL_IMAGE_ENCODER_H__ */
diff --git a/imageencoder/test/main.cpp b/imageencoder/test/main.cpp
new file mode 100644
index 0000000..1433c04
--- /dev/null
+++ b/imageencoder/test/main.cpp
@@ -0,0 +1,559 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include "ImageEncoder.h"
+
+inline unsigned long long int current_time(/*bool fixed*/)
+{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return (((unsigned long long)tv.tv_usec+(unsigned long long)tv.tv_sec*1000000) * 1000);
+}
+
+#define PERF_DEF(counter) unsigned long long int COUNTER_##counter=0;
+#define PERF_START(counter, fixed) { COUNTER_##counter = current_time(); }
+#define PERF_STOP(counter, fixed) { COUNTER_##counter = current_time() - COUNTER_##counter; }
+#define PERF_SET(counter, value) { COUNTER_##counter = value; }
+#define PERF_GET(counter) (COUNTER_##counter)
+
+#define MAX_WIDTH 5120
+#define MAX_HEIGHT 5120
+#define DEFAULT_QUALITY 90
+#define DEFAULT_BURST 1
+#define YUV420_SAMPLE_SIZE 1.5
+
+static void usage(const char* pname)
+{
+	fprintf(stderr,
+		"\n  USAGE: %s -source [path] -width [value] -height [value] \n"
+		"         -output [path] -burst [value] -quality [value] -fix\n\n"
+		"  -source: declaring the source's file path.\n"
+		"  -width: declaring the source's raw data width (0, 65536].\n"
+		"  -height: declaring the source's raw data height (0, 65536].\n"
+		"  -output: specifying the output JPEG's file path (.JPG or .jpg).\n"
+		"  -burst (optional): enabling continuous encoding times (0, 50].\n"
+		"  -quality (optional): setting image quality [0, 100].\n"
+		"  -fix (optional): fixing CPU frequency for evaluating performance.\n\n"
+		,pname);
+}
+
+static bool match_key (char *arg, const char *keyword, int minchars)
+{
+	register int ca, ck;
+	register int nmatched = 0;
+
+	while ((ca = *arg++) != '\0') {
+		if ((ck = *keyword++) == '\0')
+			return false; /* arg longer than keyword, mismatch */
+		if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+			ca = tolower(ca);
+		if (ca != ck)
+			return false; /* mismatch */
+		nmatched++; /* count matched characters */
+	}
+
+	if (nmatched < minchars)
+		return false; /* arg shorter than keyword, mismatch */
+
+	return true; /* Match */
+}
+
+int main(int argc, char** argv)
+{
+	const char *pname = argv[0];
+	int argn;
+	char *arg;
+
+	/* Parameter variables */
+	char *source_name = NULL;
+	char *output_name = (char *)"./output.jpg";
+	int quality = DEFAULT_QUALITY;
+	int burst = DEFAULT_BURST;
+	int width = 0, height = 0;
+	bool fix_cpu_frequency = false;
+	unsigned int fourcc_format = 0;
+
+	/* Internal variables*/
+	int i, j;
+	int stride = 0;
+	char final_output_name[128] = "\0";
+	int source_fd = -1;
+	int output_fd = -1;
+	unsigned int source_size = 0, source_buffer_size = 0;
+	unsigned int output_size = 0, output_buffer_size = 0;
+	unsigned int read_size = 0, write_size = 0;
+	void *source_buffer = NULL, *output_buffer = NULL;
+	void *aligned_source_buffer = NULL, *current_position = NULL;
+	void *surface_buffer = NULL, *surface_buffer_ptr = NULL;
+	int status;
+	int image_seq = -1;
+	IntelImageEncoder image_encoder;
+
+	/* For CPU frequency fixing */
+	FILE *cpu_online_nr_fd = NULL, *cpu_available_max_fd = NULL, *cpu_available_min_fd = NULL;
+	FILE *cpu_scaling_max_fd = NULL, *cpu_scaling_min_fd = NULL, *cpu_cur_fd = NULL;
+	unsigned int cpu_online_nr = 0, cpu_available_max = 1000000, cpu_available_min = 0, cpu_cur = 0;
+
+	/* For performance logging */
+	PERF_DEF(init_driver_time);
+	PERF_DEF(create_source_time);
+	PERF_DEF(create_context_time);
+	PERF_DEF(prepare_encoding_time);
+	PERF_DEF(encode_time);
+	PERF_DEF(term_driver_time);
+	unsigned long long int total_time = 0;
+	double compression_rate = 0;
+
+	/* Get the input parameters */
+	if (1 >= argc) {
+		usage(pname); /* No argument */
+		return 1;
+	}
+
+	for (argn = 1; argn < argc; argn++) {
+		arg = argv[argn];
+		if (*arg != '-') {
+			/* Every argument should begin with a '-' */
+			usage(pname);
+			fprintf(stderr, "Every argument should begin with a '-'!\n");
+			return 1;
+		}
+		arg++;
+
+		if (match_key(arg, "width", strlen("width"))) {
+			if (++argn >= argc) {
+				usage(pname); /* "-width" should be followed by a specified width value*/
+				fprintf(stderr, "-width should be followed by a specified width value!\n");
+				return 1;
+			}
+
+			if ((1 != sscanf(argv[argn], "%d", &width)) || (width <= 0)) {
+				usage(pname); /* Invalid width */
+				fprintf(stderr, "Invalid width!\n");
+				return 1;
+			}
+
+			if ((width>MAX_WIDTH) || (width%2)) {
+				usage(pname); /* Unsupported width */
+				fprintf(stderr, "Unsupported width: %d!\n", width);
+				return 1;
+			}
+		} else if (match_key(arg, "height", strlen("height"))) {
+			if (++argn >= argc) {
+				usage(pname); /* "-height" should be followed by a specified height value*/
+				fprintf(stderr, "-height should be followed by a specified height value!\n");
+				return 1;
+			}
+
+			if ((1 != sscanf(argv[argn], "%d", &height)) || (height <= 0)) {
+				usage(pname); /* Invalid height */
+				fprintf(stderr, "Invalid height!\n");
+				return 1;
+			}
+
+			if ((MAX_HEIGHT<height) || (height%2)) {
+				usage(pname); /* Unsupported height */
+				fprintf(stderr, "Unsupported height: %d!\n", height);
+				return 1;
+			}
+		} else if (match_key(arg, "source", strlen("source"))) {
+			if (++argn >= argc) {
+				usage(pname); /* "-source" should be followed by a specified source path */
+				fprintf(stderr, "-source should be followed by a specified source path!\n");
+				return 1;
+			}
+			source_name = argv[argn];
+		} else if (match_key(arg, "output", strlen("output"))) {
+			if (++argn >= argc) {
+				usage(pname); /* "-output" should be followed by a specified output file path */
+				fprintf(stderr, "-output should be followed by a specified output file path!\n");
+				return 1;
+			}
+			output_name = argv[argn];
+			if ((strlen(output_name) <= 4) ||
+				(strcmp(output_name+strlen(output_name)-4, ".jpg") &&
+				strcmp(output_name+strlen(output_name)-4, ".JPG"))) {
+				usage(pname); /* Invalid output file name */
+				fprintf(stderr, "Invalid output file name: %s!\n", output_name);
+				return 1;
+			}
+		} else if (match_key(arg, "burst", strlen("burst"))) {
+			if (++argn >= argc) {
+				usage(pname); /* "burst" should be followed by a quality value */
+				fprintf(stderr, "-burst should be followed by a specified encoding times!\n");
+				return 1;
+			}
+
+			if ((1 != sscanf(argv[argn], "%d", &burst)) || (burst < 0) || (burst > 50)) {
+				usage(pname); /* Invalid burst times */
+				fprintf(stderr, "Invalid burst times!\n");
+				return 1;
+			}
+		} else if (match_key(arg, "quality", strlen("quality"))) {
+			if (++argn >= argc) {
+				usage(pname); /* "quality" should be followed by a quality value */
+				fprintf(stderr, "-quality should be followed by a specified quality value!\n");
+				return 1;
+			}
+
+			if ((1 != sscanf(argv[argn], "%d", &quality)) || (quality < 0) || (quality > 100)) {
+				usage(pname); /* Invalid quality value */
+				fprintf(stderr, "Invalid quality value!\n");
+				return 1;
+			}
+		} else if (match_key(arg, "fix", strlen("fix"))) {
+			fix_cpu_frequency = true;
+		} else {
+			usage(pname); /* Unsupported argument */
+			fprintf(stderr, "Unsupported argument: %s!\n", arg);
+			return 1;
+		}
+	}
+
+	/* Validate the input parameters */
+	if ((0 == width) || (0 == height)) {
+		usage(pname);
+		fprintf(stderr, "Width or height unset!\n");
+		return 1;
+	}
+
+	if (NULL == source_name) {
+		usage(pname);
+		fprintf(stderr, "Source file path unset!\n");
+		return 1;
+	}
+
+	/* Get the source image data */
+	source_fd = open(source_name, O_RDONLY, 0664);
+	if (-1 == source_fd) {
+		fprintf(stderr, "Error opening source file: %s (%s)!\n", source_name, strerror(errno));
+		return 1;
+	}
+
+	source_size = width * height * YUV420_SAMPLE_SIZE;
+	stride = (width+0x3f) & (~0x3f); /* TopazHP requires stride must be an integral multiple of 64. */
+	source_buffer_size = stride * height * YUV420_SAMPLE_SIZE;
+
+	source_buffer = malloc(source_buffer_size+4096);
+	if (NULL == source_buffer) {
+		fprintf(stderr, "Fail to allocate source buffer: %d(%s)!\n", errno, strerror(errno));
+		close(source_fd);
+		return 1;
+	}
+	memset(source_buffer, 0, source_buffer_size+4096);
+	aligned_source_buffer = (void *)((unsigned int)source_buffer -
+				((unsigned int)source_buffer)%4096 + 4096);
+
+	current_position = aligned_source_buffer;
+	for (i=0; i<height; ++i) { /* Y Component */
+		read_size += read(source_fd, current_position, width);
+		current_position = (void *)((unsigned int)current_position + stride);
+	}
+	for (i=0; i<(height/2); ++i) { /* UV Component */
+		read_size += read(source_fd, current_position, width);
+		current_position = (void *)((unsigned int)current_position + stride);
+	}
+
+	close(source_fd);
+
+	if (read_size != source_size) {
+		fprintf(stderr, "Incorrect source file size: %d(%s)!\n", read_size, strerror(errno));
+		fprintf(stderr, "The correct size should be : %d.\n", source_size);
+		free(source_buffer);
+		return 1;
+	}
+
+	/* Try to fix CPUs' frequency to the maximum available */
+	if (fix_cpu_frequency) {
+		cpu_online_nr_fd = fopen("/sys/devices/system/cpu/online", "r");
+		assert(cpu_online_nr_fd != NULL);
+		fscanf(cpu_online_nr_fd, "0-%u", &cpu_online_nr);
+		assert(cpu_online_nr != 0);
+		fclose(cpu_online_nr_fd);
+
+		cpu_available_max_fd  = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
+		if (NULL == cpu_available_max_fd) {
+			unsigned char one_line[32] = {};
+			unsigned char one_segment[32] = {};
+			int readed = 0;
+
+			cpu_available_max_fd  = fopen("/proc/cpuinfo", "r");
+			assert(cpu_available_max_fd != 0);
+
+			i = strlen("cpu MHz");
+			j = -1;  /* Haven't find the cpu MHz line */
+			do {
+				if (fread(&one_line[0], 1, 1, cpu_available_max_fd) != 1) {
+					break;
+				} else if ('\n' == one_line[0]) {
+					readed = fread(one_line, 1, 24, cpu_available_max_fd);
+					if ((24 == readed) &&
+					(0 == strncmp((const char *)one_line, (const char *)"cpu MHz", i))) {
+						/* Find the cpu MHz line */
+						j = 0;
+						break;
+					} else if (readed > 0) {
+						fseek(cpu_available_max_fd, 0-readed, SEEK_CUR);
+					}
+				}
+			} while (1);
+
+			if (0 == j) {
+				while (one_line[i] != ':') {
+					++i;
+				}
+				++i; /* The space bewteen ':' and a freq value */
+				while (one_line[i] != '.') {
+					one_segment[j++] = one_line[i++];
+				}
+				one_segment[j] = '\0';
+				cpu_available_max = atoi((const char *)one_segment) * 1000;
+			}
+			fclose(cpu_available_max_fd);
+
+			if (0 == cpu_available_max) {
+				cpu_available_max = 1000000;
+				fprintf(stderr, "\nCan't find CPU frequecency value and we assume 1.0GHz.\n");
+			}
+
+			printf("\n%u CPU(s) online, whose unscalable frequency is: %u.\n",
+				cpu_online_nr+1, cpu_available_max);
+		} else {
+			fscanf(cpu_available_max_fd, "%u", &cpu_available_max);
+			assert(cpu_available_max != 0);
+			fclose(cpu_available_max_fd);
+
+			cpu_available_min_fd  = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq",
+							"r");
+			assert(cpu_available_min_fd != NULL);
+			fscanf(cpu_available_min_fd, "%u", &cpu_available_min);
+			assert(cpu_available_min != 0);
+			fclose(cpu_available_min_fd);
+
+			printf("\n%u CPU(s) online, whose MAX/MIN available frequency is: %u/%u.\n",
+				cpu_online_nr+1, cpu_available_max, cpu_available_min);
+
+			for (i=0; i<=(int)cpu_online_nr; ++i) {
+				char fd_name[64];
+
+				sprintf(fd_name, "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_max_freq", i);
+				cpu_scaling_max_fd  = fopen(fd_name, "w");
+				if (0 == i) {
+					assert(cpu_scaling_max_fd != NULL);
+				} else if ((i>0) && (NULL==cpu_scaling_max_fd)) {
+					fprintf(stderr, "No sysfs attribute to fix cpu%u's frequency!\n", i);
+					break;
+				}
+				fprintf(cpu_scaling_max_fd, "%u", cpu_available_max);
+				fclose(cpu_scaling_max_fd);
+
+				sprintf(fd_name, "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_min_freq", i);
+				cpu_scaling_min_fd  = fopen(fd_name, "w");
+				if (0 == i) {
+					assert(cpu_scaling_min_fd != NULL);
+				} else if ((i>0) && (NULL== cpu_scaling_min_fd)) {
+					fprintf(stderr, "No sysfs attribute to fix cpu%u's frequency!\n", i);
+					break;
+				}
+				fprintf(cpu_scaling_min_fd, "%u", cpu_available_max);
+				fclose(cpu_scaling_min_fd);
+
+				sprintf(fd_name, "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", i);
+				cpu_cur_fd  = fopen(fd_name, "r");
+				assert(cpu_cur_fd != NULL);
+				fscanf(cpu_cur_fd, "%u", &cpu_cur);
+				assert(cpu_cur == cpu_available_max);
+				fclose(cpu_cur_fd);
+
+				printf("cpu%u's frequency is fixed to %u.\n", i, cpu_available_max);
+
+				cpu_scaling_max_fd = cpu_scaling_min_fd = cpu_cur_fd = NULL;
+				cpu_cur = 0;
+			}
+		}
+	}
+	cpu_available_max = 1000000;
+
+	/* Print encoding settings */
+	printf("\n[INPUT]\n");
+	printf("Source: %s\n", source_name);
+	printf("Width: %d\n", width);
+	printf("Height: %d\n", height);
+	printf("Output: %s\n", output_name);
+	printf("Burst: %d times\n", burst);
+	printf("Quality: %d\n", quality);
+	if (true == fix_cpu_frequency)
+		printf("Fix CPU frequency: true\n");
+	else
+		printf("Fix CPU frequency: false\n");
+	printf("\n[OUTPUT]\n");
+
+	/* Initialize encoder */
+	PERF_START(init_driver_time, fix_cpu_frequency);
+	status = image_encoder.initializeEncoder();
+	PERF_STOP(init_driver_time, fix_cpu_frequency);
+	if (status != 0) {
+		fprintf(stderr, "initializeEncoder failed (%d)!\n", status);
+		free(source_buffer);
+		return 1;
+	}
+
+	/* Create a source surface*/
+	PERF_START(create_source_time, fix_cpu_frequency);
+	status = image_encoder.createSourceSurface(SURFACE_TYPE_USER_PTR, aligned_source_buffer,
+							width, height,
+							stride, VA_RT_FORMAT_YUV420,
+							&image_seq);
+	PERF_STOP(create_source_time, fix_cpu_frequency);
+	if (status != 0) {
+		fprintf(stderr, "createSourceSurface failed (%d)!\n", status);
+		free(source_buffer);
+		image_encoder.deinitializeEncoder();
+		return 1;
+	}
+
+	/* Create context*/
+	PERF_START(create_context_time, fix_cpu_frequency);
+	status = image_encoder.createContext(image_seq, &output_buffer_size);
+	PERF_STOP(create_context_time, fix_cpu_frequency);
+	if (status != 0) {
+		fprintf(stderr, "createContext failed (%d)!\n", status);
+		free(source_buffer);
+		image_encoder.deinitializeEncoder();
+		return 1;
+	}
+
+	output_buffer = malloc(output_buffer_size);
+	if (NULL == output_buffer) {
+		fprintf(stderr, "Fail to allocate output buffer: %d(%s)!\n", errno, strerror(errno));
+		free(source_buffer);
+		image_encoder.deinitializeEncoder();
+		return 1;
+	}
+
+	printf("Init driver: %.3fms\n", (double)PERF_GET(init_driver_time)/cpu_available_max);
+	printf("Create source: %.3fms\n", (double)PERF_GET(create_source_time)/cpu_available_max);
+	printf("Create context: %.3fms\n", (double)PERF_GET(create_context_time)/cpu_available_max);
+
+	/* Do the encoding */
+	for (i=0; i<burst; ++i) {
+		PERF_START(prepare_encoding_time, fix_cpu_frequency);
+		status = image_encoder.encode(image_seq, quality);
+		PERF_STOP(prepare_encoding_time, fix_cpu_frequency);
+		if (status != 0) {
+			fprintf(stderr, "encode failed (%d)!\n", status);
+			free(source_buffer);
+			free(output_buffer);
+			image_encoder.deinitializeEncoder();
+			return 1;
+		}
+
+		PERF_START(encode_time, fix_cpu_frequency);
+		status = image_encoder.getCoded(output_buffer, output_buffer_size, &output_size);
+		PERF_STOP(encode_time, fix_cpu_frequency);
+		if (status != 0) {
+			fprintf(stderr, "getCoded failed (%d)!\n", status);
+			free(source_buffer);
+			free(output_buffer);
+			image_encoder.deinitializeEncoder();
+			return 1;
+		}
+
+		printf("Prepare encoding: %.3fms\n", (double)PERF_GET(prepare_encoding_time)/cpu_available_max);
+		printf("Encode and stitch coded: %.3fms\n", (double)PERF_GET(encode_time)/cpu_available_max);
+
+		if (0 == i) {
+			sprintf(final_output_name, "%s", output_name);
+		} else {
+			sprintf(final_output_name, "%d.%s", i+1, output_name);
+		}
+
+		output_fd = open(final_output_name, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+		if (-1 == output_fd) {
+			fprintf(stderr, "Error opening output file: %s (%s)!\n",
+				final_output_name, strerror(errno));
+			free(source_buffer);
+			free(output_buffer);
+			image_encoder.deinitializeEncoder();
+			return 1;
+		}
+
+		write_size = write(output_fd, output_buffer, output_size);
+		close(output_fd);
+		if (write_size != output_size) {
+			fprintf(stderr, "Fail to write coded data to output file: %d(%s)!\n",
+				write_size , strerror(errno));
+			free(source_buffer);
+			free(output_buffer);
+			image_encoder.deinitializeEncoder();
+			return 1;
+		}
+
+		output_fd = -1;
+	}
+
+	free(source_buffer);
+	free(output_buffer);
+
+	/* Deinitialize encoder */
+	PERF_START(term_driver_time, fix_cpu_frequency);
+	status = image_encoder.deinitializeEncoder();
+	PERF_STOP(term_driver_time, fix_cpu_frequency);
+	if (status != 0) {
+		fprintf(stderr, "deinitializeEncoder failed (%d)!\n", status);
+		return 1;
+	}
+
+	printf("Term driver: %.3fms\n", (double)PERF_GET(term_driver_time)/cpu_available_max);
+
+	/* Print encoding results */
+	if (1 == burst) {
+		total_time = PERF_GET(init_driver_time) + PERF_GET(create_source_time) +
+				PERF_GET(create_context_time) + PERF_GET(prepare_encoding_time) +
+				PERF_GET(encode_time) + PERF_GET(term_driver_time);
+		printf("[SUM]Total: %.3fms\n", (double)total_time/cpu_available_max);
+	}
+
+	compression_rate = ((double)output_size) / ((double)source_size);
+	compression_rate = (1 - compression_rate) * 100;
+	printf("[SUM]Compression rate: %.2f%% (%d bytes : %d bytes)\n\n",
+		compression_rate, output_size, source_size);
+
+	/* Try to restore CPUs' frequency */
+	if (fix_cpu_frequency) {
+		if (cpu_available_min != 0) {
+			for (i=0; i<=(int)cpu_online_nr; ++i) {
+				char fd_name[64];
+
+				sprintf(fd_name, "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_min_freq", i);
+				cpu_scaling_min_fd  = fopen(fd_name, "w");
+				if (0 == i) {
+					assert(cpu_scaling_min_fd != NULL);
+				} else if ((i>0) && (NULL== cpu_scaling_min_fd)) {
+					fprintf(stderr, "No sysfs attribute to restore cpu%u's frequency!\n", i);
+					break;
+				}
+
+				fprintf(cpu_scaling_min_fd, "%u", cpu_available_min);
+				fclose(cpu_scaling_min_fd);
+
+				printf("cpu%u's frequency is restored.\n", i);
+
+				cpu_scaling_min_fd = NULL;
+			}
+		}
+	}
+
+	return 0;
+}
+