Index: third_party/libva/test/v4l_h264/encode/avcenc.cpp |
diff --git a/third_party/libva/test/v4l_h264/encode/avcenc.cpp b/third_party/libva/test/v4l_h264/encode/avcenc.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b3afd569bf41eb50526b65321f5994a2ba2cc7f3 |
--- /dev/null |
+++ b/third_party/libva/test/v4l_h264/encode/avcenc.cpp |
@@ -0,0 +1,508 @@ |
+/* |
+ * Copyright (c) 2012 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 NONINFRINGEMENT. |
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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. |
+ */ |
+ |
+/* |
+* Example based on Simple AVC encoder. |
+* http://cgit.freedesktop.org/libva/tree/test/encode/avcenc.c |
+* |
+*/ |
+ |
+#include <cstdio> |
+#include <cstring> |
+#include <cstdarg> |
+#include <cassert> |
+#include <va/va_x11.h> |
+#include <X11/Xlib.h> |
+#include <X11/Xutil.h> |
+ |
+#include <iostream> |
+#include <cstdlib> |
+ |
+#include "TCPSocketClient.h" |
+ |
+#define MY_Y 0x22 |
+#define MY_U 0xff |
+#define MY_V 0x55 |
+ |
+ |
+extern TCPSocketClient *sock_ptr; |
+extern int g_Debug; |
+extern char *device_settings; |
+Window win2; |
+int win2_width = 640; |
+int win2_height = 480; |
+int g_PX = -1; |
+int g_PY = -1; |
+ |
+ |
+bool g_LiveView = true; |
+bool g_Force_P_Only = false; |
+bool g_ShowNumber = true; |
+ |
+ |
+ |
+ |
+#define SLICE_TYPE_P 0 |
+#define SLICE_TYPE_B 1 |
+#define SLICE_TYPE_I 2 |
+ |
+#define ENTROPY_MODE_CAVLC 0 |
+#define ENTROPY_MODE_CABAC 1 |
+ |
+#define PROFILE_IDC_BASELINE 66 |
+#define PROFILE_IDC_MAIN 77 |
+#define PROFILE_IDC_HIGH 100 |
+ |
+#define CHECK_VASTATUS(va_status,func) \ |
+ if (va_status != VA_STATUS_SUCCESS) { \ |
+ std::cerr << __func__ << ':' << func << '(' << __LINE__ << ") failed, exit\n"; \ |
+ exit(1); \ |
+ } |
+ |
+static Display *x11_display; |
+static VADisplay va_dpy; |
+static VAContextID context_id; |
+static VAConfigID config_id; |
+ |
+static int picture_width, picture_width_in_mbs; |
+static int picture_height, picture_height_in_mbs; |
+static int frame_size; |
+static int codedbuf_size; |
+ |
+static int qp_value = 26; |
+ |
+static int log2_max_frame_num_minus4 = 0; |
+static int pic_order_cnt_type = 0; |
+static int log2_max_pic_order_cnt_lsb_minus4 = 0; |
+static int entropy_coding_mode_flag = ENTROPY_MODE_CABAC; |
+static int deblocking_filter_control_present_flag = 1; |
+static int frame_mbs_only_flag = 1; |
+ |
+static void create_encode_pipe() |
+{ |
+ VAEntrypoint entrypoints[5]; |
+ int num_entrypoints,slice_entrypoint; |
+ VAConfigAttrib attrib[2]; |
+ int major_ver, minor_ver; |
+ VAStatus va_status; |
+ |
+ x11_display = XOpenDisplay(":0.0"); |
+ assert(x11_display); |
+ |
+ va_dpy = vaGetDisplay(x11_display); |
+ va_status = vaInitialize(va_dpy, &major_ver, &minor_ver); |
+ CHECK_VASTATUS(va_status, "vaInitialize"); |
+ vaQueryConfigEntrypoints(va_dpy, VAProfileH264Baseline, entrypoints, &num_entrypoints); |
+ |
+ for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) { |
+ if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice) |
+ break; |
+ } |
+ |
+ if (slice_entrypoint == num_entrypoints) { |
+ /* not find Slice entry point */ |
+ assert(0); |
+ } |
+ |
+ /* find out the format for the render target, and rate control mode */ |
+ attrib[0].type = VAConfigAttribRTFormat; |
+ attrib[1].type = VAConfigAttribRateControl; |
+ vaGetConfigAttributes(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice, &attrib[0], 2); |
+ |
+ if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) { |
+ /* not find desired YUV420 RT format */ |
+ assert(0); |
+ } |
+ |
+ if ((attrib[1].value & VA_RC_VBR) == 0) { |
+ /* Can't find matched RC mode */ |
+ std::cerr << "VBR mode not found, exit\n"; |
+ assert(0); |
+ } |
+ |
+ attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */ |
+ attrib[1].value = VA_RC_VBR; /* set to desired RC mode */ |
+ |
+ va_status = vaCreateConfig(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice, &attrib[0], 2,&config_id); |
+ CHECK_VASTATUS(va_status, "vaCreateConfig"); |
+ |
+ /* Create a context for this decode pipe */ |
+ va_status = vaCreateContext(va_dpy, config_id, picture_width, picture_height, VA_PROGRESSIVE, 0, 0, &context_id); |
+ CHECK_VASTATUS(va_status, "vaCreateContext"); |
+} |
+ |
+static void destory_encode_pipe() |
+{ |
+ vaDestroyContext(va_dpy,context_id); |
+ vaDestroyConfig(va_dpy,config_id); |
+ vaTerminate(va_dpy); |
+ XCloseDisplay(x11_display); |
+} |
+ |
+/*************************************************** |
+* |
+* The encode pipe resource define |
+* |
+***************************************************/ |
+static VABufferID seq_parameter = VA_INVALID_ID; /*Sequence level parameter*/ |
+static VABufferID pic_parameter = VA_INVALID_ID; /*Picture level parameter*/ |
+static VABufferID slice_parameter = VA_INVALID_ID; /*Slice level parameter, multil slices*/ |
+static VABufferID coded_buf = VA_INVALID_ID; /*Output buffer, compressed data*/ |
+ |
+#define SID_NUMBER 3 |
+#define SID_INPUT_PICTURE 0 |
+#define SID_REFERENCE_PICTURE 1 |
+#define SID_RECON_PICTURE 2 |
+static VASurfaceID surface_ids[SID_NUMBER]; |
+ |
+/***************************************************/ |
+ |
+static void alloc_encode_resource() |
+{ |
+ VAStatus va_status; |
+ seq_parameter = VA_INVALID_ID; |
+ pic_parameter = VA_INVALID_ID; |
+ slice_parameter = VA_INVALID_ID; |
+ |
+ //1. Create sequence parameter set |
+ { |
+ VAEncSequenceParameterBufferH264 seq_h264 = {0}; |
+ seq_h264.level_idc = 30; |
+ seq_h264.picture_width_in_mbs = picture_width_in_mbs; |
+ seq_h264.picture_height_in_mbs = picture_height_in_mbs; |
+ seq_h264.bits_per_second = 384*1000; |
+ seq_h264.initial_qp = qp_value; |
+ seq_h264.min_qp = 3; |
+ va_status = vaCreateBuffer(va_dpy, context_id, VAEncSequenceParameterBufferType, |
+ sizeof(seq_h264),1,&seq_h264,&seq_parameter); |
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");; |
+ } |
+ //2. Create surface |
+ va_status = vaCreateSurfaces(va_dpy, picture_width, picture_height, VA_RT_FORMAT_YUV420, SID_NUMBER, &surface_ids[0]); |
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces"); |
+ //3. Create coded buffer |
+ { |
+ va_status = vaCreateBuffer(va_dpy,context_id,VAEncCodedBufferType, codedbuf_size, 1, NULL, &coded_buf); |
+ CHECK_VASTATUS(va_status,"vaBeginPicture"); |
+ } |
+} |
+ |
+static void release_encode_resource() |
+{ |
+ //-3 Relese coded buffer |
+ if (coded_buf != VA_INVALID_ID) |
+ vaDestroyBuffer(va_dpy, coded_buf); |
+ //-2 Release all the surfaces resource |
+ vaDestroySurfaces(va_dpy, &surface_ids[0], SID_NUMBER); |
+ //-1 Destory the sequence level parameter |
+ if (seq_parameter != VA_INVALID_ID) |
+ vaDestroyBuffer(va_dpy, seq_parameter); |
+} |
+ |
+ |
+static int get_coded_bitsteam_length(unsigned char *buffer, int buffer_length) |
+{ |
+ int i; |
+ for (i = buffer_length - 1; i >= 0; i--) { |
+ if (buffer[i]) |
+ break; |
+ } |
+ return i + 1; |
+} |
+ |
+ |
+ |
+void SetWindowTitle(const char* title, ...) |
+{ |
+ va_list args; |
+ va_start(args, title); |
+ char buf[256]; |
+ vsprintf(buf, title, args); |
+ va_end(args); |
+ XSetStandardProperties(x11_display,win2, buf, buf, None, NULL, 0, NULL); |
+} |
+ |
+ |
+ |
+int encoder_init(int width, int height) |
+{ |
+ picture_width = width; |
+ picture_height = height; |
+ picture_width_in_mbs = (picture_width + 15) / 16; |
+ picture_height_in_mbs = (picture_height + 15) / 16; |
+ qp_value = 26; |
+ frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ; |
+ codedbuf_size = picture_width * picture_height * 1.5; |
+ create_encode_pipe(); |
+ alloc_encode_resource(); |
+ sock_ptr->send(picture_width); |
+ sock_ptr->send(picture_height); |
+ sock_ptr->send(picture_width_in_mbs-1); |
+ sock_ptr->send(picture_height_in_mbs-1); |
+ if (g_LiveView) { |
+ win2 = XCreateSimpleWindow(x11_display, RootWindow(x11_display, 0), 0, 0, win2_width, win2_height, 0, 0, WhitePixel(x11_display, 0)); |
+ XMapWindow(x11_display, win2); |
+ if ((g_PX !=-1) && (g_PY !=-1)) { |
+ XMoveWindow(x11_display, win2, g_PX, g_PY); |
+ } |
+ SetWindowTitle("Input: %dx%d [TCP] %s",picture_width,picture_height, device_settings); |
+ XSync(x11_display, False); |
+ } |
+ return 0; |
+} |
+ |
+void encoder_close() |
+{ |
+ release_encode_resource(); |
+ destory_encode_pipe(); |
+} |
+ |
+ |
+/* 8x8 font 0-9 only - asm type format */ |
+unsigned char mydigits[80] { |
+ // 0 |
+ 0x0E,0x11,0x13,0x15,0x19,0x11,0x0E,0x00, |
+ // 1 |
+ 0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00, |
+ // 2 |
+ 0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,0x00, |
+ // 3 |
+ 0x1F,0x02,0x04,0x02,0x01,0x11,0x0E,0x00, |
+ // 4 |
+ 0x02,0x06,0x0A,0x12,0x1F,0x02,0x02,0x00, |
+ // 5 |
+ 0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E,0x00, |
+ // 6 |
+ 0x06,0x08,0x10,0x1E,0x11,0x11,0x0E,0x00, |
+ // 7 |
+ 0x1F,0x01,0x02,0x04,0x04,0x04,0x04,0x00, |
+ // 8 |
+ 0x1E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00, |
+ //9 |
+ 0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C,0x00 |
+}; |
+ |
+#define INTERSIZE 16 |
+ |
+static void ShowNumber(int num, unsigned char *buffer, VAImage *image) |
+{ |
+ int j; |
+ char buf[20]; |
+ unsigned char *dst_y; |
+ unsigned char *dst_uv_line; |
+ unsigned char *digits_ptr; |
+ assert(image); |
+ int maxlen = sprintf(buf, "%d", num); |
+ assert(maxlen<20); |
+ for (int a=0; a<maxlen;a++) { |
+ digits_ptr = &mydigits[(buf[a]-'0')*8]; |
+ for (int i=0; i<8; i++) { |
+ unsigned char current = digits_ptr[i]; |
+ dst_y = (buffer+ image->offsets[0]) + ((i*2)*image->pitches[0])+(a*INTERSIZE); |
+ dst_uv_line = (buffer + image->offsets[1]) + (i*image->pitches[1])+(a*INTERSIZE); |
+ for (j=7; j>=0;j--) { |
+ if ((current >>j) & 1) { |
+ *dst_y ++ = MY_Y; |
+ *dst_y ++ = MY_Y; |
+ *dst_uv_line++ = MY_U; |
+ *dst_uv_line++ = MY_V; |
+ } else { |
+ dst_y += 2; |
+ dst_uv_line +=2; |
+ } |
+ } |
+ dst_y = (buffer+ image->offsets[0]) + (((i*2)+1)*image->pitches[0])+(a*INTERSIZE); |
+ for (j=7; j>=0;j--) { |
+ if ((current >>j) & 1) { |
+ *dst_y ++ = MY_Y; |
+ *dst_y ++ = MY_Y; |
+ } else { |
+ dst_y += 2; |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+ |
+static void upload_yuv_to_surface(unsigned char *inbuf, VASurfaceID surface_id, unsigned int frame) |
+{ |
+ VAImage image; |
+ VAStatus va_status; |
+ void *pbuffer=NULL; |
+ unsigned char *psrc = inbuf; |
+ unsigned char *pdst = NULL; |
+ unsigned char *dst_y, *dst_uv; |
+ unsigned char *src_u, *src_v; |
+ unsigned char *dst_uv_line = NULL; |
+ int i,j; |
+ va_status = vaDeriveImage(va_dpy, surface_id, &image); |
+ va_status = vaMapBuffer(va_dpy, image.buf, &pbuffer); |
+ pdst = (unsigned char *)pbuffer; |
+ dst_uv_line = pdst + image.offsets[1]; |
+ dst_uv = dst_uv_line; |
+ for (i=0; i<picture_height; i+=2) { |
+ dst_y = (pdst + image.offsets[0]) + i*image.pitches[0]; |
+ for (j=0; j<(picture_width/2); ++j) { |
+ *(dst_y++) = psrc[0];//y1; |
+ *(dst_uv++) = psrc[1];//u; |
+ *(dst_y++) = psrc[2];//y1; |
+ *(dst_uv++) = psrc[3];//v; |
+ psrc+=4; |
+ } |
+ dst_y = (pdst + image.offsets[0]) + (i+1)*image.pitches[0]; |
+ for (j=0; j<picture_width/2; ++j) { |
+ *(dst_y++) = psrc[0];//y1; |
+ *(dst_y++) = psrc[2];//y2; |
+ psrc+=4; |
+ } |
+ dst_uv_line += image.pitches[1]; |
+ dst_uv = dst_uv_line; |
+ } |
+ if (g_ShowNumber) { |
+ ShowNumber(frame, (unsigned char *)pbuffer, &image); |
+ } |
+ va_status = vaUnmapBuffer(va_dpy, image.buf); |
+ CHECK_VASTATUS(va_status,"vaUnmapBuffer"); |
+ va_status = vaDestroyImage(va_dpy, image.image_id); |
+ CHECK_VASTATUS(va_status,"vaDestroyImage"); |
+ if (g_LiveView) { |
+ va_status = vaPutSurface(va_dpy, surface_id, win2, 0, 0, picture_width,picture_height, 0, 0, win2_width, win2_height, NULL, 0, VA_FRAME_PICTURE); |
+ CHECK_VASTATUS(va_status,"vaPutSurface"); |
+ } |
+} |
+ |
+ |
+static void prepare_input(unsigned char *buffer, int intra_slice, unsigned int frame) |
+{ |
+ static VAEncPictureParameterBufferH264 pic_h264; |
+ static VAEncSliceParameterBuffer slice_h264; |
+ VAStatus va_status; |
+ VABufferID tempID; |
+ VACodedBufferSegment *coded_buffer_segment = NULL; |
+ unsigned char *coded_mem; |
+ // Sequence level |
+ va_status = vaRenderPicture(va_dpy, context_id, &seq_parameter, 1); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture");; |
+ // Copy Image to target surface according input YUV data. |
+ upload_yuv_to_surface(buffer, surface_ids[SID_INPUT_PICTURE], frame); |
+ // Picture level |
+ pic_h264.reference_picture = surface_ids[SID_REFERENCE_PICTURE]; |
+ pic_h264.reconstructed_picture = surface_ids[SID_RECON_PICTURE]; |
+ pic_h264.coded_buf = coded_buf; |
+ pic_h264.picture_width = picture_width; |
+ pic_h264.picture_height = picture_height; |
+ pic_h264.last_picture = 0; |
+ if (pic_parameter != VA_INVALID_ID) { |
+ vaDestroyBuffer(va_dpy, pic_parameter); |
+ } |
+ va_status = vaCreateBuffer(va_dpy, context_id,VAEncPictureParameterBufferType, |
+ sizeof(pic_h264),1,&pic_h264,&pic_parameter); |
+ CHECK_VASTATUS(va_status,"vaCreateBuffer"); |
+ va_status = vaRenderPicture(va_dpy,context_id, &pic_parameter, 1); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture"); |
+ // clean old memory |
+ va_status = vaMapBuffer(va_dpy,coded_buf,(void **)(&coded_buffer_segment)); |
+ CHECK_VASTATUS(va_status,"vaMapBuffer"); |
+ coded_mem = (unsigned char*)coded_buffer_segment->buf; |
+ memset(coded_mem, 0, coded_buffer_segment->size); |
+ vaUnmapBuffer(va_dpy, coded_buf); |
+ // Slice level |
+ slice_h264.start_row_number = 0; |
+ slice_h264.slice_height = picture_height/16; /* Measured by MB */ |
+ slice_h264.slice_flags.bits.is_intra = intra_slice; |
+ slice_h264.slice_flags.bits.disable_deblocking_filter_idc = 0; |
+ if ( slice_parameter != VA_INVALID_ID) { |
+ vaDestroyBuffer(va_dpy, slice_parameter); |
+ } |
+ va_status = vaCreateBuffer(va_dpy,context_id,VAEncSliceParameterBufferType, |
+ sizeof(slice_h264),1,&slice_h264,&slice_parameter); |
+ CHECK_VASTATUS(va_status,"vaCreateBuffer");; |
+ va_status = vaRenderPicture(va_dpy,context_id, &slice_parameter, 1); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture"); |
+ |
+ // Prepare for next picture |
+ tempID = surface_ids[SID_RECON_PICTURE]; |
+ surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE]; |
+ surface_ids[SID_REFERENCE_PICTURE] = tempID; |
+} |
+ |
+static void send_slice_data(unsigned int frcount, int slice_type) |
+{ |
+ VACodedBufferSegment *coded_buffer_segment; |
+ unsigned char *coded_mem; |
+ int i, slice_data_length; |
+ int mm; |
+ VAStatus va_status; |
+ VASurfaceStatus surface_status; |
+ int is_cabac = (entropy_coding_mode_flag == ENTROPY_MODE_CABAC); |
+ va_status = vaSyncSurface(va_dpy, surface_ids[SID_INPUT_PICTURE]); |
+ CHECK_VASTATUS(va_status,"vaSyncSurface"); |
+ surface_status = (VASurfaceStatus)0; |
+ va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[SID_INPUT_PICTURE], &surface_status); |
+ CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus"); |
+ va_status = vaMapBuffer(va_dpy, coded_buf, (void **)(&coded_buffer_segment)); |
+ CHECK_VASTATUS(va_status,"vaMapBuffer"); |
+ coded_mem = (unsigned char*)coded_buffer_segment->buf; |
+ sock_ptr->send(frcount); |
+ sock_ptr->send(slice_type); |
+ |
+ if (is_cabac) { |
+ if (!coded_buffer_segment->next) { |
+ slice_data_length = get_coded_bitsteam_length(coded_mem, codedbuf_size); |
+ } else { |
+ /* Fixme me - to do: loop to each block and calculate the real data_lenght */ |
+ assert(0); |
+ } |
+ if (g_Debug) { |
+ printf("T=%d BS=%8d SZ=%8d C=%d\n", slice_type, codedbuf_size, slice_data_length, frcount); |
+ }sock_ptr->send(slice_data_length); |
+ sock_ptr->send((unsigned char*)coded_mem, slice_data_length); |
+ } else { |
+ /* FIXME */ |
+ assert(0); |
+ } |
+ vaUnmapBuffer(va_dpy, coded_buf); |
+} |
+ |
+ |
+int encode_frame(unsigned char *inbuf) |
+{ |
+ static unsigned int framecount = 0; |
+ int is_intra = (framecount % 30 == 0); |
+ if (g_Force_P_Only) { |
+ is_intra = 1; |
+ } |
+ VAStatus va_status; |
+ va_status = vaBeginPicture(va_dpy, context_id, surface_ids[SID_INPUT_PICTURE]); |
+ CHECK_VASTATUS(va_status,"vaBeginPicture"); |
+ prepare_input(inbuf, is_intra, framecount); |
+ va_status = vaEndPicture(va_dpy,context_id); |
+ CHECK_VASTATUS(va_status,"vaRenderPicture"); |
+ send_slice_data(framecount, is_intra ? SLICE_TYPE_I : SLICE_TYPE_P); |
+ framecount++; |
+ return 1; |
+} |
+ |