diff options
author | Austin Yuan <shengquan.yuan@intel.com> | 2013-05-08 12:45:57 +0800 |
---|---|---|
committer | Xiang, Haihao <haihao.xiang@intel.com> | 2013-06-25 13:53:58 +0800 |
commit | 64f9de399187204d5c30cf205b4279ec5b002675 (patch) | |
tree | 28f04144fbc69f52b25f4487768331ca6b5ce7fd | |
parent | d5fe363232c4456498282c95f8ec08c67e63a903 (diff) |
h264encode: dump reconstructed frame and calc PSNR
Signed-off-by: Austin Yuan <shengquan.yuan@intel.com>
-rwxr-xr-x | test/encode/Android.mk | 2 | ||||
-rw-r--r-- | test/encode/Makefile.am | 2 | ||||
-rw-r--r-- | test/encode/h264encode.c | 314 | ||||
-rwxr-xr-x | test/loadsurface.h | 210 |
4 files changed, 405 insertions, 123 deletions
diff --git a/test/encode/Android.mk b/test/encode/Android.mk index e8305bc..430ffd9 100755 --- a/test/encode/Android.mk +++ b/test/encode/Android.mk @@ -21,7 +21,7 @@ LOCAL_C_INCLUDES += \ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := h264encode -LOCAL_SHARED_LIBRARIES := libva-android libva libdl libdrm libcutils libutils libgui +LOCAL_SHARED_LIBRARIES := libva-android libva libdl libdrm libcutils libutils libgui libm include $(BUILD_EXECUTABLE) diff --git a/test/encode/Makefile.am b/test/encode/Makefile.am index 0f9efac..8391f5b 100644 --- a/test/encode/Makefile.am +++ b/test/encode/Makefile.am @@ -33,7 +33,7 @@ h264encode_CFLAGS = -I$(top_srcdir)/test/common -g h264encode_LDADD = \ $(top_builddir)/va/libva.la \ $(top_builddir)/test/common/libva-display.la \ - -lpthread + -lpthread -lm avcenc_SOURCES = avcenc.c avcenc_CFLAGS = -I$(top_srcdir)/test/common -g diff --git a/test/encode/h264encode.c b/test/encode/h264encode.c index d02045c..8c6e008 100644 --- a/test/encode/h264encode.c +++ b/test/encode/h264encode.c @@ -30,9 +30,12 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> +#include <sys/mman.h> #include <fcntl.h> #include <assert.h> #include <pthread.h> +#include <errno.h> +#include <math.h> #include <va/va.h> #include <va/va_enc_h264.h> #include "va_display.h" @@ -69,7 +72,6 @@ #define BITSTREAM_ALLOCATE_STEPPING 4096 - #define SURFACE_NUM 16 /* 16 surfaces for source YUV */ #define SURFACE_NUM 16 /* 16 surfaces for reference */ static VADisplay va_dpy; @@ -102,6 +104,7 @@ static char *coded_fn = NULL, *srcyuv_fn = NULL, *recyuv_fn = NULL; static FILE *coded_fp = NULL, *srcyuv_fp = NULL, *recyuv_fp = NULL; static unsigned long long srcyuv_frames = 0; static int srcyuv_fourcc = VA_FOURCC_NV12; +static int calc_psnr = 0; static int frame_width = 176; static int frame_height = 144; @@ -120,10 +123,13 @@ static int rc_mode = VA_RC_VBR; static unsigned long long current_frame_encoding = 0; static unsigned long long current_frame_display = 0; static unsigned long long current_IDR_display = 0; -static int current_frame_num = 0; +static unsigned int current_frame_num = 0; static int current_frame_type; #define current_slot (current_frame_display % SURFACE_NUM) +#define MIN(a, b) ((a)>(b)?(b):(a)) +#define MAX(a, b) ((a)>(b)?(a):(b)) + /* thread to save coded data/upload source YUV */ struct storage_task_t { void *next; @@ -703,7 +709,9 @@ static int print_help(void) printf(" --rcmode <NONE|CBR|VBR|VCM|CQP|VBR_CONTRAINED>\n"); printf(" --syncmode: sequentially upload source, encoding, save result, no multi-thread\n"); printf(" --srcyuv <filename> load YUV from a file\n"); - printf(" --fourcc <NV12|IYUV|I420|YV12> source YUV fourcc\n"); + printf(" --fourcc <NV12|IYUV|YV12> source YUV fourcc\n"); + printf(" --recyuv <filename> save reconstructed YUV into a file\n"); + printf(" --enablePSNR calculate PSNR of recyuv vs. srcyuv\n"); return 0; } @@ -712,6 +720,7 @@ static int process_cmdline(int argc, char *argv[]) { char c; const struct option long_opts[] = { + {"help", no_argument, NULL, 0 }, {"bitrate", required_argument, NULL, 1 }, {"minqp", required_argument, NULL, 2 }, {"initialqp", required_argument, NULL, 3 }, @@ -720,8 +729,10 @@ static int process_cmdline(int argc, char *argv[]) {"ip_period", required_argument, NULL, 6 }, {"rcmode", required_argument, NULL, 7 }, {"srcyuv", required_argument, NULL, 9 }, - {"fourcc", required_argument, NULL, 10 }, - {"syncmode", no_argument, NULL, 11 }, + {"recyuv", required_argument, NULL, 10 }, + {"fourcc", required_argument, NULL, 11 }, + {"syncmode", no_argument, NULL, 12 }, + {"enablePSNR", no_argument, NULL, 13 }, {NULL, no_argument, NULL, 0 }}; int long_index; @@ -742,6 +753,9 @@ static int process_cmdline(int argc, char *argv[]) case 'o': coded_fn = strdup(optarg); break; + case 0: + print_help(); + exit(0); case 1: frame_bitrate = atoi(optarg); break; @@ -771,15 +785,21 @@ static int process_cmdline(int argc, char *argv[]) srcyuv_fn = strdup(optarg); break; case 10: + recyuv_fn = strdup(optarg); + break; + case 11: srcyuv_fourcc = string_to_fourcc(optarg); if (srcyuv_fourcc <= 0) { print_help(); exit(1); } break; - case 11: + case 12: encode_syncmode = 1; break; + case 13: + calc_psnr = 1; + break; case ':': case '?': print_help(); @@ -815,6 +835,14 @@ static int process_cmdline(int argc, char *argv[]) printf("Source YUV file %s with %llu frames\n", srcyuv_fn, srcyuv_frames); } } + + /* open source file */ + if (recyuv_fn) { + recyuv_fp = fopen(recyuv_fn,"w+"); + + if (recyuv_fp == NULL) + printf("Open reconstructed YUV file %s failed\n", recyuv_fn); + } if (coded_fn == NULL) { struct stat buf; @@ -919,7 +947,7 @@ static int init_va(void) if (attrib[VAConfigAttribRateControl].value != VA_ATTRIB_NOT_SUPPORTED) { int tmp = attrib[VAConfigAttribRateControl].value; - printf("Supported rate control mode (0x%x):", tmp); + printf("Supporte rate control mode (0x%x):", tmp); if (tmp & VA_RC_NONE) printf("NONE "); @@ -1114,7 +1142,7 @@ static void sort_one(VAPictureH264 ref[], int left, int right, partition(ref, frame_idx, key, ascending); } else { key = ref[(left + right) / 2].TopFieldOrderCnt; - partition(ref, TopFieldOrderCnt, key, ascending); + partition(ref, TopFieldOrderCnt, (signed int)key, ascending); } /* recursion */ @@ -1125,16 +1153,16 @@ static void sort_one(VAPictureH264 ref[], int left, int right, sort_one(ref, i, right, ascending, frame_idx); } -static void sort_two(VAPictureH264 ref[], int left, int right, int key, int frame_idx, - int divide_ascending, int list0_ascending, int list1_ascending) +static void sort_two(VAPictureH264 ref[], int left, int right, unsigned int key, unsigned int frame_idx, + int partition_ascending, int list0_ascending, int list1_ascending) { int i = left, j = right; VAPictureH264 tmp; if (frame_idx) { - partition(ref, frame_idx, key, divide_ascending); + partition(ref, frame_idx, key, partition_ascending); } else { - partition(ref, TopFieldOrderCnt, key, divide_ascending); + partition(ref, TopFieldOrderCnt, (signed int)key, partition_ascending); } @@ -1243,7 +1271,7 @@ static int render_sequence(void) return 0; } -static int calc_poc(unsigned int pic_order_cnt_lsb) +static int calc_poc(int pic_order_cnt_lsb) { static int PicOrderCntMsb_ref = 0, pic_order_cnt_lsb_ref = 0; int prevPicOrderCntMsb, prevPicOrderCntLsb; @@ -1257,10 +1285,10 @@ static int calc_poc(unsigned int pic_order_cnt_lsb) } if ((pic_order_cnt_lsb < prevPicOrderCntLsb) && - ((prevPicOrderCntLsb - pic_order_cnt_lsb) >= (MaxPicOrderCntLsb / 2))) + ((prevPicOrderCntLsb - pic_order_cnt_lsb) >= (int)(MaxPicOrderCntLsb / 2))) PicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb; else if ((pic_order_cnt_lsb > prevPicOrderCntLsb) && - ((pic_order_cnt_lsb - prevPicOrderCntLsb) > (MaxPicOrderCntLsb / 2))) + ((pic_order_cnt_lsb - prevPicOrderCntLsb) > (int)(MaxPicOrderCntLsb / 2))) PicOrderCntMsb = prevPicOrderCntMsb - MaxPicOrderCntLsb; else PicOrderCntMsb = prevPicOrderCntMsb; @@ -1326,7 +1354,7 @@ static int render_picture(void) static int render_packedsequence(void) { - VAEncPackedHeaderParameterBuffer packedheader_param_buffer={0}; + VAEncPackedHeaderParameterBuffer packedheader_param_buffer; VABufferID packedseq_para_bufid, packedseq_data_bufid, render_id[2]; unsigned int length_in_bits; unsigned char *packedseq_buffer = NULL; @@ -1365,7 +1393,7 @@ static int render_packedsequence(void) static int render_packedpicture(void) { - VAEncPackedHeaderParameterBuffer packedheader_param_buffer={0}; + VAEncPackedHeaderParameterBuffer packedheader_param_buffer; VABufferID packedpic_para_bufid, packedpic_data_bufid, render_id[2]; unsigned int length_in_bits; unsigned char *packedpic_buffer = NULL; @@ -1404,7 +1432,7 @@ static void render_packedsei(void) { VAEncPackedHeaderParameterBuffer packed_header_param_buffer; VABufferID packed_sei_header_param_buf_id, packed_sei_buf_id, render_id[2]; - unsigned int length_in_bits, offset_in_bytes; + unsigned int length_in_bits /*offset_in_bytes*/; unsigned char *packed_sei_buffer = NULL; VAStatus va_status; int init_cpb_size, target_bit_rate, i_initial_cpb_removal_delay_length, i_initial_cpb_removal_delay; @@ -1431,7 +1459,7 @@ static void render_packedsei(void) 0, &packed_sei_buffer); - offset_in_bytes = 0; + //offset_in_bytes = 0; packed_header_param_buffer.type = VAEncPackedHeaderH264_SEI; packed_header_param_buffer.bit_length = length_in_bits; packed_header_param_buffer.has_emulation_bytes = 0; @@ -1571,110 +1599,130 @@ static int upload_source_YUV_once_for_all() return 0; } - +#define check_ret(ret) \ +if (ret != 1) { \ + printf("fread doesn't return enough data\n"); \ + exit(1); \ +} static int load_surface(VASurfaceID surface_id, unsigned long long display_order) { - VAImage surface_image; - unsigned char *surface_p=NULL, *Y_start=NULL, *U_start=NULL,*V_start=NULL, *uv_ptr; - int Y_pitch=0, U_pitch=0, row, V_pitch, uv_size; - VAStatus va_status; - + unsigned char *src_Y = NULL, *src_U = NULL, *src_V = NULL; + int ret = 0; + if (srcyuv_fp == NULL) return 0; /* rewind the file pointer if encoding more than srcyuv_frames */ display_order = display_order % srcyuv_frames; - fseek(srcyuv_fp, display_order * frame_width * frame_height * 1.5, SEEK_SET); - va_status = vaDeriveImage(va_dpy,surface_id, &surface_image); - CHECK_VASTATUS(va_status,"vaDeriveImage"); - vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p); - assert(VA_STATUS_SUCCESS == va_status); + if (srcyuv_fourcc == VA_FOURCC_NV12) { + int uv_size = 2 * (frame_width/2) * (frame_height/2); - Y_start = surface_p; - Y_pitch = surface_image.pitches[0]; - switch (surface_image.format.fourcc) { - case VA_FOURCC_NV12: - U_start = (unsigned char *)surface_p + surface_image.offsets[1]; - V_start = U_start + 1; - U_pitch = surface_image.pitches[1]; - V_pitch = surface_image.pitches[1]; - break; - case VA_FOURCC_IYUV: - U_start = (unsigned char *)surface_p + surface_image.offsets[1]; - V_start = (unsigned char *)surface_p + surface_image.offsets[2]; - U_pitch = surface_image.pitches[1]; - V_pitch = surface_image.pitches[2]; - break; - case VA_FOURCC_YV12: - U_start = (unsigned char *)surface_p + surface_image.offsets[2]; - V_start = (unsigned char *)surface_p + surface_image.offsets[1]; - U_pitch = surface_image.pitches[2]; - V_pitch = surface_image.pitches[1]; - break; - case VA_FOURCC_YUY2: - U_start = surface_p + 1; - V_start = surface_p + 3; - U_pitch = surface_image.pitches[0]; - V_pitch = surface_image.pitches[0]; - break; - default: - assert(0); + src_Y = malloc(2 * uv_size); + src_U = malloc(uv_size); + + ret = fread(src_Y, frame_width * frame_height, 1, srcyuv_fp); + check_ret(ret); + ret = fread(src_U, uv_size, 1, srcyuv_fp); + check_ret(ret); + } else if (srcyuv_fourcc == VA_FOURCC_IYUV || + srcyuv_fourcc == VA_FOURCC_YV12) { + int uv_size = (frame_width/2) * (frame_height/2); + + src_Y = malloc(4 * uv_size); + src_U = malloc(uv_size); + src_V = malloc(uv_size); + + ret = fread(src_Y, frame_width * frame_height, 1, srcyuv_fp); + check_ret(ret); + if (srcyuv_fourcc == VA_FOURCC_IYUV) { + ret = fread(src_U, uv_size, 1, srcyuv_fp); + check_ret(ret); + ret = fread(src_V, uv_size, 1, srcyuv_fp); + check_ret(ret); + } else { /* YV12 */ + ret = fread(src_V, uv_size, 1, srcyuv_fp); + check_ret(ret); + ret = fread(src_U, uv_size, 1, srcyuv_fp); + check_ret(ret); + } + } else { + printf("Unsupported source YUV format\n"); + exit(1); } + + upload_surface_yuv(va_dpy, surface_id, + srcyuv_fourcc, frame_width, frame_height, + src_Y, src_U, src_V); + if (src_Y) + free(src_Y); + if (src_U) + free(src_U); + if (src_V) + free(src_V); + + return 0; +} + - /* copy Y plane */ - for (row=0;row<frame_height;row++) { - unsigned char *Y_row = Y_start + row * Y_pitch; - (void)fread(Y_row, 1, surface_image.width, srcyuv_fp); +static int save_recyuv(VASurfaceID surface_id, + unsigned long long display_order, + unsigned long long encode_order) +{ + unsigned char *dst_Y = NULL, *dst_U = NULL, *dst_V = NULL; + + if (recyuv_fp == NULL) + return 0; + + if (srcyuv_fourcc == VA_FOURCC_NV12) { + int uv_size = 2 * (frame_width/2) * (frame_height/2); + dst_Y = malloc(2*uv_size); + dst_U = malloc(uv_size); + } else if (srcyuv_fourcc == VA_FOURCC_IYUV || + srcyuv_fourcc == VA_FOURCC_YV12) { + int uv_size = (frame_width/2) * (frame_height/2); + dst_Y = malloc(4*uv_size); + dst_U = malloc(uv_size); + dst_V = malloc(uv_size); + } else { + printf("Unsupported source YUV format\n"); + exit(1); } - - /* copy UV data, reset file pointer, - * surface_image.height may not be equal to source YUV height/frame_height - */ - fseek(srcyuv_fp, - display_order * frame_width * frame_height * 1.5 + frame_width * frame_height, - SEEK_SET); - - uv_size = 2 * (frame_width/2) * (frame_height/2); - uv_ptr = malloc(uv_size); - fread(uv_ptr, uv_size, 1, srcyuv_fp); - - for (row =0; row < frame_height/2; row++) { - unsigned char *U_row = U_start + row * U_pitch; - unsigned char *u_ptr, *v_ptr; - int j; - switch (surface_image.format.fourcc) { - case VA_FOURCC_NV12: - if (srcyuv_fourcc == VA_FOURCC_NV12) { - memcpy(U_row, uv_ptr + row * frame_width, frame_width); - break; - } else if (srcyuv_fourcc == VA_FOURCC_IYUV) { - u_ptr = uv_ptr + row * (frame_width/2); - v_ptr = uv_ptr + (frame_width/2) * (frame_height/2) + row * (frame_width/2); - } else if (srcyuv_fourcc == VA_FOURCC_YV12) { - v_ptr = uv_ptr + row * (frame_height/2); - u_ptr = uv_ptr + (frame_width/2) * (frame_height/2) + row * (frame_width/2); - } - for(j = 0; j < frame_width/2; j++) { - U_row[2*j] = u_ptr[j]; - U_row[2*j+1] = v_ptr[j]; - } - break; - case VA_FOURCC_IYUV: - case VA_FOURCC_YV12: - case VA_FOURCC_YUY2: - default: - printf("unsupported fourcc in load_surface\n"); - assert(0); + + download_surface_yuv(va_dpy, surface_id, + srcyuv_fourcc, frame_width, frame_height, + dst_Y, dst_U, dst_V); + fseek(recyuv_fp, display_order * frame_width * frame_height * 1.5, SEEK_SET); + + if (srcyuv_fourcc == VA_FOURCC_NV12) { + int uv_size = 2 * (frame_width/2) * (frame_height/2); + fwrite(dst_Y, uv_size * 2, 1, recyuv_fp); + fwrite(dst_U, uv_size, 1, recyuv_fp); + } else if (srcyuv_fourcc == VA_FOURCC_IYUV || + srcyuv_fourcc == VA_FOURCC_YV12) { + int uv_size = (frame_width/2) * (frame_height/2); + fwrite(dst_Y, uv_size * 4, 1, recyuv_fp); + + if (srcyuv_fourcc == VA_FOURCC_IYUV) { + fwrite(dst_U, uv_size, 1, recyuv_fp); + fwrite(dst_V, uv_size, 1, recyuv_fp); + } else { + fwrite(dst_V, uv_size, 1, recyuv_fp); + fwrite(dst_U, uv_size, 1, recyuv_fp); } + } else { + printf("Unsupported YUV format\n"); + exit(1); } - free(uv_ptr); - vaUnmapBuffer(va_dpy,surface_image.buf); - - vaDestroyImage(va_dpy,surface_image.image_id); + if (dst_Y) + free(dst_Y); + if (dst_U) + free(dst_U); + if (dst_V) + free(dst_V); return 0; } @@ -1782,8 +1830,9 @@ static void storage_task(unsigned long long display_order, unsigned long long en tmp = GetTickCount(); save_codeddata(display_order, encode_order); SavePictureTicks += GetTickCount() - tmp; - /* tbd: save reconstructed frame */ - + + save_recyuv(ref_surface[display_order % SURFACE_NUM], display_order, encode_order); + /* reload a new frame data */ tmp = GetTickCount(); if (srcyuv_fp != NULL) @@ -1967,12 +2016,50 @@ static int print_input() return 0; } +static int calc_PSNR(double *psnr) +{ + unsigned long srcyuv_size, recyuv_size, min_size; + char *srcyuv_ptr, *recyuv_ptr; + unsigned long i, sse=0; + double ssemean; + + fseek(srcyuv_fp, 0L, SEEK_END); + srcyuv_size = ftell(srcyuv_fp); + fseek(recyuv_fp, 0L, SEEK_END); + recyuv_size = ftell(recyuv_fp); + + fseek(srcyuv_fp, 0L, SEEK_SET); + fseek(recyuv_fp, 0L, SEEK_SET); + + min_size = MIN(srcyuv_size,recyuv_size); + srcyuv_ptr = mmap (0, min_size, PROT_READ, MAP_SHARED, fileno(srcyuv_fp), 0); + recyuv_ptr = mmap (0, min_size, PROT_READ, MAP_SHARED, fileno(recyuv_fp), 0); + if ((srcyuv_ptr == MAP_FAILED) || (recyuv_ptr == MAP_FAILED)) { + printf("Failed to mmap YUV files\n"); + return 1; + } + + for (i=0; i<min_size; i++) { + char tmp = srcyuv_ptr[i] - recyuv_ptr[i]; + sse += tmp * tmp; + } + ssemean = (double)sse/(double)min_size; + *psnr = 20.0*log10(255) - 10.0*log10(ssemean); + + munmap(srcyuv_ptr, min_size); + munmap(recyuv_ptr, min_size); + + return 0; +} static int print_performance(unsigned int PictureCount) { - unsigned int others = 0; - double total_size = frame_width * frame_height * 1.5 * frame_count; + unsigned int psnr_ret = 1, others = 0; + double psnr = 0, total_size = frame_width * frame_height * 1.5 * frame_count; + if (calc_psnr && srcyuv_fp && recyuv_fp) + psnr_ret = calc_PSNR(&psnr); + others = TotalTicks - UploadPictureTicks - BeginPictureTicks - RenderPictureTicks - EndPictureTicks - SyncPictureTicks - SavePictureTicks; @@ -1982,6 +2069,9 @@ static int print_performance(unsigned int PictureCount) (double) 1000*PictureCount / TotalTicks, PictureCount, TotalTicks, ((double) TotalTicks) / (double) PictureCount); printf("PERFORMANCE: Compression ratio : %d:1\n", (unsigned int)(total_size / frame_size)); + if (psnr_ret == 0) + printf("PERFORMANCE: PSNR : %.2f (%lld frames calculated)\n", + psnr, MIN(frame_count, srcyuv_frames)); printf("PERFORMANCE: UploadPicture : %d ms (%.2f, %.2f%% percent)\n", (int) UploadPictureTicks, ((double) UploadPictureTicks) / (double) PictureCount, @@ -2006,8 +2096,8 @@ static int print_performance(unsigned int PictureCount) others/(double) TotalTicks/0.01); if (encode_syncmode == 0) - printf("(Multithread enabled, the profiling is only for reference)\n"); - + printf("(Multithread enabled, the timing is only for reference)\n"); + return 0; } diff --git a/test/loadsurface.h b/test/loadsurface.h index 6f7bce2..119db97 100755 --- a/test/loadsurface.h +++ b/test/loadsurface.h @@ -24,7 +24,7 @@ #include "loadsurface_yuv.h" static int scale_2dimage(unsigned char *src_img, int src_imgw, int src_imgh, - unsigned char *dst_img, int dst_imgw, int dst_imgh) + unsigned char *dst_img, int dst_imgw, int dst_imgh) { int row=0, col=0; @@ -39,10 +39,10 @@ static int scale_2dimage(unsigned char *src_img, int src_imgw, int src_imgh, static int YUV_blend_with_pic(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, - unsigned int fourcc, int fixed_alpha) + unsigned char *Y_start, int Y_pitch, + unsigned char *U_start, int U_pitch, + unsigned char *V_start, int V_pitch, + unsigned int fourcc, int fixed_alpha) { /* PIC YUV format */ unsigned char *pic_y_old = yuvga_pic; @@ -155,7 +155,7 @@ static int yuvgen_planar(int width, int height, /* copy Y plane */ int y_factor = 1; - if (fourcc == VA_FOURCC_YUY2) y_factor = 2; + if (fourcc == VA_FOURCC_YUY2) y_factor = 2; for (row=0;row<height;row++) { unsigned char *Y_row = Y_start + row * Y_pitch; int jj, xpos, ypos; @@ -178,7 +178,7 @@ static int yuvgen_planar(int width, int height, if (fourcc == VA_FOURCC_YUY2) { Y_row[jj*y_factor+1] = uv_value; // it is for UV - } + } } } @@ -196,11 +196,11 @@ static int yuvgen_planar(int width, int height, switch (fourcc) { case VA_FOURCC_NV12: memset(U_row, uv_value, width); - break; + break; case VA_FOURCC_YV12: memset (U_row,uv_value,width/2); memset (V_row,uv_value,width/2); - break; + break; case VA_FOURCC_YUY2: // see above. it is set with Y update. break; @@ -286,3 +286,195 @@ static int upload_surface(VADisplay va_dpy, VASurfaceID surface_id, return 0; } + +/* + * Upload YUV data from memory into a surface + * if src_fourcc == NV12, assume the buffer pointed by src_U + * is UV interleaved (src_V is ignored) + */ +static int upload_surface_yuv(VADisplay va_dpy, VASurfaceID surface_id, + int src_fourcc, int src_width, int src_height, + unsigned char *src_Y, unsigned char *src_U, unsigned char *src_V) +{ + VAImage surface_image; + unsigned char *surface_p=NULL, *Y_start=NULL, *U_start=NULL, *V_start=NULL; + int Y_pitch=0, U_pitch=0, V_pitch=0, row; + VAStatus va_status; + + va_status = vaDeriveImage(va_dpy,surface_id, &surface_image); + CHECK_VASTATUS(va_status,"vaDeriveImage"); + + vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p); + assert(VA_STATUS_SUCCESS == va_status); + + Y_start = surface_p; + Y_pitch = surface_image.pitches[0]; + switch (surface_image.format.fourcc) { + case VA_FOURCC_NV12: + U_start = (unsigned char *)surface_p + surface_image.offsets[1]; + V_start = U_start + 1; + U_pitch = surface_image.pitches[1]; + V_pitch = surface_image.pitches[1]; + break; + case VA_FOURCC_IYUV: + U_start = (unsigned char *)surface_p + surface_image.offsets[1]; + V_start = (unsigned char *)surface_p + surface_image.offsets[2]; + U_pitch = surface_image.pitches[1]; + V_pitch = surface_image.pitches[2]; + break; + case VA_FOURCC_YV12: + U_start = (unsigned char *)surface_p + surface_image.offsets[2]; + V_start = (unsigned char *)surface_p + surface_image.offsets[1]; + U_pitch = surface_image.pitches[2]; + V_pitch = surface_image.pitches[1]; + break; + case VA_FOURCC_YUY2: + U_start = surface_p + 1; + V_start = surface_p + 3; + U_pitch = surface_image.pitches[0]; + V_pitch = surface_image.pitches[0]; + break; + default: + assert(0); + } + + /* copy Y plane */ + for (row=0;row<src_height;row++) { + unsigned char *Y_row = Y_start + row * Y_pitch; + memcpy(Y_row, src_Y + row*src_width, src_width); + } + + for (row =0; row < src_height/2; row++) { + unsigned char *U_row = U_start + row * U_pitch; + unsigned char *u_ptr = NULL, *v_ptr=NULL; + int j; + switch (surface_image.format.fourcc) { + case VA_FOURCC_NV12: + if (src_fourcc == VA_FOURCC_NV12) { + memcpy(U_row, src_U + row * src_width, src_width); + break; + } else if (src_fourcc == VA_FOURCC_IYUV) { + u_ptr = src_U + row * (src_width/2); + v_ptr = src_V + row * (src_width/2); + } else if (src_fourcc == VA_FOURCC_YV12) { + v_ptr = src_U + row * (src_width/2); + u_ptr = src_V + row * (src_width/2); + } + for(j = 0; j < src_width/2; j++) { + U_row[2*j] = u_ptr[j]; + U_row[2*j+1] = v_ptr[j]; + } + break; + case VA_FOURCC_IYUV: + case VA_FOURCC_YV12: + case VA_FOURCC_YUY2: + default: + printf("unsupported fourcc in load_surface_yuv\n"); + assert(0); + } + } + + vaUnmapBuffer(va_dpy,surface_image.buf); + + vaDestroyImage(va_dpy,surface_image.image_id); + + return 0; +} + +/* + * Download YUV data from a surface into memory + * Some hardward doesn't have a aperture for linear access of + * tiled surface, thus use vaGetImage to expect the implemnetion + * to do tile to linear convert + * + * if dst_fourcc == NV12, assume the buffer pointed by dst_U + * is UV interleaved (src_V is ignored) + */ +static int download_surface_yuv(VADisplay va_dpy, VASurfaceID surface_id, + int dst_fourcc, int dst_width, int dst_height, + unsigned char *dst_Y, unsigned char *dst_U, unsigned char *dst_V) +{ + VAImage surface_image; + unsigned char *surface_p=NULL, *Y_start=NULL, *U_start=NULL,*V_start=NULL; + int Y_pitch=0, U_pitch=0, V_pitch=0, row; + VAStatus va_status; + + va_status = vaDeriveImage(va_dpy,surface_id, &surface_image); + CHECK_VASTATUS(va_status,"vaDeriveImage"); + + vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p); + assert(VA_STATUS_SUCCESS == va_status); + + Y_start = surface_p; + Y_pitch = surface_image.pitches[0]; + switch (surface_image.format.fourcc) { + case VA_FOURCC_NV12: + U_start = (unsigned char *)surface_p + surface_image.offsets[1]; + V_start = U_start + 1; + U_pitch = surface_image.pitches[1]; + V_pitch = surface_image.pitches[1]; + break; + case VA_FOURCC_IYUV: + U_start = (unsigned char *)surface_p + surface_image.offsets[1]; + V_start = (unsigned char *)surface_p + surface_image.offsets[2]; + U_pitch = surface_image.pitches[1]; + V_pitch = surface_image.pitches[2]; + break; + case VA_FOURCC_YV12: + U_start = (unsigned char *)surface_p + surface_image.offsets[2]; + V_start = (unsigned char *)surface_p + surface_image.offsets[1]; + U_pitch = surface_image.pitches[2]; + V_pitch = surface_image.pitches[1]; + break; + case VA_FOURCC_YUY2: + U_start = surface_p + 1; + V_start = surface_p + 3; + U_pitch = surface_image.pitches[0]; + V_pitch = surface_image.pitches[0]; + break; + default: + assert(0); + } + + /* copy Y plane */ + for (row=0;row<dst_height;row++) { + unsigned char *Y_row = Y_start + row * Y_pitch; + memcpy(dst_Y + row*dst_width, Y_row, dst_width); + } + + for (row =0; row < dst_height/2; row++) { + unsigned char *U_row = U_start + row * U_pitch; + unsigned char *u_ptr = NULL, *v_ptr = NULL; + int j; + switch (surface_image.format.fourcc) { + case VA_FOURCC_NV12: + if (dst_fourcc == VA_FOURCC_NV12) { + memcpy(dst_U + row * dst_width, U_row, dst_width); + break; + } else if (dst_fourcc == VA_FOURCC_IYUV) { + u_ptr = dst_U + row * (dst_width/2); + v_ptr = dst_V + row * (dst_width/2); + } else if (dst_fourcc == VA_FOURCC_YV12) { + v_ptr = dst_U + row * (dst_width/2); + u_ptr = dst_V + row * (dst_width/2); + } + for(j = 0; j < dst_width/2; j++) { + u_ptr[j] = U_row[2*j]; + v_ptr[j] = U_row[2*j+1]; + } + break; + case VA_FOURCC_IYUV: + case VA_FOURCC_YV12: + case VA_FOURCC_YUY2: + default: + printf("unsupported fourcc in load_surface_yuv\n"); + assert(0); + } + } + + vaUnmapBuffer(va_dpy,surface_image.buf); + + vaDestroyImage(va_dpy,surface_image.image_id); + + return 0; +} |