diff options
-rwxr-xr-x[-rw-r--r--] | android/Android.mk | 31 | ||||
-rw-r--r-- | android/gralloc.cpp | 1 | ||||
-rw-r--r-- | android/libjpeg-encoder.cpp | 846 | ||||
-rw-r--r-- | android/mce.cpp | 48 | ||||
-rwxr-xr-x | android/skia-encoder.cpp | 127 | ||||
-rw-r--r-- | utils/loadsurface_yuv.h | 2 | ||||
-rw-r--r-- | vaenc/Android.mk | 1 | ||||
-rw-r--r-- | vaenc/Makefile | 4 | ||||
-rw-r--r-- | vaenc/hevcencode.c | 938 | ||||
-rw-r--r-- | vaenc/va_encode.c | 11 | ||||
-rw-r--r-- | vaenc/va_encode.h | 1 | ||||
-rw-r--r-- | vaenc/vp8encode.c | 8 | ||||
-rw-r--r-- | yuvtool/main.c | 133 |
13 files changed, 1828 insertions, 323 deletions
diff --git a/android/Android.mk b/android/Android.mk index d73c075..2566382 100644..100755 --- a/android/Android.mk +++ b/android/Android.mk @@ -26,3 +26,34 @@ LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) + + +###### Build imageencoder ###### + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + skia-encoder.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libskia \ + libui \ + libgui + +LOCAL_MODULE:= skia-encoder + +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES += \ + external/skia/include/core \ + external/skia/include/effects \ + external/skia/include/images \ + external/skia/src/ports \ + external/skia/include/utils + +include $(BUILD_EXECUTABLE) + +###### End build imageencoder ###### diff --git a/android/gralloc.cpp b/android/gralloc.cpp index e8cf7ee..fcffc3f 100644 --- a/android/gralloc.cpp +++ b/android/gralloc.cpp @@ -51,7 +51,6 @@ static GraphicBuffer *GfxBuffer[32]; extern "C" int alloc_gralloc_buffer(int num_buffers, unsigned long *buffers, int width, int height, int linear); #endif - int alloc_gralloc_buffer(int num_buffers, unsigned long *buffers, int width, int height, int linear) { diff --git a/android/libjpeg-encoder.cpp b/android/libjpeg-encoder.cpp new file mode 100644 index 0000000..d22a79f --- /dev/null +++ b/android/libjpeg-encoder.cpp @@ -0,0 +1,846 @@ +/* + * Copyright (c) 2007-2008 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. + * + * Authors: + * Sun, Jing <jing.a.sun@intel.com> + */ + +#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 <pthread.h> +#include "jpeglib.h" + +inline unsigned long long int current_time(/*bool fixed*/) +{ +#if 0 + if (!fixed) { + struct timeval tv; + + gettimeofday(&tv, NULL); + return (((unsigned long long)tv.tv_usec+(unsigned long long)tv.tv_sec*1000000) * 1000); + } + else { + unsigned a, d; + + __asm__ volatile("rdtsc" : "=a" (a), "=d" (d)); + return ((unsigned long long)a) | (((unsigned long long)d) << 32); + } +#endif + 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 DEFAULT_THREAD_COUNT 1 +#define MAX_THREAD_COUNT 8 +#define MAX_WIDTH 65536 +#define MAX_HEIGHT 65536 +#define DEFAULT_QUALITY 80 +#define NV12_SAMPLE_SIZE 1.5 +#define NV12_COMPONENTS 3 +#define NV12_MCU_SIZE 16 +#define MAX_MCU_SIZE 1170 +#define MAX_CODED_BUFFER_SIZE(width,height) ((((((width)+15)/16)*(((height)+15)/16)* MAX_MCU_SIZE/4+1024)+0xf)&~0xf) + +#define HEADER_TOTAL_LEN 623 +#define HEADER_SOS_LEN 14 +#define HEADER_EOI_LEN 2 +#define HEADER_HEIGHT_POS 163 +#define HEADER_WIDTH_POS 165 + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + JOCTET *buffer; /* start of buffer */ + size_t size; /* size of buffer */ +}test_dest_mgr; + +typedef struct { + unsigned int id; + void *source_buffer; + int width; + int height; + int quality; + int sub_height; + int rows; + void *sub_output_buffer; + unsigned int sub_output_size; +}thread_parameters; + +static void usage(const char* pname) +{ + fprintf(stderr, + "\n USAGE: %s -source [path] -width [value] -height [value] \n" + " -output [path] -quality [value] -thread [value] -fix\n\n" + " -source: declaring the source's file path (of NV12).\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" + " -quality (optional): setting image quality [0, 100].\n" + " -thread (optional): setting the encoding threads [1, 8].\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 */ +} + +/* + * Convert source samples from the interleaved NV12 format to YUV411 format + * for Libjpeg doesn't support encoding interleaved source directly. + */ +static void NV12_color_convert(JSAMPLE *source, int width, int height, JSAMPLE *dest) +{ + int i, j; + JSAMPLE *source_UV = NULL; + JSAMPLE *dest_U = NULL; + JSAMPLE *dest_V = NULL; + + /* Copy the luminance component directly to destination*/ + memcpy((void *)dest, (void *)source, width*height); + + /* Deinterleave then copy the chrominance components to destination*/ + source_UV = (JSAMPLE *)((unsigned int)source + width*height); + dest_U = (JSAMPLE *)((unsigned int)dest + width*height); + dest_V = (JSAMPLE *)((unsigned int)dest_U + (width*height)/4); + for(i=0,j=0; i<(width*height/2); i+=2,++j) { + dest_U[j] = source_UV[i]; + dest_V[j] = source_UV[i+1]; + } +} + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ +static void init_destination (j_compress_ptr cinfo) +{ + test_dest_mgr *dest_mgr_ptr = (test_dest_mgr *)cinfo->dest; + + dest_mgr_ptr->pub.next_output_byte = dest_mgr_ptr->buffer; + dest_mgr_ptr->pub.free_in_buffer = dest_mgr_ptr->size; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + */ +static boolean empty_output_buffer (j_compress_ptr cinfo) +{ + test_dest_mgr *dest_mgr_ptr = (test_dest_mgr *)cinfo->dest; + fprintf(stderr, "The coded buffer is too small (free_in_buffer: %d)!\n", dest_mgr_ptr->pub.free_in_buffer); + return FALSE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + */ +static void term_destination (j_compress_ptr cinfo) +{ + /* Need to do nothing while term */ +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ +static void setup_dest_mgr (j_compress_ptr cinfo, void *buffer, unsigned int size) +{ + test_dest_mgr *dest_mgr_ptr; + + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + sizeof(test_dest_mgr)); + } + + dest_mgr_ptr = (test_dest_mgr *)cinfo->dest; + dest_mgr_ptr->pub.init_destination = init_destination; + dest_mgr_ptr->pub.empty_output_buffer = empty_output_buffer; + dest_mgr_ptr->pub.term_destination = term_destination; + dest_mgr_ptr->buffer = (JOCTET *)buffer; + dest_mgr_ptr->size = size; +} + +void *encode_thread_fn(void *arg) +{ + int i = 0, sub_coded_size = 0; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW Y_row[NV12_MCU_SIZE],U_row[NV12_MCU_SIZE],V_row[NV12_MCU_SIZE]; + JSAMPARRAY source_array[NV12_COMPONENTS]; + int uncoded_rows = 0, current_rows = 0; + test_dest_mgr *dest_mgr_ptr = NULL; + void *current_Y = NULL, *current_U = NULL, *current_V = NULL; + thread_parameters *p_para = (thread_parameters *)arg; + + source_array[0] = Y_row; + source_array[1] = U_row; + source_array[2] = V_row; + + uncoded_rows = p_para->rows; + + /* Initialize the JPEG compression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + /* Initialize JPEG parameters */ + cinfo.in_color_space = JCS_YCbCr; + cinfo.image_width = p_para->width; + cinfo.image_height = uncoded_rows; + cinfo.input_components = NV12_COMPONENTS; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, p_para->quality, TRUE); /* TRUE for forcing baseline (8-bit sample depth) */ + cinfo.raw_data_in = TRUE; + + /* Specify data destination for compression */ + setup_dest_mgr(&cinfo, p_para->sub_output_buffer, p_para->sub_output_size); + dest_mgr_ptr = (test_dest_mgr *)cinfo.dest; + + /* Start compressor */ + jpeg_start_compress(&cinfo, TRUE); /* TRUE for writing tables into dest */ + + /* Process data */ + current_Y = (void *)((unsigned int)p_para->source_buffer + + p_para->id*p_para->width*p_para->sub_height); + current_U = (void *)((unsigned int)p_para->source_buffer + p_para->width*p_para->height + + p_para->id*p_para->width*p_para->sub_height/4); + current_V = (void *)((unsigned int)p_para->source_buffer + p_para->width*p_para->height*5/4 + + p_para->id*p_para->width*p_para->sub_height/4); + while (uncoded_rows > 0) { + current_rows = (uncoded_rows > NV12_MCU_SIZE)? NV12_MCU_SIZE : uncoded_rows; + for (i=0; i<current_rows; ++i) { + Y_row[i] = (JSAMPROW)(current_Y); + current_Y =(void *)((unsigned int)current_Y + p_para->width); + } + for (i=0; i<(current_rows/2); ++i) { + U_row[i] = (JSAMPROW)(current_U); + V_row[i] = (JSAMPROW)(current_V); + current_U =(void *)((unsigned int)current_U + p_para->width/2); + current_V =(void *)((unsigned int)current_V + p_para->width/2); + } + jpeg_write_raw_data(&cinfo, source_array, NV12_MCU_SIZE); + uncoded_rows -= current_rows; + } + + /* Finish compression */ + jpeg_finish_compress(&cinfo); + + /* Check result */ + if (jerr.num_warnings != 0) { + fprintf(stderr, "Thread %d: Libjpeg outputs %ld warnings!\n", p_para->id, jerr.num_warnings); + sub_coded_size = -1; + } + else { + sub_coded_size = dest_mgr_ptr->size - dest_mgr_ptr->pub.free_in_buffer; + } + + /* Release memory */ + jpeg_destroy_compress(&cinfo); + + pthread_exit((void *)sub_coded_size); + return NULL; +} + +int main(int argc, char** argv) +{ + const char *pname = argv[0]; + int argn; + char *arg; + + int i, j; + char *source_name = NULL; + char *output_name = "./output.jpg"; + //char final_output_name[128] = "\0"; + int source_fd = -1; + int output_fd = -1; + int quality = DEFAULT_QUALITY; + int width = 0, height = 0; + int thread = DEFAULT_THREAD_COUNT; + unsigned int source_size = 0, output_size = 0; + unsigned int read_size = 0, write_size = 0; + void *source_buffer = NULL, *converted_source_buffer = NULL, *output_buffer = NULL; + unsigned char *merged_output_buffer=NULL; + bool fix_cpu_frequency = false; + + pthread_t *encode_thread = NULL; + thread_parameters *encode_thread_para = NULL; + int *sub_coded_size = NULL; + bool hasError = false; + + 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; + + unsigned long long int convert_time = 0; + unsigned long long int core_encoding_time = 0; + unsigned long long int subpictures_merging_time = 0; + unsigned long long int total_time = 0; + + PERF_DEF(NV12_color_convert); + PERF_DEF(core_encoding); + PERF_DEF(subpictures_merging); + + double compression_rate = 0; + + 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 ((height>MAX_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, "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, "thread", strlen("thread"))) { + if (++argn >= argc) { + usage(pname); /* "thread" should be followed by a thread count */ + fprintf(stderr, "-thread should be followed by a specified thread count!\n"); + return 1; + } + if ((1 != sscanf(argv[argn], "%d", &thread)) || (thread < 1) || (thread > MAX_THREAD_COUNT)) { + usage(pname); /* Invalid thread count */ + fprintf(stderr, "Invalid thread count!\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; + } + } + + if ((0 == width) || (0 == height)) { + usage(pname); + fprintf(stderr, "Width or height unset!\n"); + return 1; + } + + if (height < 240) { + printf("Height is too small to do multi-threading.\n" + "Force to run as single thread.\n"); + thread = 1; + } + + if (NULL == source_name) { + usage(pname); + fprintf(stderr, "Source file path unset!\n"); + return 1; + } + + 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 * NV12_SAMPLE_SIZE; + source_buffer = malloc(source_size); + 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_size); + + read_size = read(source_fd, source_buffer, source_size); + 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); + close(source_fd); + free(source_buffer); + return 1; + } + close(source_fd); + + //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 it to 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; + //Fixing is done. + + 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("Quality: %d\n", quality); + printf("Thread: %d\n", thread); + if (true == fix_cpu_frequency) + printf("Fix CPU frequency: true\n"); + else + printf("Fix CPU frequency: false\n"); + + printf("\n[OUTPUT]\n"); + + converted_source_buffer = malloc(source_size); + if (NULL == converted_source_buffer) { + fprintf(stderr, "Fail to allocate converted source buffer: %d(%s)!\n", errno, strerror(errno)); + return 1; + } + memset(converted_source_buffer, 0, source_size); + + PERF_START(NV12_color_convert, fix_cpu_frequency); + NV12_color_convert((JSAMPLE *)source_buffer, width, height, (JSAMPLE *)converted_source_buffer); + PERF_STOP(NV12_color_convert, fix_cpu_frequency); + free(source_buffer); + + output_size = MAX_CODED_BUFFER_SIZE(width, height); + output_buffer = malloc(output_size); + if (NULL == output_buffer) { + fprintf(stderr, "Fail to allocate output buffer: %d(%s)!\n", errno, strerror(errno)); + free(converted_source_buffer); + return 1; + } + memset(output_buffer, 0, output_size); + + encode_thread = (pthread_t *)malloc(sizeof(pthread_t) * thread); + if (NULL == encode_thread) { + fprintf(stderr, "Fail to allocate thread data: %d(%s)!\n", errno, strerror(errno)); + free(converted_source_buffer); + free(output_buffer); + return 1; + } + encode_thread_para = (thread_parameters *)malloc(sizeof(thread_parameters) * thread); + if (NULL == encode_thread_para) { + fprintf(stderr, "Fail to allocate thread data: %d(%s)!\n", errno, strerror(errno)); + free(converted_source_buffer); + free(output_buffer); + free(encode_thread); + return 1; + } + sub_coded_size = (int *)malloc(sizeof(int) * thread); + if (NULL == sub_coded_size) { + fprintf(stderr, "Fail to allocate thread data: %d(%s)!\n", errno, strerror(errno)); + free(converted_source_buffer); + free(output_buffer); + free(encode_thread); + free(encode_thread_para); + return 1; + } + + + PERF_START(core_encoding, fix_cpu_frequency); + /* Create encoding threads */ + for (i=0; i<thread; ++i) { + encode_thread_para[i].id = i; + encode_thread_para[i].width = width; + encode_thread_para[i].height = height; + encode_thread_para[i].quality = quality; + encode_thread_para[i].source_buffer = converted_source_buffer; + encode_thread_para[i].sub_height = ((height/thread+NV12_MCU_SIZE-1) + /NV12_MCU_SIZE)*NV12_MCU_SIZE; + encode_thread_para[i].rows = (i != (thread-1))? + encode_thread_para[i].sub_height: + (height-(encode_thread_para[i].sub_height*(thread-1))); + encode_thread_para[i].sub_output_size = output_size/thread; + encode_thread_para[i].sub_output_buffer = (void *)((unsigned int)output_buffer + + (output_size/thread)*i); + + pthread_create(&encode_thread[i], NULL, encode_thread_fn, (void *)&encode_thread_para[i]); + } + + /* Wait for encoding threads' completion */ + for (i=0; i<thread; ++i) { + pthread_join(encode_thread[i], (void **)&sub_coded_size[i]); + if (sub_coded_size[i] <= 0) { + hasError = true; + } + } + free(converted_source_buffer); + if (hasError) { + free(output_buffer); + free(encode_thread); + free(encode_thread_para); + free(sub_coded_size); + return 1; + } + PERF_STOP(core_encoding, fix_cpu_frequency); + + /* Dump each encoding thread's result */ + for (i=0; i<thread; ++i) { + printf("Thread %d: the coded size is %d.\n", i, sub_coded_size[i]); + } + printf("\n"); + + /* Create the final output buffer to take merged coded data */ + merged_output_buffer = malloc(output_size); + if (NULL == merged_output_buffer) { + fprintf(stderr, "Fail to allocate merged output buffer: %d(%s)!\n", errno, strerror(errno)); + free(output_buffer); + free(encode_thread); + free(encode_thread_para); + free(sub_coded_size); + return 1; + } + memset(merged_output_buffer, 0, output_size); + + /* Merge those sub-pictures together */ + PERF_START(subpictures_merging, fix_cpu_frequency); + + /* Write the JPEG header */ + memcpy(merged_output_buffer, + encode_thread_para[0].sub_output_buffer, + HEADER_TOTAL_LEN-HEADER_SOS_LEN); + output_size = HEADER_TOTAL_LEN - HEADER_SOS_LEN; + + /* Update the width and height info */ + merged_output_buffer[HEADER_HEIGHT_POS] = (height>>8) & 0xFF; + merged_output_buffer[HEADER_HEIGHT_POS+1] = (height) & 0xFF; + merged_output_buffer[HEADER_WIDTH_POS] = (width>>8) & 0xFF; + merged_output_buffer[HEADER_WIDTH_POS+1] = (width) & 0xFF; + + /* Write the restarting interval */ + if (thread > 1) { + unsigned int MCUs = (encode_thread_para[0].sub_height/NV12_MCU_SIZE) * + (width/NV12_MCU_SIZE); + + merged_output_buffer[output_size++] = 0xFF; + merged_output_buffer[output_size++] = 0xDD; + merged_output_buffer[output_size++] = 0; + merged_output_buffer[output_size++] = 4; + merged_output_buffer[output_size++] = (MCUs>>8) & 0xFF; + merged_output_buffer[output_size++] = (MCUs) & 0xFF; + } + + memcpy((void *)((unsigned int)merged_output_buffer+output_size), + (void *)((unsigned int)encode_thread_para[0].sub_output_buffer+HEADER_TOTAL_LEN-HEADER_SOS_LEN), + HEADER_SOS_LEN); + output_size += HEADER_SOS_LEN; + + /* Write coded segments */ + for (i=0; i<thread; ++i) { + memcpy((void *)((unsigned int)merged_output_buffer+output_size), + (void *)((unsigned int)encode_thread_para[i].sub_output_buffer+HEADER_TOTAL_LEN), + (sub_coded_size[i]-HEADER_TOTAL_LEN-HEADER_EOI_LEN)); + output_size += (sub_coded_size[i]-HEADER_TOTAL_LEN-HEADER_EOI_LEN); + + if (i != (thread-1)) { + merged_output_buffer[output_size++] = 0xFF; + merged_output_buffer[output_size++] = (i&0x7) | 0xD0; + } + } + /* Write EOI */ + merged_output_buffer[output_size++]= 0xFF; + merged_output_buffer[output_size++]= 0xD9; + + PERF_STOP(subpictures_merging, fix_cpu_frequency); + + free(output_buffer); + free(encode_thread); + free(encode_thread_para); + free(sub_coded_size); + + output_fd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0664); + if (-1 == output_fd) { + fprintf(stderr, "Error opening output file: %s (%s)!\n", output_name, strerror(errno)); + free(merged_output_buffer); + return 1; + } + + write_size = write(output_fd, merged_output_buffer, output_size); + if (write_size != output_size) { + fprintf(stderr, "Fail to write coded data to output file: %d(%s)!\n", write_size , strerror(errno)); + close(output_fd); + free(merged_output_buffer); + return 1; + } + + free(merged_output_buffer); + close(output_fd); + output_fd = -1; + + convert_time = PERF_GET(NV12_color_convert); + core_encoding_time = PERF_GET(core_encoding); + subpictures_merging_time = PERF_GET(subpictures_merging); + total_time = convert_time + core_encoding_time + subpictures_merging_time; + printf("[SUM]Convert: %.3fms\n", ((double)convert_time)/cpu_available_max); + printf("[SUM]Core encoding: %.3fms\n", ((double)core_encoding_time)/cpu_available_max); + printf("[SUM]Sub-pictures merging: %.3fms\n", ((double)subpictures_merging_time)/cpu_available_max); + 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", compression_rate, output_size, source_size); + + //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; + } + } + } + //Restoring is done + + return 0; +} diff --git a/android/mce.cpp b/android/mce.cpp index 1bd3bee..84d8765 100644 --- a/android/mce.cpp +++ b/android/mce.cpp @@ -26,7 +26,6 @@ Chang, Ying<ying.chang@intel.com> Wang, Elaine<elaine.wang@intel.com> */ - //#define LOG_NDEBUG 0 #define LOG_TAG "mce" #include <utils/Log.h> @@ -55,10 +54,11 @@ #include "vpx/vp8cx.h" #define fourcc 0x30385056 +#define vp9_fourcc 0x30395056 using namespace android; -static int64_t kTimeout = 50000ll; +static int64_t kTimeout = 5000000ll; static void usage(const char *me) { fprintf(stderr, "MediCodec Encoder\n" @@ -66,7 +66,7 @@ static void usage(const char *me) { "\t\t-w width -h height\n" "\t\t-f framerate -b bitreate -c color format{0 - nv12, 1 - i420}\n" "\t\t-p output format{0 - es, 1 - muxed}\n" - "\t\t-v mimetype{video/avc, video/x-vnd.on2.vp8, video/mp4v-es, video/3gpp}\n", + "\t\t-v mimetype{video/avc, video/x-vnd.on2.vp8, video/x-vnd.on2.vp9, video/mp4v-es, video/3gpp}\n", me); exit(1); @@ -84,6 +84,30 @@ static void mem_put_le32(char *mem, unsigned int val) { mem[3] = val>>24; } +static void write_vp9_file_header(FILE *outfile, + const vpx_codec_enc_cfg_t *cfg, + int frame_cnt) { + char header[32]; + + if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) + return; + header[0] = 'D'; + header[1] = 'K'; + header[2] = 'I'; + header[3] = 'F'; + mem_put_le16(header+4, 0); /* version */ + mem_put_le16(header+6, 32); /* headersize */ + mem_put_le32(header+8, vp9_fourcc); /* headersize */ + mem_put_le16(header+12, cfg->g_w); /* width */ + mem_put_le16(header+14, cfg->g_h); /* height */ + mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ + mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ + mem_put_le32(header+24, frame_cnt); /* length */ + mem_put_le32(header+28, 0); /* unused */ + + (void) fwrite(header, 1, 32, outfile); +} + static void write_ivf_file_header(FILE *outfile, const vpx_codec_enc_cfg_t *cfg, int frame_cnt) { @@ -142,6 +166,7 @@ int main(int argc, char **argv) { vpx_codec_cx_pkt_t pkt; vpx_codec_enc_cfg_t cfg; bool is_vpx = false; + bool is_vp9 = false; while ((res = getopt(argc, argv, "i:o:f:b:w:h:c:v:p:n:")) >= 0) { switch (res) { @@ -216,7 +241,8 @@ int main(int argc, char **argv) { "mimetype %s, input %s, output %s\n", width, height, bitrate, framerate, mime, input, output); is_vpx = (strncmp(mime, "video/x-vnd.on2.vp8", 19) == 0); - if (is_vpx) { + is_vp9 = (strncmp(mime, "video/x-vnd.on2.vp9", 19) == 0); + if (is_vpx || is_vp9) { cfg.g_w = width; cfg.g_h = height; cfg.g_timebase.den = framerate ; @@ -258,8 +284,9 @@ int main(int argc, char **argv) { fIn = fopen(input, "r"); if(outputFormat) { - pMuxer = new MediaMuxer(output, - is_vpx ? MediaMuxer::OUTPUT_FORMAT_WEBM : MediaMuxer::OUTPUT_FORMAT_MPEG_4); + fOut = fopen(output, "w"); + pMuxer = new MediaMuxer(fileno(fOut), + (is_vpx||is_vp9) ? MediaMuxer::OUTPUT_FORMAT_WEBM : MediaMuxer::OUTPUT_FORMAT_MPEG_4); } else { fOut = fopen(output, "w"); } @@ -271,6 +298,8 @@ int main(int argc, char **argv) { if (is_vpx && !outputFormat) write_ivf_file_header(fOut, &cfg, 0); + if (is_vp9 && !outputFormat) + write_vp9_file_header(fOut, &cfg, 0); err = codec->configure(format, NULL, NULL, MediaCodec::CONFIGURE_FLAG_ENCODE); CHECK_EQ(err, (status_t)OK); @@ -312,7 +341,7 @@ again: sawOutputEOS = true; } else { if (!outputFormat) { - if (is_vpx) { + if (is_vpx || is_vp9) { pkt.data.frame.sz = size; pkt.data.frame.pts = frame_cnt; pkt.kind = VPX_CODEC_CX_FRAME_PKT; @@ -355,8 +384,13 @@ again: if(!fseek(fOut, 0, SEEK_SET)) write_ivf_file_header(fOut, &cfg, frame_cnt); } + if (is_vp9) { + if(!fseek(fOut, 0, SEEK_SET)) + write_vp9_file_header(fOut, &cfg, frame_cnt); + } fclose(fOut); } else { + fclose(fOut); err = pMuxer->stop(); CHECK_EQ(err, (status_t)OK); } diff --git a/android/skia-encoder.cpp b/android/skia-encoder.cpp new file mode 100755 index 0000000..1a405bb --- /dev/null +++ b/android/skia-encoder.cpp @@ -0,0 +1,127 @@ +#include <getopt.h> +#include <stdio.h> + +#include "SkBitmap.h" +#include "SkPaint.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkString.h" +#include "SkImageEncoder.h" +#include "SkImageDecoder.h" + +static SkImageEncoder::Type image_type; +static char* src_image = NULL; +static char* dst_image = NULL; + +static void usage(const char* pname) +{ + fprintf(stderr, + "\n USAGE: %s -src [path] -dst [path] \n" + "\n Image Support .PNG(.png), .WEBP(.webp) or .JPEG(.jpeg) Format Only.\n" + ,pname); +} + + +static int process_cmdline(int argc, char *argv[]) +{ + char c; + +#if 0 + int i; + printf("Argumen Num = %d\n", argc); + for (i = 0; i < argc; i++) { + printf("Argument %d:%s\n", i, argv[i]); + } + printf("==>%s:%d\n", __FUNCTION__, __LINE__); +#endif + + const struct option long_opts[] = { + {"help", no_argument, NULL, 0 }, + {"src", required_argument, NULL, 1 }, + {"dst", required_argument, NULL, 2 }, + {NULL, 0, 0, 0}}; + + if (argc <= 1) { + usage(argv[0]); /* No argument */ + return 1; + } + + while ((c = getopt_long_only(argc,argv,"?",long_opts,NULL)) != EOF) { + switch (c) { + case '?': + goto out; + break; + + case 0: + goto out; + break; + + case 1: + src_image = strdup(optarg); + break; + + case 2: + dst_image = strdup(optarg); + break; + + default: + goto out; + break; + } + } + + if ((NULL == src_image) || (NULL == dst_image)) { + goto out; + } + + if ((NULL != strstr(dst_image, ".PNG")) || (NULL != strstr(dst_image, ".png"))) { + image_type = SkImageEncoder::kPNG_Type; + } else if ((NULL != strstr(dst_image, ".WEBP")) || (NULL != strstr(dst_image, ".webp"))) { + image_type = SkImageEncoder::kWEBP_Type; + } else if ((NULL != strstr(dst_image, ".JPEG")) || (NULL != strstr(dst_image, ".jpeg"))) { + image_type = SkImageEncoder::kJPEG_Type; + } else { + goto out; + } + + printf("============= Start Encode ==============\n"); + if (SkImageEncoder::kPNG_Type == image_type) { + printf("INPUT: IMAGE TYPE : PNG IMAGE\n"); + } else if (SkImageEncoder::kWEBP_Type == image_type) { + printf("INPUT: IMAGE TYPE : WEBP IMAGE\n"); + } else if (SkImageEncoder::kJPEG_Type == image_type) { + printf("INPUT: IMAGE TYPE : JPEG IMAGE\n"); + } + + printf("INPUT: Src IMAGE : %s\n", src_image); + printf("INPUT: Dest IMAGE : %s\n", dst_image); + + return 1; + +out: + usage(argv[0]); + exit(0); +} + + +int main(int argc, char* argv[]) +{ + int ret = -1; + int i = 0; + + process_cmdline(argc, argv); + + SkBitmap srcImage; + + ret = SkImageDecoder::DecodeFile(src_image, &srcImage); + printf("Decode is successful? %s \n", (ret ? "Yes" : "No")); + + ret =SkImageEncoder::EncodeFile(dst_image, srcImage, image_type, 100); + printf("Encode is successful? %s \n", (ret ? "Yes" : "No")); + + printf("============= Finish Encode ==============\n"); + + return 0; +} + + diff --git a/utils/loadsurface_yuv.h b/utils/loadsurface_yuv.h index 0b466c1..05852dc 100644 --- a/utils/loadsurface_yuv.h +++ b/utils/loadsurface_yuv.h @@ -28989,7 +28989,6 @@ static int yuvgen_planar(int width, int height, /* copy UV data */ for( row =0; row < height/2; row++) { - /* fill garbage data into the other field */ if (((field == VA_TOP_FIELD) && (row &1)) || ((field == VA_BOTTOM_FIELD) && ((row &1)==0))) { @@ -29003,6 +29002,7 @@ static int yuvgen_planar(int width, int height, memset(U_row, uv_value, width); break; case VA_FOURCC_YV12: + case VA_FOURCC_IYUV: memset (U_row,uv_value,width/2); memset (V_row,uv_value,width/2); break; diff --git a/vaenc/Android.mk b/vaenc/Android.mk index db9dd48..623ea8f 100644 --- a/vaenc/Android.mk +++ b/vaenc/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := \ va_encode.c va_surface.c h264encode.c \ mpeg4encode.c h263encode.c vp8encode.c \ jpegencode.c jpegtables.c mpeg2encode.c \ + hevcencode.c \ codedmeta.c ../utils/configrc.lex.l ../utils/configrc.yacc.y \ ../android/gralloc.cpp ../utils/psnr.c ../utils/ssim.c diff --git a/vaenc/Makefile b/vaenc/Makefile index 87f431f..3b1f5c8 100644 --- a/vaenc/Makefile +++ b/vaenc/Makefile @@ -1,7 +1,7 @@ all: va_encode -srcs=va_encode.c h264encode.c mpeg4encode.c h263encode.c vp8encode.c jpegencode.c jpegtables.c mpeg2encode.c va_surface.c codedmeta.c configrc.lex.c configrc.yacc.c ../common/va_display.c ../common/va_display_drm.c ../common/va_display_x11.c ../utils/ssim.c ../utils/psnr.c -objs=va_encode.o h264encode.o mpeg4encode.o h263encode.o vp8encode.o jpegencode.o jpegtables.o mpeg2encode.o va_surface.o codedmeta.o configrc.lex.o configrc.yacc.o ../common/va_display.o ../common/va_display_drm.o ../common/va_display_x11.o ../utils/ssim.o ../utils/psnr.o +srcs=va_encode.c h264encode.c mpeg4encode.c h263encode.c vp8encode.c hevcencode.c jpegencode.c jpegtables.c mpeg2encode.c va_surface.c codedmeta.c configrc.lex.c configrc.yacc.c ../common/va_display.c ../common/va_display_drm.c ../common/va_display_x11.c ../utils/ssim.c ../utils/psnr.c +objs=va_encode.o h264encode.o mpeg4encode.o h263encode.o vp8encode.o hevcencode.o jpegencode.o jpegtables.o mpeg2encode.o va_surface.o codedmeta.o configrc.lex.o configrc.yacc.o ../common/va_display.o ../common/va_display_drm.o ../common/va_display_x11.o ../utils/ssim.o ../utils/psnr.o headers=va_encode.h cflags=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE diff --git a/vaenc/hevcencode.c b/vaenc/hevcencode.c index 8079075..af9d3f0 100644 --- a/vaenc/hevcencode.c +++ b/vaenc/hevcencode.c @@ -46,6 +46,17 @@ #define NAL_PPS 8 #define NAL_SEI 6 +#define NAL_VPS_HEVC 0x20 +#define NAL_SPS_HEVC 0x21 +#define NAL_PPS_HEVC 0x22 +#define NAL_AUD_HEVC 0x09 + +#define TRAIL_R 1 +#define IDR_W_RADL 19 +#define IDR_N_LP 20 +#define BLA_W_LP 16 +#define RSV_IRAP_VCL23 23 + #define SLICE_TYPE_P 0 #define SLICE_TYPE_B 1 #define SLICE_TYPE_I 2 @@ -59,10 +70,13 @@ #define BITSTREAM_ALLOCATE_STEPPING 4096 +#define NUM_MAX_REF_FRAME_HEVC 15 + static VAConfigAttrib hevc_attrib[VAConfigAttribTypeMax]; static VAEncSequenceParameterBufferHEVC seq_param; -static VAPictureParameterBufferHEVC pic_param; +static VAEncPictureParameterBufferHEVC pic_param; +static VAEncSliceParameterBufferHEVC slc_param; static VAPictureHEVC CurrentCurrPic; static VAPictureHEVC ReferenceFrames[16], RefPicList0_P[32], RefPicList0_B[32], RefPicList1_B[32]; @@ -75,14 +89,20 @@ static unsigned int num_ref_frames = 2; static unsigned int numShortTerm = 0; static int constraint_set_flag = 0; static int hevc_packedheader = 0; /* support pack header? */ -static int hevc_maxref = (1<<16|1); +static int hevc_maxref = 15; static int hevc_autoref = 0; +static int frame_poc = 0; + static VAProfile hevc_profile = -1; int hevc_entropy_mode = 1; /* cabac */ int hevc_8x8_dct = 0; +#define LCU_SIZE 32 +#define ALIGN(x, align) (((x) + (align) - 1 ) & (~((align) - 1))) +#define GET_CTU_NUM(x, LCU_SIZE) ((ALIGN(x, LCU_SIZE))/LCU_SIZE) + struct __bitstream { unsigned int *buffer; int bit_offset; @@ -205,149 +225,253 @@ rbsp_trailing_bits(bitstream *bs) bitstream_byte_aligning(bs, 0); } -static void nal_start_code_prefix(bitstream *bs) +static unsigned char get_va_frame_type(int frame_type) { + switch (frame_type) { + case FRAME_IDR: + return 7; + case FRAME_I: + return 2; + case FRAME_P: + return 0; + case FRAME_B: + return 1; + default: + fprintf(stderr, "%s Invalid frame type:%d\n", __FUNCTION__, frame_type); + return 0; + } +} + + +static void nal_start_code_prefix_HEVC(bitstream *bs, bool flag) { - bitstream_put_ui(bs, 0x00000001, 32); + if (!flag) + bitstream_put_ui(bs, 0x00, 8); + bitstream_put_ui(bs, 0x000001, 24); } -static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type) +static void nal_header_HEVC(bitstream *bs, int nal_ref_idc, int nal_unit_type) { bitstream_put_ui(bs, 0, 1); /* forbidden_zero_bit: 0 */ - bitstream_put_ui(bs, nal_ref_idc, 2); - bitstream_put_ui(bs, nal_unit_type, 5); + bitstream_put_ui(bs, nal_unit_type, 6); + bitstream_put_ui(bs, 0, 6); + bitstream_put_ui(bs, 1, 3); } -static void sps_rbsp(bitstream *bs) +static void profile_tier_level(bitstream *bs) { - int profile_idc = PROFILE_IDC_BASELINE; - - bitstream_put_ui(bs, 0, 32); - bitstream_put_ui(bs, 0, 32); - - //profile_tier_level(0) - - bitstream_put_ui(bs, seq_param.general_profile_idc, 8); //general_profile_idc = 1; - bitstream_put_ui(bs, 0, 32); //eneral_profile_compatibility_flag[] = 0; - //general_progressive_source_flag = 1 general_interlaced_source_flag = 0 - //general_non_packed_constraint_flag = 1 general_frame_only_constraint_flag = 0 - bitstream_put_ui(bs, 0xb<<4, 8); - bitstream_put_ui(bs, 0, 32); - bitstream_put_ui(bs, 0, 8); - //general_level_idc = 123, i.e. L4.1 - bitstream_put_ui(bs, seq_param.general_level_idc * 30, 8); - bitstream_put_ue(bs, 0); //sps_seq_parameter_set_id - bitstream_put_ue(bs, seq_param.seq_fields.chroma_format_idc); //chroma_format_idc - - bitstream_put_ue(bs, frame_width_mbaligned); - bitstream_put_ue(bs, frame_height_mbaligned); - - //conformance_window_flag = 0 - bitstream_put_ui(bs, seq_param.frame_cropping_flag, 1); /* frame_cropping_flag */ - - if (seq_param.frame_cropping_flag) { - bitstream_put_ue(bs, seq_param.frame_crop_left_offset); /* frame_crop_left_offset */ - bitstream_put_ue(bs, seq_param.frame_crop_right_offset); /* frame_crop_right_offset */ - bitstream_put_ue(bs, seq_param.frame_crop_top_offset); /* frame_crop_top_offset */ - bitstream_put_ue(bs, seq_param.frame_crop_bottom_offset); /* frame_crop_bottom_offset */ - } - - //bit_depth_luma_minus8 bit_depth_chroma_minus8 - bitstream_put_ue(bs, 0); - bitstream_put_ue(bs, 0); - - bitstream_put_ue(bs, seq_param.seq_fields.bits.log2_max_pic_order_cnt_cnt_lsb_minus4); - - //sps_sub_layer_ordering_info_present_flag + int i = 0; + bitstream_put_ui(bs, 0, 2); bitstream_put_ui(bs, 0, 1); - //log2_min_luma_coding_block_size_minus3 - bitstream_put_ue(bs, 1); - bitstream_put_ue(bs, 0); - bitstream_put_ue(bs, 1); - bitstream_put_ue(bs, 0); - bitstream_put_ue(bs, 1); - bitstream_put_ue(bs, 1); + bitstream_put_ui(bs, 1, 5); + for(i = 0; i < 32; i++) + bitstream_put_ui(bs, 0, 1); - bitstream_put_ui(bs, 0, 4); + bitstream_put_ui(bs, 1, 1); + bitstream_put_ui(bs, 0, 1); + bitstream_put_ui(bs, 0, 1); + bitstream_put_ui(bs, 1, 1); + bitstream_put_ui(bs, 0/*ps.general_reserved_zero_44bits*/, 44); + bitstream_put_ui(bs, 51*3, 8); +} + +static void sps_rbsp(bitstream *bs) +{ + int conformance_window_flag = 0; + bitstream_put_ui(bs, 0, 4); //sps_video_parameter_set_id + bitstream_put_ui(bs, 0, 3); + bitstream_put_ui(bs, 1, 1); //sps_temporal_id_nesting_flag + profile_tier_level(bs); - //num_short_term_ref_pic_sets bitstream_put_ue(bs, 0); - //num_long_term_ref_pic_sets - bitstream_put_ue(bs, 0); - - //sps_temporal_mvp_enabled_flag strong_intra_smoothing_enabled_flag - //vui_parameters_present_flag - bitstream_put_ui(bs, 0, 3); - + bitstream_put_ue(bs, 1); //4:2:0 seq_param.seq_fields.bits.chroma_format_idc + if (seq_param.seq_fields.bits.chroma_format_idc == 3) + bitstream_put_ui(bs, 0, 1); + + int wFrameWidthInMinCbMinus1 = (ALIGN(frame_width, 16) >> 3) - 1; + seq_param.pic_width_in_luma_samples = (wFrameWidthInMinCbMinus1 + 1) * (1 << 3); + bitstream_put_ue(bs, seq_param.pic_width_in_luma_samples); + int wFrameHeightInMinCbMinus1 = (ALIGN(frame_height, 16) >> 3) - 1; + seq_param.pic_height_in_luma_samples = (wFrameHeightInMinCbMinus1 + 1) * (1 << 3); + bitstream_put_ue(bs, seq_param.pic_height_in_luma_samples); + + if((ALIGN(frame_width, 16) != frame_width) || (ALIGN(frame_height, 16) != frame_height)) + { + conformance_window_flag = 1; + bitstream_put_ui(bs, conformance_window_flag, 1); //conformance_window_flag + bitstream_put_ue(bs, 0); //conf_win_left_offset + //bitstream_put_ue(bs, (frame_width_mbaligned - frame_width)/2); + bitstream_put_ue(bs, (ALIGN(frame_width, 16) - frame_width)/2); //conf_win_right_offset + bitstream_put_ue(bs, 0); // conf_win_top_offset + //bitstream_put_ue(bs, (frame_height_mbaligned - frame_height)/2); + bitstream_put_ue(bs, (ALIGN(frame_height, 16) - frame_height)/2); // conf_win_bottom_offset + } + else + bitstream_put_ui(bs, conformance_window_flag, 1); //conformance_window_flag + + bitstream_put_ue(bs, 0); //seq_fields.bits.bit_depth_luma_minus8 + bitstream_put_ue(bs, 0); //seq_fields.bits.bit_depth_chroma_minus8 + bitstream_put_ue(bs, 0); // log2_max_pic_order_cnt_lsb_minus4); + bitstream_put_ui(bs, 0, 1); //sps_sub_layer_ordering_info_present_flag + + bitstream_put_ue(bs, 6); // sps_max_dec_pic_buffering[0] + bitstream_put_ue(bs, 0); //sps.sps_num_reorder_pics[0]); + bitstream_put_ue(bs, 0); //sps.sps_max_latency_increase[0]); + + bitstream_put_ue(bs, 0);// seq_param.log2_min_luma_coding_block_size_minus3); + bitstream_put_ue(bs, 2); //seq_param.log2_diff_max_min_luma_coding_block_size); + bitstream_put_ue(bs, 0); //seq_param.log2_min_transform_block_size_minus2); + bitstream_put_ue(bs, 3); //seq_param.log2_diff_max_min_transform_block_size); + bitstream_put_ue(bs, 2); //seq_param.max_transform_hierarchy_depth_inter); + bitstream_put_ue(bs, 2); //seq_param.max_transform_hierarchy_depth_intra); + + bitstream_put_ui(bs, 0, 1); //seq_param.seq_fields.bits.scaling_list_enabled_flag, 1); + bitstream_put_ui(bs, 1, 1); //seq_param.seq_fields.bits.amp_enabled_flag, 1); + bitstream_put_ui(bs, 0, 1); //seq_param.seq_fields.bits.sample_adaptive_offset_enabled_flag, 1); + bitstream_put_ui(bs, 0, 1); //seq_param.seq_fields.bits.pcm_enabled_flag, 1); + + bitstream_put_ue(bs, 1); //sps.num_short_term_ref_pic_sets); + bitstream_put_ue(bs, 1); // num_negative_pics port from short_term_ref_pic_set() + bitstream_put_ue(bs, 0); // ps.num_positive_pics[refIdx==0?0:1] + bitstream_put_ue(bs, 0); // ps.delta_poc_s0_minus1[refIdx] + bitstream_put_ui(bs, 1, 1); // ps.used_by_curr_pic_s0_flag[refIdx], 1) + + bitstream_put_ui(bs, 0, 1); //sps.long_term_ref_pics_present_flag, 1); + bitstream_put_ui(bs, 1, 1); //seq_param.seq_fields.bits.sps_temporal_mvp_enabled_flag, 1); + bitstream_put_ui(bs, 0, 1); //seq_param.seq_fields.bits.strong_intra_smoothing_enabled_flag , 1); + bitstream_put_ui(bs, 0, 1); //seq_param.vui_parameters_present_flag, 1); + bitstream_put_ui(bs, 0, 1); //sps.sps_extension_flag, 1); - rbsp_trailing_bits(bs); /* rbsp_trailing_bits */ + rbsp_trailing_bits(bs); } static void pps_rbsp(bitstream *bs) { - bitstream_put_ue(bs, pic_param.pic_parameter_set_id); /* pic_parameter_set_id */ - bitstream_put_ue(bs, pic_param.seq_parameter_set_id); /* seq_parameter_set_id */ + bitstream_put_ue(bs, 0); //pps.pic_parameter_set_id); + bitstream_put_ue(bs, 0); //sps.sps_seq_parameter_set_id); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.dependent_slice_segments_enabled_flag, 1); + bitstream_put_ui(bs, 0, 1); //pps.output_flag_present_flag, 1); + bitstream_put_ui(bs, 0, 3); //pps.num_extra_slice_header_bits, 3); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.sign_data_hiding_enabled_flag, 1); + bitstream_put_ui(bs, 1, 1); //pps.cabac_init_present_flag, 1); + + bitstream_put_ue(bs, 0); //pps.num_ref_idx_l0_default_active_minus1); + bitstream_put_ue(bs, 0); //pic_param.num_ref_idx_l1_default_active_minus1); + bitstream_put_se(bs, 2); //pic_param.pic_init_qp + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.constrained_intra_pred_flag, 1); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.transform_skip_enabled_flag , 1); + if (rc_mode == VA_RC_CQP) + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.cu_qp_delta_enabled_flag , 1); + else + { + bitstream_put_ui(bs, 1, 1); + bitstream_put_ue(bs, 0); //pic_param.diff_cu_qp_delta_depth); + } - bitstream_put_ui(bs, pic_param.pic_fields.dependent_slice_segments_enabled_flag, 1); + bitstream_put_se(bs, 0); //pic_param.pps_cb_qp_offset); + bitstream_put_se(bs, 0); //pic_param.pps_cr_qp_offset); + bitstream_put_ui(bs, 0, 1); //pps.pps_slice_chroma_qp_offsets_present_flag, 1) + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.weighted_pred_flag, 1); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.weighted_bipred_flag, 1); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.transquant_bypass_enabled_flag, 1); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.tiles_enabled_flag, 1); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.entropy_coding_sync_enabled_flag, 1); - bitstream_put_ui(bs, 0, 4); + /* skip pic_param.pic_fields.bits.tiles_enabled_fla part */ - bitstream_put_ui(bs, pic_param.pic_fields.sign_data_hiding_enabled_flag); + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.pps_loop_filter_across_slices_enabled_flag, 1); + bitstream_put_ui(bs, 1, 1); //pps.deblocking_filter_control_present_flag, 1); - //cabac_init_present_flag - bitstream_put_ui(bs, 1, 1); - bitstream_put_ue(bs, pic_param.num_ref_idx_l0_active_minus1); /* num_ref_idx_l0_active_minus1 */ - bitstream_put_ue(bs, pic_param.num_ref_idx_l1_active_minus1); /* num_ref_idx_l1_active_minus1 1 */ + bitstream_put_ui(bs, 1, 1); //pps.deblocking_filter_override_enabled_flag, 1); + bitstream_put_ui(bs, 1, 1); //pps.disable_deblocking_filter_flag, 1); - bitstream_put_se(bs, pic_param.pic_init_qp - 26); /* pic_init_qp_minus26 */ + bitstream_put_ui(bs, 0, 1); //pic_param.pic_fields.bits.scaling_list_data_present_flag, 1); - bitstream_put_ui(bs, pic_param.pic_fields.constrained_intra_pred_flag, 1); - bitstream_put_ui(bs, pic_param.pic_fields.transform_skip_enabled_flag, 1); - bitstream_put_ui(bs, pic_param.pic_fields.cu_qp_delta_enabled_flag, 1); - bitstream_put_ui(bs, pic_param.pic_fields.bits.entropy_coding_mode_flag, 1); /* entropy_coding_mode_flag */ - if (pic_param.pic_fields.bits.entropy_coding_mode_flag) - bitstream_put_ue(bs, pic_param.diff_cu_qp_delta_depth); - bitstrea_put_se(se, pic_param.pps_cb_qp_offset); - bitstrea_put_se(se, pic_param.pps_cr_qp_offset); + bitstream_put_ui(bs, 0, 1); //pps.lists_modification_present_flag, 1); + bitstream_put_ue(bs, 0); //pic_param.log2_parallel_merge_level_minus2); + bitstream_put_ui(bs, 0, 1); //pps.slice_segment_header_extension_present_flag, 1); + bitstream_put_ui(bs, 0, 1); //pps.pps_extension_flag, 1); - //pps_slice_chroma_qp_offsets_present_flag - bitstream_put_ui(bs, 0, 1); - //weighted_pred_flag - bitstream_put_ui(bs, pic_param.pic_fields.weighted_pred_flag, 1); - //weighted_bipred_flag - bitstream_put_ui(bs, 0, 1); + rbsp_trailing_bits(bs); +} - bitstream_put_ui(bs,pic_param.pic_fields.transquant_bypass_enabled_flag, 1); - bitstream_put_ui(bs,pic_param.pic_fields.tiles_enabled_flag, 1); - bitstream_put_ui(bs,pic_param.pic_fields.entropy_coding_sync_enabled_flag, 1); - - if (pic_param.pic_fields.tiles_enabled_flag) { - bitstream_put_ue(bs, pic_param.num_tile_columns_minus1); - bitstream_put_ue(bs, pic_param.num_tile_rows_minus1); - //uniform_spacing_flag - bitstream_put_ui(bs, 0, 1); - for( i = 0; i < pic_param.num_tile_columns_minus1; i++ ) - bitstream_put_ue(bs, pic_param.column_width_minus1[i]); - - for( i = 0; i < pic_param.num_tile_rows_minus1; i++ ) - bitstream_put_ue(bs, pic_param.row_height_minus1[i]); - bistream_put_ui(bs, pic_param.pic_fields.loop_filter_across_tiles_enabled_flag, 1); +static void slice_rbsp(bitstream *bs) +{ + unsigned char frame_type = get_va_frame_type(current_frame_type); + unsigned char slice_type = (frame_type == FRAME_IDR)? SLICE_TYPE_I : current_frame_type; + unsigned char nal_type = (frame_type == FRAME_IDR) ? IDR_W_RADL : TRAIL_R; + + bitstream_put_ui(bs, 1, 1); // sliceps.first_slice_in_pic_flag, 1); + + if (nal_type >= BLA_W_LP && nal_type <= RSV_IRAP_VCL23) + bitstream_put_ui(bs, 0, 1); //sliceps.no_output_of_prior_pics_flag, 1); + + bitstream_put_ue(bs, 0); //slc_param.slice_pic_parameter_set_id); + + bitstream_put_ue(bs, slice_type); //sliceps.slice_type); + + if (nal_type != IDR_W_RADL && nal_type != IDR_N_LP) + { + bitstream_put_ui(bs, frame_poc, 4); // or 8 sliceps.pic_order_cnt_lsb/2, (sps.log2_max_pic_order_cnt_lsb_minus4+4)); + bitstream_put_ui(bs, 1, 1); //sliceps.short_term_ref_pic_set_sps_flag, 1); + + bitstream_put_ui(bs, 1, 1); //sliceps.slice_fields.bits.slice_temporal_mvp_enabled_flag, 1); } - //pps_loop_filter_across_slices_enabled_flag - //deblocking_filter_control_present_flag - //pps_scaling_list_data_present_flag - //lists_modification_present_flag - bitstream_put_ui(bs, 0, 4); - bitstream_put_ue(bs, pic_param.log2_parallel_merge_level_minus2); - //slice_segment_header_extension_present_flag - //pps_extension_flag - bitstream_put_ui(bs, 0, 2); + /* skip seq_fields.bits.sample_adaptive_offset_enabled part */ + + if (slice_type == SLICE_TYPE_P) + { + bitstream_put_ui(bs, 0, 1); //slc_param.slice_fields.bits.num_ref_idx_active_override_flag/*0*/, 1); + if (slice_type == SLICE_TYPE_P) + bitstream_put_ui(bs, 0, 1);//slc_param.slice_fields.bits.mvd_l1_zero_flag, 1); + + bitstream_put_ui(bs, 0, 1); //.slice_fields.bits.cabac_init_flag + bitstream_put_ui(bs, 1, 1);//slc_param.slice_fields.bits.collocated_from_l0_flag, 1); + + bitstream_put_ue(bs, 0);//5 - sliceps.max_num_merge_cand + } + + + bitstream_put_se(bs, 0); //slc_param.slice_qp_delta); + + bitstream_put_ui(bs, 1, 1); //sliceps.deblocking_filter_override_flag, 1); + bitstream_put_ui(bs, 0, 1); //slc_param.slice_fields.bits.slice_deblocking_filter_disabled_flag, 1); + bitstream_put_se(bs, 0); //slc_param.slice_beta_offset_div2); + bitstream_put_se(bs, 0); //slc_param.slice_tc_offset_div2); rbsp_trailing_bits(bs); + frame_poc++; } +static void vps_rbsp(bitstream *bs) +{ + bitstream_put_ui(bs, 0, 4); + bitstream_put_ui(bs, 3, 2); + bitstream_put_ui(bs, 0, 6); //vps.vps_max_layers_minus1, + bitstream_put_ui(bs, 0, 3); //vps.vps_max_sub_layers_minus1, 3); + bitstream_put_ui(bs, 1, 1); //vps.vps_temporal_id_nesting_flag, 1); + bitstream_put_ui(bs, 0xFFFF, 16); + + profile_tier_level(bs); + bitstream_put_ui(bs, 0, 1); //vps.vps_sub_layer_ordering_info_present_flag, 1); + + bitstream_put_ue(bs, 6); //?vps.vps_max_dec_pic_buffering[i]); + bitstream_put_ue(bs, 0); //vps.vps_num_reorder_pics[i]); + bitstream_put_ue(bs, 0); //vps.vps_max_latency_increase[i]); + + bitstream_put_ui(bs, 0, 6); //vps.max_nuh_reserved_zero_layer_id, 6); + bitstream_put_ue(bs, 0); //vps.max_op_sets-1); + + bitstream_put_ui(bs, 0, 1); //vps.vps_timing_info_present_flag, 1); + + /* skip vps_timing_info_present_flag part */ + + bitstream_put_ui(bs, 0, 1); + + rbsp_trailing_bits(bs); +} static int build_packed_pic_buffer(unsigned char **header_buffer) @@ -355,8 +479,8 @@ build_packed_pic_buffer(unsigned char **header_buffer) bitstream bs; bitstream_start(&bs); - nal_start_code_prefix(&bs); - nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS); + nal_start_code_prefix_HEVC(&bs, false); + nal_header_HEVC(&bs, NAL_REF_IDC_LOW, NAL_PPS_HEVC); pps_rbsp(&bs); bitstream_end(&bs); @@ -370,8 +494,8 @@ build_packed_seq_buffer(unsigned char **header_buffer) bitstream bs; bitstream_start(&bs); - nal_start_code_prefix(&bs); - nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS); + nal_start_code_prefix_HEVC(&bs, false); + nal_header_HEVC(&bs, NAL_REF_IDC_LOW, NAL_SPS_HEVC); sps_rbsp(&bs); bitstream_end(&bs); @@ -379,6 +503,38 @@ build_packed_seq_buffer(unsigned char **header_buffer) return bs.bit_offset; } +static int +build_packed_slice_buffer(unsigned char **header_buffer) +{ + unsigned char frame_type = get_va_frame_type(current_frame_type); + unsigned char nal_type = (frame_type == FRAME_IDR) ? IDR_W_RADL : TRAIL_R; + bitstream bs; + + bitstream_start(&bs); + nal_start_code_prefix_HEVC(&bs, true); + nal_header_HEVC(&bs, NAL_REF_IDC_LOW, nal_type); + slice_rbsp(&bs); + bitstream_end(&bs); + + *header_buffer = (unsigned char *)bs.buffer; + return bs.bit_offset; +} + +static int +build_packed_vps_buffer(unsigned char **header_buffer) +{ + bitstream bs; + + bitstream_start(&bs); + nal_start_code_prefix_HEVC(&bs, false); + nal_header_HEVC(&bs, NAL_REF_IDC_LOW, NAL_VPS_HEVC); + vps_rbsp(&bs); + bitstream_end(&bs); + + *header_buffer = (unsigned char *)bs.buffer; + return bs.bit_offset; +} + static int build_packed_sei_buffer_timing(unsigned int init_cpb_removal_length, unsigned int init_cpb_removal_delay, @@ -415,8 +571,8 @@ build_packed_sei_buffer_timing(unsigned int init_cpb_removal_length, pic_byte_size = (sei_pic_bs.bit_offset + 7) / 8; bitstream_start(&nal_bs); - nal_start_code_prefix(&nal_bs); - nal_header(&nal_bs, NAL_REF_IDC_NONE, NAL_SEI); + nal_start_code_prefix_HEVC(&nal_bs, false); + nal_header_HEVC(&nal_bs, NAL_REF_IDC_NONE, NAL_SEI); /* Write the SEI buffer period data */ bitstream_put_ui(&nal_bs, 0, 8); @@ -467,42 +623,42 @@ build_packed_sei_buffer_timing(unsigned int init_cpb_removal_length, } \ } \ -static void sort_one(VAPictureH264 ref[], int left, int right, - int ascending, int frame_idx) +static void sort_one(VAPictureHEVC ref[], int left, int right, + int ascending, int pic_order_cnt) { int i = left, j = right; unsigned int key; - VAPictureH264 tmp; + VAPictureHEVC tmp; - if (frame_idx) { - key = ref[(left + right) / 2].frame_idx; - partition(ref, frame_idx, key, ascending); + if (pic_order_cnt) { + key = ref[(left + right) / 2].pic_order_cnt; + partition(ref, pic_order_cnt, key, ascending); } else { - key = ref[(left + right) / 2].TopFieldOrderCnt; - partition(ref, TopFieldOrderCnt, (signed int)key, ascending); + key = ref[(left + right) / 2].pic_order_cnt; + partition(ref, pic_order_cnt, (signed int)key, ascending); } /* recursion */ if (left < j) - sort_one(ref, left, j, ascending, frame_idx); + sort_one(ref, left, j, ascending, pic_order_cnt); if (i < right) - sort_one(ref, i, right, ascending, frame_idx); + sort_one(ref, i, right, ascending, pic_order_cnt); } -static void sort_two(VAPictureH264 ref[], int left, int right, unsigned int key, unsigned int frame_idx, +static void sort_two(VAPictureHEVC ref[], int left, int right, unsigned int key, unsigned int pic_order_cnt, int partition_ascending, int list0_ascending, int list1_ascending) { int i = left, j = right; - VAPictureH264 tmp; + VAPictureHEVC tmp; - if (frame_idx) { - partition(ref, frame_idx, key, partition_ascending); + if (pic_order_cnt) { + partition(ref, pic_order_cnt, key, partition_ascending); } else { - partition(ref, TopFieldOrderCnt, (signed int)key, partition_ascending); + partition(ref, pic_order_cnt, (signed int)key, partition_ascending); } - sort_one(ref, left, i-1, list0_ascending, frame_idx); - sort_one(ref, j+1, right, list1_ascending, frame_idx); + sort_one(ref, left, i-1, list0_ascending, pic_order_cnt); + sort_one(ref, j+1, right, list1_ascending, pic_order_cnt); } static int update_ReferenceFrames(void) @@ -512,7 +668,7 @@ static int update_ReferenceFrames(void) if (current_frame_type == FRAME_B) return 0; - CurrentCurrPic.flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; + CurrentCurrPic.flags = 0;//VA_PICTURE_HEVC_LONG_TERM_REFERENCE; numShortTerm++; if (numShortTerm > num_ref_frames) numShortTerm = num_ref_frames; @@ -531,68 +687,80 @@ static int update_ReferenceFrames(void) static int update_RefPicList(void) { - unsigned int current_poc = CurrentCurrPic.TopFieldOrderCnt; - + unsigned int current_poc = CurrentCurrPic.pic_order_cnt; + int i = 0; + + /* Init reference frame list */ + for (i = 0; i < 15; i++) { + RefPicList0_P[i].picture_id = VA_INVALID_SURFACE; + RefPicList0_P[i].flags = VA_PICTURE_HEVC_INVALID; + RefPicList0_B[i].picture_id = VA_INVALID_SURFACE; + RefPicList0_B[i].flags = VA_PICTURE_HEVC_INVALID; + RefPicList1_B[i].picture_id = VA_INVALID_SURFACE; + RefPicList1_B[i].flags = VA_PICTURE_HEVC_INVALID; + } + if (current_frame_type == FRAME_P) { - memcpy(RefPicList0_P, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); + memcpy(RefPicList0_P, ReferenceFrames, numShortTerm * sizeof(VAPictureHEVC)); sort_one(RefPicList0_P, 0, numShortTerm-1, 0, 1); } if (current_frame_type == FRAME_B) { - memcpy(RefPicList0_B, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); - sort_two(RefPicList0_B, 0, numShortTerm-1, current_poc, 0, - 1, 0, 1); + memcpy(RefPicList0_B, ReferenceFrames, numShortTerm * sizeof(VAPictureHEVC)); + sort_two(RefPicList0_B, 0, numShortTerm-1, current_poc, 0, 1, 0, 1); - memcpy(RefPicList1_B, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); - sort_two(RefPicList1_B, 0, numShortTerm-1, current_poc, 0, - 0, 1, 0); + memcpy(RefPicList1_B, ReferenceFrames, numShortTerm * sizeof(VAPictureHEVC)); + sort_two(RefPicList1_B, 0, numShortTerm-1, current_poc, 0, 0, 1, 0); } - + return 0; } -static int render_sequence(rc_param_t *rc_param) +static int render_sequence(struct rc_param_t *rc_param) { VABufferID seq_param_buf, rc_param_buf, misc_param_tmpbuf, render_id[2]; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterRateControl *misc_rate_ctrl; - seq_param.general_profile_idc = 1 /* 1: main profile 2: main 10 profile*/; - seq_param.general_level_idc = 3 * 30 /* level 3 */ + seq_param.general_profile_idc = 1; /* 1: main profile 2: main 10 profile*/ + seq_param.general_level_idc = 51; /* level 3 */ seq_param.general_tier_flag = 0; seq_param.intra_period = intra_period; - seq_param.intra_idr_period = (intra_period == 0) ? 0 : (intra_idr_period / intra_period); - seq_param.ip_period = 1; + seq_param.intra_idr_period = intra_idr_period; //(intra_period == 0) ? 0 : (intra_idr_period / intra_period); + seq_param.ip_period = ip_period; //1; seq_param.bits_per_second = rc_param->bits_per_second; - - seq_param.picture_width_in_min_cu_minus1 = frame_width_mbaligned / 8; - seq_param.picture_height_in_min_cu_minus1 = frame_height_mbaligned / 8; - seq_param.seq_fields.chroma_format_idc = 1; /* 420 */ - seq_param.seq_fields.separate_colour_plane_flag = 0; - //seq_param.seq_fields.bit_depth_luma_minus8 = 0; - //seq_param.seq_fields.bit_depth_chroma_minus8 = 0; + seq_param.seq_fields.bits.chroma_format_idc = 1; /* 420 */ seq_param.log2_min_luma_coding_block_size_minus3 = 0; //min CU = 8; - seq_param.log2_max_luma_coding_block_size_minus3 = 3;//max CU = 64; + seq_param.log2_diff_max_min_luma_coding_block_size = 2; seq_param.log2_min_transform_block_size_minus2 = 0; - seq_param.log2_max_transform_block_size_minus2 = 3; - - seq_param.max_num_ref_frames = num_ref_frames; - seq_param.seq_fields.bits.frame_mbs_only_flag = 1; - seq_param.vui_time_scale = frame_rate * 2; - seq_param.vui_num_units_in_tick = 2; /* Tc = num_units_in_tick / time_sacle */ - - if (frame_width != frame_width_mbaligned || - frame_height != frame_height_mbaligned) { - seq_param.frame_cropping_flag = 1; - seq_param.frame_crop_left_offset = 0; - seq_param.frame_crop_right_offset = (frame_width_mbaligned - frame_width)/2; - seq_param.frame_crop_top_offset = 0; - seq_param.frame_crop_bottom_offset = (frame_height_mbaligned - frame_height)/2; - } + seq_param.log2_diff_max_min_transform_block_size = 3; + seq_param.max_transform_hierarchy_depth_inter = 2; + seq_param.max_transform_hierarchy_depth_intra= 2; + + seq_param.pic_width_in_luma_samples = ALIGN(frame_width, 16); //frame_width_mbaligned; + seq_param.pic_height_in_luma_samples = ALIGN(frame_height, 16); //frame_height_mbaligned; + seq_param.seq_fields.bits.separate_colour_plane_flag = 0; + seq_param.seq_fields.bits.bit_depth_luma_minus8 = 0; + seq_param.seq_fields.bits.bit_depth_chroma_minus8 = 0; + seq_param.seq_fields.bits.scaling_list_enabled_flag = 0; + seq_param.seq_fields.bits.strong_intra_smoothing_enabled_flag = 0; + seq_param.seq_fields.bits.amp_enabled_flag = 1; + seq_param.seq_fields.bits.sample_adaptive_offset_enabled_flag = 0; + seq_param.seq_fields.bits.pcm_enabled_flag = 0; + seq_param.seq_fields.bits.pcm_loop_filter_disabled_flag = 1; + seq_param.seq_fields.bits.sps_temporal_mvp_enabled_flag = 1; + seq_param.pcm_sample_bit_depth_luma_minus1 = 7; + seq_param.pcm_sample_bit_depth_chroma_minus1 = 7; + seq_param.log2_min_pcm_luma_coding_block_size_minus3 = 0; + seq_param.log2_max_pcm_luma_coding_block_size_minus3 = 0; + + seq_param.vui_time_scale = 0; + seq_param.vui_num_units_in_tick = 0; /* Tc = num_units_in_tick / time_sacle */ + va_status = vaCreateBuffer(va_dpy, context_id, VAEncSequenceParameterBufferType, sizeof(seq_param),1,&seq_param,&seq_param_buf); @@ -600,20 +768,6 @@ static int render_sequence(rc_param_t *rc_param) va_status = vaRenderPicture(va_dpy,context_id, &seq_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; - - if (misc_priv_type != 0) { - va_status = vaCreateBuffer(va_dpy, context_id, - VAEncMiscParameterBufferType, - sizeof(VAEncMiscParameterBuffer), - 1, NULL, &misc_param_tmpbuf); - CHECK_VASTATUS(va_status,"vaCreateBuffer"); - vaMapBuffer(va_dpy, misc_param_tmpbuf,(void **)&misc_param_tmp); - misc_param_tmp->type = misc_priv_type; - misc_param_tmp->data[0] = misc_priv_value; - vaUnmapBuffer(va_dpy, misc_param_tmpbuf); - - va_status = vaRenderPicture(va_dpy,context_id, &misc_param_tmpbuf, 1); - } return va_status; } @@ -638,7 +792,9 @@ static int render_framerate() misc_param->type = VAEncMiscParameterTypeFrameRate; misc_frame_rate = (VAEncMiscParameterFrameRate *)misc_param->data; - misc_frame_rate->framerate = frame_rate; + /* If framerate=30, the coded data is very big. */ + /* Compare with mv_encode, which pass 3000 here */ + misc_frame_rate->framerate = frame_rate * 100; vaUnmapBuffer(va_dpy, frame_rate_param_buf); @@ -674,7 +830,7 @@ static int render_rcparam(unsigned int mask, struct rc_param_t *rc_param) if (mask & RC_MASK_target_percentage) misc_rate_ctrl->target_percentage = rc_param->target_percentage; else - misc_rate_ctrl->target_percentage = 66; + misc_rate_ctrl->target_percentage = 95; if (mask & RC_MASK_window_size) misc_rate_ctrl->window_size = rc_param->window_size; @@ -684,7 +840,7 @@ static int render_rcparam(unsigned int mask, struct rc_param_t *rc_param) if (mask & RC_MASK_initial_qp) misc_rate_ctrl->initial_qp = rc_param->initial_qp; else - misc_rate_ctrl->initial_qp = initial_qp; + misc_rate_ctrl->initial_qp = 28; // 28 for HEVC if (mask & RC_MASK_min_qp) misc_rate_ctrl->min_qp = rc_param->min_qp; @@ -706,6 +862,79 @@ static int render_rcparam(unsigned int mask, struct rc_param_t *rc_param) return 0; } +static int render_roi(void) +{ + VAStatus va_status; + VABufferID misc_roi_buf_id = VA_INVALID_ID; + VAEncMiscParameterBuffer *misc_param; + VAEncMiscParameterBufferROI *misc_roi_param; + VAEncROI encroi; + + roi_rec_x = (!roi_rec_x)?frame_width / 3:roi_rec_x; + roi_rec_y = (!roi_rec_x)?frame_height / 3:roi_rec_y; + roi_rec_w = (!roi_rec_w)?frame_width / 3:roi_rec_w; + roi_rec_h = (!roi_rec_h)?frame_height / 3:roi_rec_h; + + va_status = vaCreateBuffer(va_dpy, context_id, + VAEncMiscParameterBufferType, + sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterBufferROI), + 1, + NULL, + &misc_roi_buf_id); + CHECK_VASTATUS(va_status, "vaCreateBuffer"); + + vaMapBuffer(va_dpy, + misc_roi_buf_id, + (void **)&misc_param); + + misc_param->type = VAEncMiscParameterTypeROI; + misc_roi_param = (VAEncMiscParameterBufferROI *)misc_param->data; + + misc_roi_param->num_roi = 1; + misc_roi_param->max_delta_qp = roi_maxqp; + misc_roi_param->min_delta_qp = roi_minqp; + + encroi.roi_rectangle.x = roi_rec_x; + encroi.roi_rectangle.y = roi_rec_y; + encroi.roi_rectangle.width = roi_rec_w; + encroi.roi_rectangle.height = roi_rec_h; + + encroi.roi_value = roi_value; + + misc_roi_param->roi = &encroi; + + vaUnmapBuffer(va_dpy, misc_roi_buf_id); + + va_status = vaRenderPicture(va_dpy, context_id, &misc_roi_buf_id, 1); + CHECK_VASTATUS(va_status,"vaRenderPicture"); + + if (buf_destroy) + destroy_vabuffers(va_dpy, 1, misc_roi_buf_id); + + return va_status; +} + +static int render_qualitylevel(void) +{ + VAStatus va_status; + VABufferID misc_param_tmpbuf; + VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; + VAEncMiscParameterBufferQualityLevel *misc_quality_param; + + va_status = vaCreateBuffer(va_dpy, context_id, + VAEncMiscParameterBufferType, + sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterBufferQualityLevel), + 1, NULL, &misc_param_tmpbuf); + CHECK_VASTATUS(va_status,"vaCreateBuffer"); + vaMapBuffer(va_dpy, misc_param_tmpbuf,(void **)&misc_param_tmp); + misc_param_tmp->type = VAEncMiscParameterTypeQualityLevel; + misc_quality_param = (VAEncMiscParameterBufferQualityLevel *)misc_param_tmp->data; + misc_quality_param->quality_level = misc_tu_value; + vaUnmapBuffer(va_dpy, misc_param_tmpbuf); + va_status = vaRenderPicture(va_dpy,context_id, &misc_param_tmpbuf, 1); + + return va_status; +} static int calc_poc(int pic_order_cnt_lsb) { @@ -739,62 +968,53 @@ static int calc_poc(int pic_order_cnt_lsb) return TopFieldOrderCnt; } -static unsigned char get_va_frame_type(int frame_type) { - switch (frame_type) { - case FRAME_IDR: - case FRAME_I: - return 1; - case FRAME_P: - return 2; - case FRAME_B: - return 3; - default: - fprintf(stderr, "%s Invalid frame type:%d\n", __FUNCTION__, frame_type); - return 1; -} - static int render_picture(void) { VABufferID pic_param_buf; VAStatus va_status; int i = 0; - pic_param.CurrPic.picture_id = ref_surface[current_slot]; - pic_param.CurrPic.flags = 0; - pic_param.CurrPic.PicOrderCnt = calc_poc((current_frame_display - current_IDR_display) % MaxPicOrderCntLsb); - CurrentCurrPic = pic_param.CurrPic; + pic_param.decoded_curr_pic.picture_id = ref_surface[current_slot]; + pic_param.decoded_curr_pic.pic_order_cnt = current_frame_num; + pic_param.decoded_curr_pic.flags = 0; + + CurrentCurrPic = pic_param.decoded_curr_pic; if (getenv("TO_DEL")) { /* set RefPicList into ReferenceFrames */ update_RefPicList(); /* calc RefPicList */ - memset(pic_param.ReferenceFrames, 0xff, 16 * sizeof(VAPictureH264)); /* invalid all */ + memset(pic_param.reference_frames, 0xff, 15 * sizeof(VAPictureHEVC)); /* invalid all */ if (current_frame_type == FRAME_P) { - pic_param.ReferenceFrames[0] = RefPicList0_P[0]; + pic_param.reference_frames[0] = RefPicList0_P[0]; } else if (current_frame_type == FRAME_B) { - pic_param.ReferenceFrames[0] = RefPicList0_B[0]; - pic_param.ReferenceFrames[1] = RefPicList1_B[0]; + pic_param.reference_frames[0] = RefPicList0_B[0]; + pic_param.reference_frames[1] = RefPicList1_B[0]; } } else { if (hevc_autoref == 0) { - memcpy(pic_param.ReferenceFrames, ReferenceFrames, numShortTerm*sizeof(VAPictureH264)); - for (i = numShortTerm; i < surface_num; i++) { - pic_param.ReferenceFrames[i].picture_id = VA_INVALID_SURFACE; - pic_param.ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; + memcpy(pic_param.reference_frames, ReferenceFrames, numShortTerm*sizeof(VAPictureHEVC)); + for (i = numShortTerm; i < 15; i++) { + pic_param.reference_frames[i].picture_id = VA_INVALID_SURFACE; + pic_param.reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; } } else { - for (i=0; i<surface_num; i++) { - pic_param.ReferenceFrames[i].picture_id = ref_surface[i]; - pic_param.ReferenceFrames[i].flags = 0; + for (i = 0; i < 15; i++) { + pic_param.reference_frames[i].picture_id = ref_surface[i]; + pic_param.reference_frames[i].flags = 0;//VA_PICTURE_HEVC_LONG_TERM_REFERENCE; } } } - + + unsigned char frame_type = get_va_frame_type(current_frame_type); + unsigned char coding_type = (frame_type == FRAME_IDR)? SLICE_TYPE_I : current_frame_type; + pic_param.pic_fields.bits.cu_qp_delta_enabled_flag = 1; + pic_param.pic_fields.bits.screen_content_flag = 1; + pic_param.pic_init_qp = 28; + pic_param.last_picture = (current_frame_encoding == frame_count); + pic_param.pic_fields.bits.reference_pic_flag = (current_frame_type != FRAME_B); + pic_param.pic_fields.bits.coding_type = coding_type; pic_param.pic_fields.bits.idr_pic_flag = (current_frame_type == FRAME_IDR); pic_param.pic_fields.bits.reference_pic_flag = (current_frame_type != FRAME_B); - pic_param.pic_fields.bits.transform_8x8_mode_flag = hevc_8x8_dct; pic_param.coded_buf = coded_buf[current_slot]; - pic_param.last_picture = (current_frame_encoding == frame_count); - pic_param.pic_init_qp = initial_qp; - pic_param.coding_type = get_va_frame_type(current_frame_type); va_status = vaCreateBuffer(va_dpy, context_id,VAEncPictureParameterBufferType, sizeof(pic_param),1,&pic_param, &pic_param_buf); @@ -881,6 +1101,81 @@ static int render_packedpicture(void) return 0; } +static int render_packedslice(void) +{ + VAEncPackedHeaderParameterBuffer packedheader_param_buffer; + VABufferID packedslc_para_bufid, packedslc_data_bufid, render_id[2]; + unsigned int length_in_bits; + unsigned char *packedslc_buffer = NULL; + VAStatus va_status; + + length_in_bits = build_packed_slice_buffer(&packedslc_buffer); + packedheader_param_buffer.type = VAEncPackedHeaderSlice; + packedheader_param_buffer.bit_length = length_in_bits; + packedheader_param_buffer.has_emulation_bytes = 0; + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderParameterBufferType, + sizeof(packedheader_param_buffer), 1, &packedheader_param_buffer, + &packedslc_para_bufid); + CHECK_VASTATUS(va_status,"vaCreateBuffer"); + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderDataBufferType, + (length_in_bits + 7) / 8, 1, packedslc_buffer, + &packedslc_data_bufid); + CHECK_VASTATUS(va_status,"vaCreateBuffer"); + + render_id[0] = packedslc_para_bufid; + render_id[1] = packedslc_data_bufid; + va_status = vaRenderPicture(va_dpy,context_id, render_id, 2); + CHECK_VASTATUS(va_status,"vaRenderPicture"); + + free(packedslc_buffer); + + return 0; +} + +static int render_packedvps(void) +{ + VAEncPackedHeaderParameterBuffer packedheader_param_buffer; + VABufferID packedvps_para_bufid, packedvps_data_bufid, render_id[2]; + unsigned int length_in_bits; + unsigned char *packedvps_buffer = NULL; + VAStatus va_status; + + length_in_bits = build_packed_vps_buffer(&packedvps_buffer); + packedheader_param_buffer.type = VAEncPackedHeaderSequence; + packedheader_param_buffer.bit_length = length_in_bits; + packedheader_param_buffer.has_emulation_bytes = 0; + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderParameterBufferType, + sizeof(packedheader_param_buffer), 1, &packedheader_param_buffer, + &packedvps_para_bufid); + CHECK_VASTATUS(va_status,"vaCreateBuffer"); + + va_status = vaCreateBuffer(va_dpy, + context_id, + VAEncPackedHeaderDataBufferType, + (length_in_bits + 7) / 8, 1, packedvps_buffer, + &packedvps_data_bufid); + CHECK_VASTATUS(va_status,"vaCreateBuffer"); + + render_id[0] = packedvps_para_bufid; + render_id[1] = packedvps_data_bufid; + va_status = vaRenderPicture(va_dpy,context_id, render_id, 2); + CHECK_VASTATUS(va_status,"vaRenderPicture"); + + free(packedvps_buffer); + + return 0; +} + + static void render_packedsei(void) { VAEncPackedHeaderParameterBuffer packed_header_param_buffer; @@ -912,7 +1207,7 @@ static void render_packedsei(void) &packed_sei_buffer); //offset_in_bytes = 0; - packed_header_param_buffer.type = VAEncPackedHeaderH264_SEI; + packed_header_param_buffer.type = VAEncPackedHeaderHEVC_SEI; packed_header_param_buffer.bit_length = length_in_bits; packed_header_param_buffer.has_emulation_bytes = 0; @@ -1031,10 +1326,10 @@ static int render_hrd(void) misc_hrd_param->initial_buffer_fullness = misc_hrd_param->buffer_size * 0.875; } else { if (windows_size != 0) { - misc_hrd_param->buffer_size = (uint32_t)((bits_size * (uint64_t)windows_size) / 1000); + misc_hrd_param->buffer_size = 0; //(uint32_t)((bits_size * (uint64_t)windows_size) / 1000); } else misc_hrd_param->buffer_size = frame_bitrate; - misc_hrd_param->initial_buffer_fullness = misc_hrd_param->buffer_size * 0.875; + misc_hrd_param->initial_buffer_fullness = 0; //misc_hrd_param->buffer_size * 0.875; } vaUnmapBuffer(va_dpy, misc_parameter_hrd_buf_id); @@ -1047,73 +1342,88 @@ static int render_hrd(void) static int render_slice(void) { - VABufferID slice_param_buf; + VABufferID slice_param_buf_id = VA_INVALID_ID; VAStatus va_status; - VAEncSliceParameterBufferH264 *slice_param, *current_slice; + VAEncSliceParameterBufferHEVC *slice_param, *current_slice; int i, j, frame_slice_cc = frame_slice_count; int mb_rendered = 0; + slc_param.slice_beta_offset_div2 = 2; + slc_param.slice_fields.bits.slice_temporal_mvp_enabled_flag = 1; + slc_param.slice_fields.bits.collocated_from_l0_flag = 1; + slc_param.max_num_merge_cand = 5; + va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType, - sizeof(VAEncSliceParameterBufferH264), frame_slice_count, NULL, &slice_param_buf); + sizeof(VAEncSliceParameterBufferHEVC), frame_slice_count, &slc_param, &slice_param_buf_id); CHECK_VASTATUS(va_status,"vaCreateBuffer"); - va_status = vaMapBuffer(va_dpy, slice_param_buf, + va_status = vaMapBuffer(va_dpy, slice_param_buf_id, (void **)&slice_param); CHECK_VASTATUS(va_status,"vaMapBuffer"); - memset((void *)slice_param, 0, sizeof(VAEncSliceParameterBufferH264) * frame_slice_count); - + update_RefPicList(); for (j = 0; j < frame_slice_cc; j++) { current_slice = slice_param + j; - current_slice->disable_deblocking_filter_idc = 1; - current_slice->macroblock_address = mb_rendered; + current_slice->slice_segment_address = mb_rendered; if (j == frame_slice_cc - 1) { - current_slice->num_macroblocks = (frame_width_mbaligned * frame_height_mbaligned) / (16 * 16) - mb_rendered; + // current_slice->num_ctu_in_slice = GET_CTU_NUM(frame_width_mbaligned, 32) * GET_CTU_NUM(frame_height_mbaligned, 32) - mb_rendered; + current_slice->num_ctu_in_slice = (frame_width_mbaligned * frame_height_mbaligned) / (32 * 32) - mb_rendered; } else { - current_slice->num_macroblocks = (frame_width_mbaligned * frame_slice_height) / (16 * 16); - mb_rendered += current_slice->num_macroblocks; + //current_slice->num_ctu_in_slice = GET_CTU_NUM(frame_width_mbaligned, 32) * GET_CTU_NUM(frame_height_mbaligned, 32); + current_slice->num_ctu_in_slice = (frame_width_mbaligned * frame_slice_height) / (32 * 32); + mb_rendered += current_slice->num_ctu_in_slice; } - current_slice->slice_type = (current_frame_type == FRAME_IDR)? 2 : current_frame_type; - if (current_frame_type == FRAME_IDR) { - if (current_frame_encoding != 0) - ++current_slice->idr_pic_id; + + current_slice->slice_type = (current_frame_type == FRAME_IDR)? SLICE_TYPE_I : current_frame_type; + if ((current_frame_type == FRAME_IDR) || (current_frame_type == FRAME_I)) { + /* Reset reference for IDR also */ + for (i = 0; i < 15; i++) { + current_slice->ref_pic_list0[i].picture_id = VA_INVALID_SURFACE; + current_slice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; + current_slice->ref_pic_list1[i].picture_id = VA_INVALID_SURFACE; + current_slice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; + } } else if (current_frame_type == FRAME_P) { int refpiclist0_max = hevc_maxref & 0xffff; - memcpy(current_slice->RefPicList0, RefPicList0_P, refpiclist0_max*sizeof(VAPictureH264)); + //printf("refpiclist0_max %d\n", refpiclist0_max); + memcpy(current_slice->ref_pic_list0, RefPicList0_P, refpiclist0_max*sizeof(VAPictureHEVC)); - for (i = refpiclist0_max; i < 32; i++) { - current_slice->RefPicList0[i].picture_id = VA_INVALID_SURFACE; - current_slice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID; + for (i = refpiclist0_max; i < 15; i++) { + current_slice->ref_pic_list0[i].picture_id = VA_INVALID_SURFACE; + current_slice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; + } + + for (i = 0; i < 15; i++) { + current_slice->ref_pic_list1[i].picture_id = VA_INVALID_SURFACE; + current_slice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; } } else if (current_frame_type == FRAME_B) { int refpiclist0_max = hevc_maxref & 0xffff; int refpiclist1_max = (hevc_maxref >> 16) & 0xffff; - memcpy(current_slice->RefPicList0, RefPicList0_B, refpiclist0_max*sizeof(VAPictureH264)); - for (i = refpiclist0_max; i < 32; i++) { - current_slice->RefPicList0[i].picture_id = VA_INVALID_SURFACE; - current_slice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID; + memcpy(current_slice->ref_pic_list0, RefPicList0_B, refpiclist0_max*sizeof(VAPictureHEVC)); + for (i = refpiclist0_max; i < 15; i++) { + current_slice->ref_pic_list0[i].picture_id = VA_INVALID_SURFACE; + current_slice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; } - memcpy(current_slice->RefPicList1, RefPicList1_B, refpiclist1_max*sizeof(VAPictureH264)); - for (i = refpiclist1_max; i < 32; i++) { - current_slice->RefPicList1[i].picture_id = VA_INVALID_SURFACE; - current_slice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID; + memcpy(current_slice->ref_pic_list1, RefPicList1_B, refpiclist1_max*sizeof(VAPictureHEVC)); + for (i = refpiclist1_max; i < 15; i++) { + current_slice->ref_pic_list1[i].picture_id = VA_INVALID_SURFACE; + current_slice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; } } - current_slice->slice_alpha_c0_offset_div2 = 0; current_slice->slice_beta_offset_div2 = 0; - current_slice->direct_spatial_mv_pred_flag = 1; - current_slice->pic_order_cnt_lsb = (current_frame_display - current_IDR_display) % MaxPicOrderCntLsb; } - va_status = vaUnmapBuffer(va_dpy, slice_param_buf); + va_status = vaUnmapBuffer(va_dpy, slice_param_buf_id); CHECK_VASTATUS(va_status,"vaUnmapBuffer"); - va_status = vaRenderPicture(va_dpy, context_id, &slice_param_buf, 1); + va_status = vaRenderPicture(va_dpy, context_id, &slice_param_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture"); + return 0; } @@ -1159,15 +1469,20 @@ static VAStatus hevc_render_frame(unsigned int mask, struct rc_param_t *rc_param numShortTerm = 0; current_frame_num = 0; current_IDR_display = current_frame_display; + frame_poc = 0; } if (current_frame_type == FRAME_IDR) { - render_framerate(); - render_sequence(rc_param); - render_picture(); if (hevc_packedheader) { + render_packedvps(); render_packedsequence(); render_packedpicture(); } + render_sequence(rc_param); + render_picture(); + render_hrd(); + render_rcparam(mask, rc_param); + render_framerate(); + render_qualitylevel(); if (rc_mode == VA_RC_CBR) { //render_packedsei(); render_hrd(); @@ -1181,20 +1496,23 @@ static VAStatus hevc_render_frame(unsigned int mask, struct rc_param_t *rc_param if (max_slice_size) { render_max_slice_size(); } + if (roi_enable) + render_roi(); } else { - //render_sequence(); + render_packedpicture(); + //render_sequence(rc_param); render_picture(); - //if (rc_mode == VA_RC_CBR) - // render_packedsei(); - //render_hrd(); + if (roi_enable) + render_roi(); } if (mask) render_rcparam(mask, rc_param); + render_packedslice(); render_slice(); - - update_ReferenceFrames(); - + + update_ReferenceFrames(); + return VA_STATUS_SUCCESS; } @@ -1207,14 +1525,15 @@ static VAStatus hevc_get_config(void) int support_encode = 0; VAStatus va_status; unsigned int i; + unsigned int rc_value = 0; if (va_profile_str) { if (strncmp(va_profile_str, "MP", 2) == 0) hevc_profile = VAProfileHEVCMain; - else if (strncmp(va_profile_str, "MP10", 2) == 0) + else if (strncmp(va_profile_str, "MP10", 4) == 0) hevc_profile = VAProfileHEVCMain10; } - + /* use the highest profile */ for (i = 0; i < sizeof(profile_list)/sizeof(profile_list[0]); i++) { if ((hevc_profile != -1) && hevc_profile != profile_list[i]) @@ -1223,7 +1542,8 @@ static VAStatus hevc_get_config(void) hevc_profile = profile_list[i]; vaQueryConfigEntrypoints(va_dpy, hevc_profile, entrypoints, &num_entrypoints); for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) { - if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice) { + printf("entrypoint support %d\n", entrypoints[slice_entrypoint]); + if (entrypoints[slice_entrypoint] == va_entrypoint) { support_encode = 1; break; } @@ -1296,12 +1616,39 @@ static VAStatus hevc_get_config(void) printf("Desired rc mode %s is not supported, exit\n", rc_to_string(rc_mode)); exit(1); } - + config_attrib[config_attrib_num].type = VAConfigAttribRateControl; - config_attrib[config_attrib_num].value = rc_mode; + if (rc_mode == VA_RC_CBR || rc_mode == VA_RC_VBR) + rc_value = VA_RC_MB | rc_mode; + else + rc_value = rc_mode; + config_attrib[config_attrib_num].value = rc_value; //rc_mode; config_attrib_num++; } + if (hevc_attrib[VAConfigAttribEncMaxSlices].value != VA_ATTRIB_NOT_SUPPORTED) { + printf("Support %d slices\n", hevc_attrib[VAConfigAttribEncMaxSlices].value); + config_attrib[config_attrib_num].type = VAConfigAttribEncMaxSlices; + config_attrib[config_attrib_num].value = 256; + config_attrib_num++; + } + + if (hevc_attrib[VAConfigAttribEncSliceStructure].value != VA_ATTRIB_NOT_SUPPORTED) { + int tmp = hevc_attrib[VAConfigAttribEncSliceStructure].value; + + printf("Support VAConfigAttribEncSliceStructure\n"); + config_attrib[config_attrib_num].type = VAConfigAttribEncSliceStructure; + config_attrib[config_attrib_num].value = VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS; + config_attrib_num++; +#if 0 + if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS) + printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS\n"); + if (tmp & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) + printf("Support VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS\n"); + if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) + printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS\n"); +#endif + } if (hevc_attrib[VAConfigAttribEncPackedHeaders].value != VA_ATTRIB_NOT_SUPPORTED) { int tmp = hevc_attrib[VAConfigAttribEncPackedHeaders].value; @@ -1359,32 +1706,40 @@ static VAStatus hevc_get_config(void) printf("Support %d RefPicList0 and %d RefPicList1\n", hevc_maxref & 0xffff, (hevc_maxref >> 16) & 0xffff ); + config_attrib[config_attrib_num].type = VAConfigAttribEncMaxRefFrames; + config_attrib[config_attrib_num].value = hevc_maxref; + config_attrib_num++; } - if (hevc_attrib[VAConfigAttribEncMaxSlices].value != VA_ATTRIB_NOT_SUPPORTED) - printf("Support %d slices\n", hevc_attrib[VAConfigAttribEncMaxSlices].value); - - if (hevc_attrib[VAConfigAttribEncSliceStructure].value != VA_ATTRIB_NOT_SUPPORTED) { - int tmp = hevc_attrib[VAConfigAttribEncSliceStructure].value; - - printf("Support VAConfigAttribEncSliceStructure\n"); + if (hevc_attrib[VAConfigAttribEncQualityRange].value != VA_ATTRIB_NOT_SUPPORTED) { + printf("Support VAConfigAttribEncQualityRange\n"); + config_attrib[config_attrib_num].type = VAConfigAttribEncQualityRange; + config_attrib[config_attrib_num].value = 7; + config_attrib_num++; + } - if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS) - printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS\n"); - if (tmp & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) - printf("Support VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS\n"); - if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) - printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS\n"); + if (hevc_attrib[VAConfigAttribEncIntraRefresh].value != VA_ATTRIB_NOT_SUPPORTED) { + printf("Support VAConfigAttribEncIntraRefresh\n"); + config_attrib[config_attrib_num].type = VAConfigAttribEncIntraRefresh; + config_attrib_num++; } - if (hevc_attrib[VAConfigAttribEncMacroblockInfo].value != VA_ATTRIB_NOT_SUPPORTED) { - printf("Support VAConfigAttribEncMacroblockInfo\n"); + if (hevc_attrib[VAConfigAttribEncROI].value != VA_ATTRIB_NOT_SUPPORTED) { + printf("Support VAConfigAttribEncROI\n"); + config_attrib[config_attrib_num].type = VAConfigAttribEncROI; + config_attrib_num++; + } + + if (hevc_attrib[VAConfigAttribEncFunctionTypeIntel].value != VA_ATTRIB_NOT_SUPPORTED) { + printf("Support VAConfigAttribEncFunctionTypeIntel\n"); + config_attrib[config_attrib_num].type = VAConfigAttribEncFunctionTypeIntel; + config_attrib_num++; } if (hevc_attrib[VAConfigAttribEncAutoReference].value != VA_ATTRIB_NOT_SUPPORTED) { printf("Support VAConfigAttribEncAutoReference\n"); hevc_autoref = 1; } - + va_profile = hevc_profile; va_entrypoint = VAEntrypointEncSlice; @@ -1412,6 +1767,7 @@ static int hevc_save_codeddata(FILE *coded_fp, VACodedBufferSegment *buf_list, while (p != NULL) { *rec_surfaceid = ref_surface[p->reserved]; + coded_size += fwrite(p->buf, 1, p->size, coded_fp); p = (VACodedBufferSegment *) p->next; } diff --git a/vaenc/va_encode.c b/vaenc/va_encode.c index 4fb4ae8..e5cadb7 100644 --- a/vaenc/va_encode.c +++ b/vaenc/va_encode.c @@ -316,7 +316,7 @@ static int print_help(void) { printf("./va_encode <options>\n"); printf(" -i : interactive mode, stop at every frame encoding\n"); - printf(" -t <H264|MPEG4|H263|JPEG|VP8>\n"); + printf(" -t <H264|MPEG4|H263|JPEG|VP8|HEVC>\n"); printf(" -w <width> -h <height>\n"); printf(" -framecount <frame number>\n"); printf(" -n <frame number>\n"); @@ -497,6 +497,8 @@ static int process_cmdline(int argc, char *argv[]) current_codec = &h264_codec; else if (!strncmp(optarg, "JPEG", 4)) current_codec = &jpeg_codec; + else if (!strncmp(optarg, "HEVC", 4)) + current_codec = &hevc_codec; else { print_help(); exit(0); @@ -667,6 +669,7 @@ static int process_cmdline(int argc, char *argv[]) riff_file = 0; break; case 37: + ivf_file = 0; riff_file = 1; frame_count = 1; break; @@ -911,6 +914,10 @@ static int process_cmdline(int argc, char *argv[]) if (current_codec != &vp8_codec) { frame_width_mbaligned = (frame_width + 15) & (~15); frame_height_mbaligned = (frame_height + 15) & (~15); + if (current_codec == &hevc_codec) { + frame_width_mbaligned = (frame_width + 31) & (~31); + frame_height_mbaligned = (frame_height + 31) & (~31); + } } else { frame_width_mbaligned = frame_width; frame_height_mbaligned = frame_height; @@ -1236,7 +1243,7 @@ static int save_codeddata(unsigned int display_order, unsigned int encode_order, if (coded_fp == NULL) printf("Open file %s error (%s)\n", fn, strerror(errno)); } - + if ((dump_frame == 0) && current_codec->save_codeddata) { coded_size = current_codec->save_codeddata(coded_fp, buf_list, rec_surfaceid); save_frame_size_log(encode_order, coded_size); diff --git a/vaenc/va_encode.h b/vaenc/va_encode.h index 0341692..02be4e7 100644 --- a/vaenc/va_encode.h +++ b/vaenc/va_encode.h @@ -311,4 +311,5 @@ extern struct codec_table_t mpeg4_codec; extern struct codec_table_t h263_codec; extern struct codec_table_t vp8_codec; extern struct codec_table_t jpeg_codec; +extern struct codec_table_t hevc_codec; static struct codec_table_t *current_codec = &h264_codec; diff --git a/vaenc/vp8encode.c b/vaenc/vp8encode.c index 068eccd..eb00548 100644 --- a/vaenc/vp8encode.c +++ b/vaenc/vp8encode.c @@ -184,6 +184,8 @@ static VAStatus render_picture(struct rc_param_t *rc_param, int num) pic_vp8.coded_buf = coded_buf[current_slot]; pic_vp8.pic_flags.value = 0; pic_vp8.pic_flags.bits.frame_type = (current_frame_type != FRAME_IDR); + if (riff_file) + pic_vp8.pic_flags.bits.show_frame = 1; #if 0 pic_vp8.pic_flags.bits.no_ref_arf = 1; pic_vp8.pic_flags.bits.no_ref_gf = 1; @@ -521,7 +523,7 @@ static VAStatus vp8_render_frame(unsigned int mask, struct rc_param_t *rc_param) render_framerate_param(mask, rc_param, i); render_rcparam(mask, rc_param, i); render_hrdparam(); - render_max_framesize_param(); + //render_max_framesize_param(); if (layer_num > 1) { render_layer_structure_param(); for (i = 0; i < layer_num; i++) { @@ -619,7 +621,7 @@ static int vp8_save_codeddata(FILE *coded_fp, VACodedBufferSegment *buf_list, riff_header[9] = 'E'; riff_header[10] = 'B'; riff_header[11] = 'P'; - mem_put_le32(riff_header+12, 0x20385056); // raw video format + mem_put_le32(riff_header+12, 0x20385056); // raw video format "VP8 " mem_put_le32(riff_header+16, frame_length); // frame_size coded_size += fwrite(riff_header, 1, 20, coded_fp); } @@ -628,7 +630,7 @@ static int vp8_save_codeddata(FILE *coded_fp, VACodedBufferSegment *buf_list, p = buf_list; if(p!=NULL) *rec_surfaceid = p->reserved; - + /* write the data */ while (p != NULL) { coded_size += fwrite(p->buf, 1, p->size, coded_fp); diff --git a/yuvtool/main.c b/yuvtool/main.c index 964d54f..1e7e3a7 100644 --- a/yuvtool/main.c +++ b/yuvtool/main.c @@ -47,6 +47,7 @@ #include <sys/shm.h> #include <sys/time.h> #include <assert.h> +#include <errno.h> #include <../utils/va_wrapper.h> #include <../utils/loadsurface_yuv.h> @@ -71,6 +72,7 @@ static int frame_rate=30,frame_num=1; static struct timeval tftarget; static int output_psnr_file = 0; static int rotate_degree = 90; +static int psnr_each_frame = 0; static int GetPortId(Display *dpy) { @@ -736,16 +738,18 @@ static int rotate_yuv(void) static int exit_with_help(void) { - printf("yuvtool <display|convert|psnr|ssim|create|rotate> <options>\n"); + printf("yuvtool <display|convert|psnr|ssim|create|rotate|md5> <options>\n"); printf(" for display, options is: -s <widthxheight> -i <input YUV file> -ifourcc <input fourcc> -path <output path>\n"); printf(" for create, options is: -s <widthxheight> -n <frame number> -i <input YUV file> -ifourcc <input fourcc>\n"); printf(" for convert, options is: -s <widthxheight> -i <input YUV file> -ifourcc <input fourcc>\n"); printf(" -o <output YUV file> -ofourcc <output fourcc>\n"); printf(" currently, support NV12<->I420/YV12 BMP->NV12 conversion\n"); - printf(" for psnr, options is: -s <widthxheight> -i <input YUV file> -o <output YUV file> -n <frame number>\n"); + printf(" for psnr, options is: -s <widthxheight> -i <input YUV file> -o <output YUV file> -n <frame number> -e\n"); printf(" The two files should be same with width same FOURCC and resolution\n"); + printf(" -e will calculate each frame psnr\n"); printf(" for ssim, options is: -s <widthxheight> -i <reference YUV file> -o <reconstructed YUV file> -n <frame number>\n"); - printf(" The two files should be same with width same FOURCC and resolution\n"); + printf(" for md5, options is: -s <widthxheight> -i <reference YUV file> -ifourcc <input fourcc>\n"); + printf(" Calculate the MD5 of each frame for static frame analyze\n"); printf(" for crc, options is:-s widthxheight -i <input YUV file>\n"); printf(" for scale, options is:-s widthxheight -i <input YUV file> -ifourcc <input fourcc> \n"); printf(" -S widthxheight -o <output YUV file>\n"); @@ -789,14 +793,32 @@ static int psnr_yuv(void) { double psnr = 0, mse = 0; double psnr_y, psnr_u, psnr_v; - + int i; + fprintf(stdout,"Calculate PSNR %s vs %s, (%dx%d, %d frames)\n", input_fn, output_fn, width, height, frame_num); - calc_PSNR(input_fp, output_fp, width, height, frame_num, - &psnr, &psnr_y, &psnr_u, &psnr_v, &mse); + + if (psnr_each_frame == 0) { + calc_PSNR(input_fp, output_fp, width, height, frame_num, + &psnr, &psnr_y, &psnr_u, &psnr_v, &mse); + + printf("PSNR: %.2f (Y=%.2f,U=%.2f, V=%.2f)\n", psnr, psnr_y, psnr_u, psnr_v); + return 0; + } + + + for (i=0; i<frame_num; i++) { + psnr_y = psnr_u = psnr_v = psnr = mse = 0; + calc_PSNR(input_fp, output_fp, width, height, 1, + &psnr, &psnr_y, &psnr_u, &psnr_v, &mse); + fseek(input_fp, width*height*1.5, SEEK_CUR); + fseek(output_fp, width*height*1.5, SEEK_CUR); + + printf("Frame %d: PSNR: %.2f (Y=%.2f,U=%.2f, V=%.2f)\n", i, psnr, psnr_y, psnr_u, psnr_v); - printf("PSNR: %.2f (Y=%.2f,U=%.2f, V=%.2f\n", psnr, psnr_y, psnr_u, psnr_v); + } + return 0; } @@ -816,6 +838,78 @@ static int ssim_yuv(void) } +static int md5_yuv(void) +{ + unsigned int frame_size = width * height * 1.5; + char tmp_template[32] = { 'm', 'd', '5', 'X','X','X','X','X','X' }; + char *tmp_fn, *one_frame, popen_cmd[64]; + FILE *tmp_fp; + int current_frame = 0; + + fprintf(stdout, "Calculate each frame MD5, (%dx%d, %d frames)\n", + width, height, frame_num); + + tmp_fn = mktemp(tmp_template); + tmp_fp = fopen(tmp_fn, "w+"); + if (tmp_fp == NULL) { + printf("Open temp file %s failed (%s)\n", tmp_fn, strerror(errno)); + exit(1); + } + + one_frame = malloc(frame_size); + if (one_frame == NULL) { + printf("malloc error %s, exit\n", strerror(errno)); + exit(1); + } + + sprintf(popen_cmd, "md5sum %s", tmp_fn); + while (frame_num-- > 0) { + char last_md5sum_output[256]; + char md5sum_output[256]; + + FILE *popen_fp; + int i; + + fread(one_frame, frame_size, 1, input_fp); + + rewind(tmp_fp); + fwrite(one_frame, frame_size, 1, tmp_fp); + fflush(tmp_fp); + fsync(fileno(tmp_fp)); + + popen_fp = popen(popen_cmd, "r"); + if (popen_fp == NULL) { + printf("Failed to md5sum command\n" ); + exit(1); + } + fgets(md5sum_output, sizeof(md5sum_output), popen_fp); + pclose(popen_fp); + + printf("Frame %d md5: ", current_frame); + + for (i=0; i<sizeof(md5sum_output); i++) { + if (md5sum_output[i] == ' ') + md5sum_output[i] = '\0'; + } + if ((current_frame > 0) && + (strcmp(md5sum_output, last_md5sum_output) == 0)) + printf("***identicle***"); + else + printf(md5sum_output); + + current_frame ++; + strcpy(last_md5sum_output, md5sum_output); + + printf("\n"); + } + + free(one_frame); + fclose(tmp_fp); + + return 0; +} + + static int scale_yuv(void) { int tmp=0,i=0; @@ -932,22 +1026,22 @@ static int YUV_Generator_Planar(int width, int height, unsigned char *Y_start, int Y_pitch, unsigned char *U_start, int U_pitch, unsigned char *V_start, int V_pitch, - int UV_interleave) + unsigned int fourcc) { static int row_shift = 0; int box_width = 8; - row_shift++; if (row_shift == 16) row_shift = 0; - V_start = U_start + 1; yuvgen_planar(width, height, Y_start, Y_pitch, U_start, U_pitch, V_start, V_pitch, - VA_FOURCC_NV12, box_width, row_shift, + fourcc, box_width, row_shift, 0); + row_shift++; + return 0; } @@ -969,7 +1063,7 @@ static int create_yuv(void) one_frame, width, one_frame + width*height, width/2, one_frame + width*height + (width/2)*(height/2), width/2, - 0); + ifourcc); fwrite(one_frame, width*height*1.5, 1, input_fp); } } else if ((ifourcc == VA_FOURCC_YV12)) { @@ -978,7 +1072,7 @@ static int create_yuv(void) one_frame, width, one_frame + width*height + (width/2)*(height/2), width/2, one_frame + width*height, width/2, - 0); + ifourcc); fwrite(one_frame, width*height*1.5, 1, input_fp); } } else if (ifourcc == VA_FOURCC_NV12) { @@ -987,7 +1081,7 @@ static int create_yuv(void) one_frame, width, one_frame + width*height, width, one_frame + width*height, width, - 1); + ifourcc); fwrite(one_frame, width*height*1.5, 1, input_fp); } } else { @@ -1007,7 +1101,8 @@ static enum { SSIM, CREATE, SCALE, - ROTATE + ROTATE, + MD5 } operation; @@ -1047,6 +1142,8 @@ int main(int argc, char **argv) operation = SCALE; else if (strcmp(argv[1],"rotate") == 0) operation = ROTATE; + else if (strcmp(argv[1],"md5") == 0) + operation = MD5; else { printf("ERROR:The first parameter isn't <scale|display|convert|psnr|create|crc>, exit\n"); exit_with_help(); @@ -1056,7 +1153,7 @@ int main(int argc, char **argv) argc--; argv++; - while ((c=getopt_long_only(argc,argv,"fn:s:S:i:d:o:h?",long_opts,&long_index)) != -1) { + while ((c=getopt_long_only(argc,argv,"fen:s:S:i:d:o:h?",long_opts,&long_index)) != -1) { switch (c) { case 'h': case '?': @@ -1066,6 +1163,9 @@ int main(int argc, char **argv) case 'f': output_psnr_file = 1; break; + case 'e': + psnr_each_frame = 1; + break; case 'n': input_frame_num = atoi(optarg); break; @@ -1188,6 +1288,7 @@ int main(int argc, char **argv) if (operation == ROTATE) rotate_yuv(); if (operation == PSNR) psnr_yuv(); if (operation == SSIM) ssim_yuv(); + if (operation == MD5) md5_yuv(); if (operation == CONVERT && ifourcc == VA_FOURCC_BMP24) bmp2yuv(input_fp, output_fp, ofourcc); else if (operation == CONVERT) |