2
* Copyright (c) 2012 Intel Corporation. All Rights Reserved.
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the
6
* "Software"), to deal in the Software without restriction, including
7
* without limitation the rights to use, copy, modify, merge, publish,
8
* distribute, sub license, and/or sell copies of the Software, and to
9
* permit persons to whom the Software is furnished to do so, subject to
10
* the following conditions:
12
* The above copyright notice and this permission notice (including the
13
* next paragraph) shall be included in all copies or substantial portions
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
20
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22
* USE OR OTHER DEALINGS IN THE SOFTWARE.
26
* Example based on Simple AVC encoder.
27
* http://cgit.freedesktop.org/libva/tree/test/encode/avcenc.c
35
#include <va/va_x11.h>
37
#include <X11/Xutil.h>
42
#include "TCPSocketClient.h"
49
extern TCPSocketClient *sock_ptr;
51
extern char *device_settings;
54
int win2_height = 480;
59
bool g_LiveView = true;
60
bool g_Force_P_Only = false;
61
bool g_ShowNumber = true;
66
#define SLICE_TYPE_P 0
67
#define SLICE_TYPE_B 1
68
#define SLICE_TYPE_I 2
70
#define ENTROPY_MODE_CAVLC 0
71
#define ENTROPY_MODE_CABAC 1
73
#define PROFILE_IDC_BASELINE 66
74
#define PROFILE_IDC_MAIN 77
75
#define PROFILE_IDC_HIGH 100
77
#define CHECK_VASTATUS(va_status,func) \
78
if (va_status != VA_STATUS_SUCCESS) { \
79
std::cerr << __func__ << ':' << func << '(' << __LINE__ << ") failed, exit\n"; \
83
static Display *x11_display;
84
static VADisplay va_dpy;
85
static VAContextID context_id;
86
static VAConfigID config_id;
88
static int picture_width, picture_width_in_mbs;
89
static int picture_height, picture_height_in_mbs;
90
static int frame_size;
91
static int codedbuf_size;
93
static int qp_value = 26;
95
static int log2_max_frame_num_minus4 = 0;
96
static int pic_order_cnt_type = 0;
97
static int log2_max_pic_order_cnt_lsb_minus4 = 0;
98
static int entropy_coding_mode_flag = ENTROPY_MODE_CABAC;
99
static int deblocking_filter_control_present_flag = 1;
100
static int frame_mbs_only_flag = 1;
102
static void create_encode_pipe()
104
VAEntrypoint entrypoints[5];
105
int num_entrypoints,slice_entrypoint;
106
VAConfigAttrib attrib[2];
107
int major_ver, minor_ver;
110
x11_display = XOpenDisplay(":0.0");
113
va_dpy = vaGetDisplay(x11_display);
114
va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
115
CHECK_VASTATUS(va_status, "vaInitialize");
116
vaQueryConfigEntrypoints(va_dpy, VAProfileH264Baseline, entrypoints, &num_entrypoints);
118
for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
119
if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice)
123
if (slice_entrypoint == num_entrypoints) {
124
/* not find Slice entry point */
128
/* find out the format for the render target, and rate control mode */
129
attrib[0].type = VAConfigAttribRTFormat;
130
attrib[1].type = VAConfigAttribRateControl;
131
vaGetConfigAttributes(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice, &attrib[0], 2);
133
if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) {
134
/* not find desired YUV420 RT format */
138
if ((attrib[1].value & VA_RC_VBR) == 0) {
139
/* Can't find matched RC mode */
140
std::cerr << "VBR mode not found, exit\n";
144
attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
145
attrib[1].value = VA_RC_VBR; /* set to desired RC mode */
147
va_status = vaCreateConfig(va_dpy, VAProfileH264Baseline, VAEntrypointEncSlice, &attrib[0], 2,&config_id);
148
CHECK_VASTATUS(va_status, "vaCreateConfig");
150
/* Create a context for this decode pipe */
151
va_status = vaCreateContext(va_dpy, config_id, picture_width, picture_height, VA_PROGRESSIVE, 0, 0, &context_id);
152
CHECK_VASTATUS(va_status, "vaCreateContext");
155
static void destory_encode_pipe()
157
vaDestroyContext(va_dpy,context_id);
158
vaDestroyConfig(va_dpy,config_id);
160
XCloseDisplay(x11_display);
163
/***************************************************
165
* The encode pipe resource define
167
***************************************************/
168
static VABufferID seq_parameter = VA_INVALID_ID; /*Sequence level parameter*/
169
static VABufferID pic_parameter = VA_INVALID_ID; /*Picture level parameter*/
170
static VABufferID slice_parameter = VA_INVALID_ID; /*Slice level parameter, multil slices*/
171
static VABufferID coded_buf = VA_INVALID_ID; /*Output buffer, compressed data*/
174
#define SID_INPUT_PICTURE 0
175
#define SID_REFERENCE_PICTURE 1
176
#define SID_RECON_PICTURE 2
177
static VASurfaceID surface_ids[SID_NUMBER];
179
/***************************************************/
181
static void alloc_encode_resource()
184
seq_parameter = VA_INVALID_ID;
185
pic_parameter = VA_INVALID_ID;
186
slice_parameter = VA_INVALID_ID;
188
//1. Create sequence parameter set
190
VAEncSequenceParameterBufferH264 seq_h264 = {0};
191
seq_h264.level_idc = 30;
192
seq_h264.picture_width_in_mbs = picture_width_in_mbs;
193
seq_h264.picture_height_in_mbs = picture_height_in_mbs;
194
seq_h264.bits_per_second = 384*1000;
195
seq_h264.initial_qp = qp_value;
197
va_status = vaCreateBuffer(va_dpy, context_id, VAEncSequenceParameterBufferType,
198
sizeof(seq_h264),1,&seq_h264,&seq_parameter);
199
CHECK_VASTATUS(va_status,"vaCreateBuffer");;
202
va_status = vaCreateSurfaces(va_dpy, picture_width, picture_height, VA_RT_FORMAT_YUV420, SID_NUMBER, &surface_ids[0]);
203
CHECK_VASTATUS(va_status, "vaCreateSurfaces");
204
//3. Create coded buffer
206
va_status = vaCreateBuffer(va_dpy,context_id,VAEncCodedBufferType, codedbuf_size, 1, NULL, &coded_buf);
207
CHECK_VASTATUS(va_status,"vaBeginPicture");
211
static void release_encode_resource()
213
//-3 Relese coded buffer
214
if (coded_buf != VA_INVALID_ID)
215
vaDestroyBuffer(va_dpy, coded_buf);
216
//-2 Release all the surfaces resource
217
vaDestroySurfaces(va_dpy, &surface_ids[0], SID_NUMBER);
218
//-1 Destory the sequence level parameter
219
if (seq_parameter != VA_INVALID_ID)
220
vaDestroyBuffer(va_dpy, seq_parameter);
224
static int get_coded_bitsteam_length(unsigned char *buffer, int buffer_length)
227
for (i = buffer_length - 1; i >= 0; i--) {
236
void SetWindowTitle(const char* title, ...)
239
va_start(args, title);
241
vsprintf(buf, title, args);
243
XSetStandardProperties(x11_display,win2, buf, buf, None, NULL, 0, NULL);
248
int encoder_init(int width, int height)
250
picture_width = width;
251
picture_height = height;
252
picture_width_in_mbs = (picture_width + 15) / 16;
253
picture_height_in_mbs = (picture_height + 15) / 16;
255
frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ;
256
codedbuf_size = picture_width * picture_height * 1.5;
257
create_encode_pipe();
258
alloc_encode_resource();
259
sock_ptr->send(picture_width);
260
sock_ptr->send(picture_height);
261
sock_ptr->send(picture_width_in_mbs-1);
262
sock_ptr->send(picture_height_in_mbs-1);
264
win2 = XCreateSimpleWindow(x11_display, RootWindow(x11_display, 0), 0, 0, win2_width, win2_height, 0, 0, WhitePixel(x11_display, 0));
265
XMapWindow(x11_display, win2);
266
if ((g_PX !=-1) && (g_PY !=-1)) {
267
XMoveWindow(x11_display, win2, g_PX, g_PY);
269
SetWindowTitle("Input: %dx%d [TCP] %s",picture_width,picture_height, device_settings);
270
XSync(x11_display, False);
277
release_encode_resource();
278
destory_encode_pipe();
282
/* 8x8 font 0-9 only - asm type format */
283
unsigned char mydigits[80] = {
285
0x0E,0x11,0x13,0x15,0x19,0x11,0x0E,0x00,
287
0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00,
289
0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,0x00,
291
0x1F,0x02,0x04,0x02,0x01,0x11,0x0E,0x00,
293
0x02,0x06,0x0A,0x12,0x1F,0x02,0x02,0x00,
295
0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E,0x00,
297
0x06,0x08,0x10,0x1E,0x11,0x11,0x0E,0x00,
299
0x1F,0x01,0x02,0x04,0x04,0x04,0x04,0x00,
301
0x1E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00,
303
0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C,0x00
308
static void ShowNumber(int num, unsigned char *buffer, VAImage *image)
312
unsigned char *dst_y;
313
unsigned char *dst_uv_line;
314
unsigned char *digits_ptr;
316
int maxlen = sprintf(buf, "%d", num);
318
for (int a=0; a<maxlen;a++) {
319
digits_ptr = &mydigits[(buf[a]-'0')*8];
320
for (int i=0; i<8; i++) {
321
unsigned char current = digits_ptr[i];
322
dst_y = (buffer+ image->offsets[0]) + ((i*2)*image->pitches[0])+(a*INTERSIZE);
323
dst_uv_line = (buffer + image->offsets[1]) + (i*image->pitches[1])+(a*INTERSIZE);
324
for (j=7; j>=0;j--) {
325
if ((current >>j) & 1) {
328
*dst_uv_line++ = MY_U;
329
*dst_uv_line++ = MY_V;
335
dst_y = (buffer+ image->offsets[0]) + (((i*2)+1)*image->pitches[0])+(a*INTERSIZE);
336
for (j=7; j>=0;j--) {
337
if ((current >>j) & 1) {
350
static void upload_yuv_to_surface(unsigned char *inbuf, VASurfaceID surface_id, unsigned int frame)
355
unsigned char *psrc = inbuf;
356
unsigned char *pdst = NULL;
357
unsigned char *dst_y, *dst_uv;
358
unsigned char *src_u, *src_v;
359
unsigned char *dst_uv_line = NULL;
361
va_status = vaDeriveImage(va_dpy, surface_id, &image);
362
va_status = vaMapBuffer(va_dpy, image.buf, &pbuffer);
363
pdst = (unsigned char *)pbuffer;
364
dst_uv_line = pdst + image.offsets[1];
365
dst_uv = dst_uv_line;
366
for (i=0; i<picture_height; i+=2) {
367
dst_y = (pdst + image.offsets[0]) + i*image.pitches[0];
368
for (j=0; j<(picture_width/2); ++j) {
369
*(dst_y++) = psrc[0];//y1;
370
*(dst_uv++) = psrc[1];//u;
371
*(dst_y++) = psrc[2];//y1;
372
*(dst_uv++) = psrc[3];//v;
375
dst_y = (pdst + image.offsets[0]) + (i+1)*image.pitches[0];
376
for (j=0; j<picture_width/2; ++j) {
377
*(dst_y++) = psrc[0];//y1;
378
*(dst_y++) = psrc[2];//y2;
381
dst_uv_line += image.pitches[1];
382
dst_uv = dst_uv_line;
385
ShowNumber(frame, (unsigned char *)pbuffer, &image);
387
va_status = vaUnmapBuffer(va_dpy, image.buf);
388
CHECK_VASTATUS(va_status,"vaUnmapBuffer");
389
va_status = vaDestroyImage(va_dpy, image.image_id);
390
CHECK_VASTATUS(va_status,"vaDestroyImage");
392
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);
393
CHECK_VASTATUS(va_status,"vaPutSurface");
398
static void prepare_input(unsigned char *buffer, int intra_slice, unsigned int frame)
400
static VAEncPictureParameterBufferH264 pic_h264;
401
static VAEncSliceParameterBuffer slice_h264;
404
VACodedBufferSegment *coded_buffer_segment = NULL;
405
unsigned char *coded_mem;
407
va_status = vaRenderPicture(va_dpy, context_id, &seq_parameter, 1);
408
CHECK_VASTATUS(va_status,"vaRenderPicture");;
409
// Copy Image to target surface according input YUV data.
410
upload_yuv_to_surface(buffer, surface_ids[SID_INPUT_PICTURE], frame);
412
pic_h264.reference_picture = surface_ids[SID_REFERENCE_PICTURE];
413
pic_h264.reconstructed_picture = surface_ids[SID_RECON_PICTURE];
414
pic_h264.coded_buf = coded_buf;
415
pic_h264.picture_width = picture_width;
416
pic_h264.picture_height = picture_height;
417
pic_h264.last_picture = 0;
418
if (pic_parameter != VA_INVALID_ID) {
419
vaDestroyBuffer(va_dpy, pic_parameter);
421
va_status = vaCreateBuffer(va_dpy, context_id,VAEncPictureParameterBufferType,
422
sizeof(pic_h264),1,&pic_h264,&pic_parameter);
423
CHECK_VASTATUS(va_status,"vaCreateBuffer");
424
va_status = vaRenderPicture(va_dpy,context_id, &pic_parameter, 1);
425
CHECK_VASTATUS(va_status,"vaRenderPicture");
427
va_status = vaMapBuffer(va_dpy,coded_buf,(void **)(&coded_buffer_segment));
428
CHECK_VASTATUS(va_status,"vaMapBuffer");
429
coded_mem = (unsigned char*)coded_buffer_segment->buf;
430
memset(coded_mem, 0, coded_buffer_segment->size);
431
vaUnmapBuffer(va_dpy, coded_buf);
433
slice_h264.start_row_number = 0;
434
slice_h264.slice_height = picture_height/16; /* Measured by MB */
435
slice_h264.slice_flags.bits.is_intra = intra_slice;
436
slice_h264.slice_flags.bits.disable_deblocking_filter_idc = 0;
437
if ( slice_parameter != VA_INVALID_ID) {
438
vaDestroyBuffer(va_dpy, slice_parameter);
440
va_status = vaCreateBuffer(va_dpy,context_id,VAEncSliceParameterBufferType,
441
sizeof(slice_h264),1,&slice_h264,&slice_parameter);
442
CHECK_VASTATUS(va_status,"vaCreateBuffer");;
443
va_status = vaRenderPicture(va_dpy,context_id, &slice_parameter, 1);
444
CHECK_VASTATUS(va_status,"vaRenderPicture");
446
// Prepare for next picture
447
tempID = surface_ids[SID_RECON_PICTURE];
448
surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE];
449
surface_ids[SID_REFERENCE_PICTURE] = tempID;
452
static void send_slice_data(unsigned int frcount, int slice_type)
454
VACodedBufferSegment *coded_buffer_segment;
455
unsigned char *coded_mem;
456
int i, slice_data_length;
459
VASurfaceStatus surface_status;
460
int is_cabac = (entropy_coding_mode_flag == ENTROPY_MODE_CABAC);
461
va_status = vaSyncSurface(va_dpy, surface_ids[SID_INPUT_PICTURE]);
462
CHECK_VASTATUS(va_status,"vaSyncSurface");
463
surface_status = (VASurfaceStatus)0;
464
va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[SID_INPUT_PICTURE], &surface_status);
465
CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
466
va_status = vaMapBuffer(va_dpy, coded_buf, (void **)(&coded_buffer_segment));
467
CHECK_VASTATUS(va_status,"vaMapBuffer");
468
coded_mem = (unsigned char*)coded_buffer_segment->buf;
469
sock_ptr->send(frcount);
470
sock_ptr->send(slice_type);
473
if (!coded_buffer_segment->next) {
474
slice_data_length = get_coded_bitsteam_length(coded_mem, codedbuf_size);
476
/* Fixme me - to do: loop to each block and calculate the real data_lenght */
480
printf("T=%d BS=%8d SZ=%8d C=%d\n", slice_type, codedbuf_size, slice_data_length, frcount);
481
}sock_ptr->send(slice_data_length);
482
sock_ptr->send((unsigned char*)coded_mem, slice_data_length);
487
vaUnmapBuffer(va_dpy, coded_buf);
491
int encode_frame(unsigned char *inbuf)
493
static unsigned int framecount = 0;
494
int is_intra = (framecount % 30 == 0);
495
if (g_Force_P_Only) {
499
va_status = vaBeginPicture(va_dpy, context_id, surface_ids[SID_INPUT_PICTURE]);
500
CHECK_VASTATUS(va_status,"vaBeginPicture");
501
prepare_input(inbuf, is_intra, framecount);
502
va_status = vaEndPicture(va_dpy,context_id);
503
CHECK_VASTATUS(va_status,"vaRenderPicture");
504
send_slice_data(framecount, is_intra ? SLICE_TYPE_I : SLICE_TYPE_P);