a8474c006282b61236bbb01e8418e40e782ddd1f
[profile/ivi/libva.git] / test / encode / h264encode.c
1 /*
2  * Copyright (c) 2007-2013 Intel Corporation. All Rights Reserved.
3  *
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:
11  * 
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  * 
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "sysdeps.h"
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <getopt.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <fcntl.h>
34 #include <assert.h>
35 #include <pthread.h>
36 #include <va/va.h>
37 #include <va/va_enc_h264.h>
38 #include "va_display.h"
39
40 #define CHECK_VASTATUS(va_status,func)                                  \
41     if (va_status != VA_STATUS_SUCCESS) {                               \
42         fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
43         exit(1);                                                        \
44     }
45
46 #include "../loadsurface.h"
47
48 #define NAL_REF_IDC_NONE        0
49 #define NAL_REF_IDC_LOW         1
50 #define NAL_REF_IDC_MEDIUM      2
51 #define NAL_REF_IDC_HIGH        3
52
53 #define NAL_NON_IDR             1
54 #define NAL_IDR                 5
55 #define NAL_SPS                 7
56 #define NAL_PPS                 8
57 #define NAL_SEI                 6
58
59 #define SLICE_TYPE_P            0
60 #define SLICE_TYPE_B            1
61 #define SLICE_TYPE_I            2
62
63 #define ENTROPY_MODE_CAVLC      0
64 #define ENTROPY_MODE_CABAC      1
65
66 #define PROFILE_IDC_BASELINE    66
67 #define PROFILE_IDC_MAIN        77
68 #define PROFILE_IDC_HIGH        100
69    
70 #define BITSTREAM_ALLOCATE_STEPPING     4096
71
72
73 #define SRC_SURFACE_NUM 16 /* 16 surfaces for source YUV */
74 #define REF_SURFACE_NUM 16 /* 16 surfaces for reference */
75 static  VADisplay va_dpy;
76 static  VAProfile h264_profile;
77 static  VAConfigAttrib attrib[VAConfigAttribTypeMax];
78 static  VAConfigAttrib config_attrib[VAConfigAttribTypeMax];
79 static  int config_attrib_num = 0;
80 static  VASurfaceID src_surface[SRC_SURFACE_NUM];
81 static  VABufferID coded_buf[SRC_SURFACE_NUM];
82 static  VASurfaceID ref_surface[REF_SURFACE_NUM];
83 static  VAConfigID config_id;
84 static  VAContextID context_id;
85 static  VAEncSequenceParameterBufferH264 seq_param;
86 static  VAEncPictureParameterBufferH264 pic_param;
87 static  VAEncSliceParameterBufferH264 slice_param;
88 static  VAPictureH264 LLastCurrPic, LastCurrPic, CurrentCurrPic; /* One reference for P and two for B */
89
90 static  int constraint_set_flag = 0;
91 static  int h264_packedheader = 0; /* support pack header? */
92 static  int h264_maxref = 3;
93 static  char *coded_fn = NULL, *srcyuv_fn = NULL, *recyuv_fn = NULL;
94 static  FILE *coded_fp = NULL, *srcyuv_fp = NULL, *recyuv_fp = NULL;
95 static  unsigned long long srcyuv_frames = 0;
96 static  unsigned int srcyuv_fourcc = VA_FOURCC_NV12;
97
98 static  int frame_width = 176;
99 static  int frame_height = 144;
100 static  int frame_rate = 30;
101 static  unsigned int frame_count = 60;
102 static  unsigned int frame_coded = 0;
103 static  unsigned int frame_bitrate = 0;
104 static  unsigned int frame_slices = 1;
105 static  int initial_qp = 28;
106 static  int minimal_qp = 0;
107 static  int intra_period = 30;
108 static  int intra_idr_period = 60;
109 static  int ip_period = 1;
110 static  int rc_mode = VA_RC_VBR;
111 static  int slice_refoverride = 0;
112 static  unsigned long long current_frame_encoding = 0;
113 static  unsigned long long current_frame_display = 0;
114 static  int current_frame_num = 0;
115 static  int current_frame_type;
116
117 /* thread to save coded data/upload source YUV */
118 struct storage_task_t {
119     void *next;
120     unsigned long long display_order;
121     unsigned long long encode_order;
122 };
123 static  struct storage_task_t *storage_task_header = NULL, *storage_task_tail = NULL;
124 #define SRC_SURFACE_IN_ENCODING 0
125 #define SRC_SURFACE_IN_STORAGE  1
126 static  int srcsurface_status[SRC_SURFACE_NUM];
127 static  int encode_syncmode = 0;
128 static  pthread_mutex_t encode_mutex = PTHREAD_MUTEX_INITIALIZER;
129 static  pthread_cond_t  encode_cond = PTHREAD_COND_INITIALIZER;
130 static  pthread_t encode_thread;
131
132 /* for performance profiling */
133 static unsigned int UploadPictureTicks=0;
134 static unsigned int BeginPictureTicks=0;
135 static unsigned int RenderPictureTicks=0;
136 static unsigned int EndPictureTicks=0;
137 static unsigned int SyncPictureTicks=0;
138 static unsigned int SavePictureTicks=0;
139 static unsigned int TotalTicks=0;
140
141 struct __bitstream {
142     unsigned int *buffer;
143     int bit_offset;
144     int max_size_in_dword;
145 };
146 typedef struct __bitstream bitstream;
147
148
149 static unsigned int 
150 va_swap32(unsigned int val)
151 {
152     unsigned char *pval = (unsigned char *)&val;
153
154     return ((pval[0] << 24)     |
155             (pval[1] << 16)     |
156             (pval[2] << 8)      |
157             (pval[3] << 0));
158 }
159
160 static void
161 bitstream_start(bitstream *bs)
162 {
163     bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
164     bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
165     bs->bit_offset = 0;
166 }
167
168 static void
169 bitstream_end(bitstream *bs)
170 {
171     int pos = (bs->bit_offset >> 5);
172     int bit_offset = (bs->bit_offset & 0x1f);
173     int bit_left = 32 - bit_offset;
174
175     if (bit_offset) {
176         bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
177     }
178 }
179  
180 static void
181 bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits)
182 {
183     int pos = (bs->bit_offset >> 5);
184     int bit_offset = (bs->bit_offset & 0x1f);
185     int bit_left = 32 - bit_offset;
186
187     if (!size_in_bits)
188         return;
189
190     bs->bit_offset += size_in_bits;
191
192     if (bit_left > size_in_bits) {
193         bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
194     } else {
195         size_in_bits -= bit_left;
196         bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
197         bs->buffer[pos] = va_swap32(bs->buffer[pos]);
198
199         if (pos + 1 == bs->max_size_in_dword) {
200             bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
201             bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int));
202         }
203
204         bs->buffer[pos + 1] = val;
205     }
206 }
207
208 static void
209 bitstream_put_ue(bitstream *bs, unsigned int val)
210 {
211     int size_in_bits = 0;
212     int tmp_val = ++val;
213
214     while (tmp_val) {
215         tmp_val >>= 1;
216         size_in_bits++;
217     }
218
219     bitstream_put_ui(bs, 0, size_in_bits - 1); // leading zero
220     bitstream_put_ui(bs, val, size_in_bits);
221 }
222
223 static void
224 bitstream_put_se(bitstream *bs, int val)
225 {
226     unsigned int new_val;
227
228     if (val <= 0)
229         new_val = -2 * val;
230     else
231         new_val = 2 * val - 1;
232
233     bitstream_put_ue(bs, new_val);
234 }
235
236 static void
237 bitstream_byte_aligning(bitstream *bs, int bit)
238 {
239     int bit_offset = (bs->bit_offset & 0x7);
240     int bit_left = 8 - bit_offset;
241     int new_val;
242
243     if (!bit_offset)
244         return;
245
246     assert(bit == 0 || bit == 1);
247
248     if (bit)
249         new_val = (1 << bit_left) - 1;
250     else
251         new_val = 0;
252
253     bitstream_put_ui(bs, new_val, bit_left);
254 }
255
256 static void 
257 rbsp_trailing_bits(bitstream *bs)
258 {
259     bitstream_put_ui(bs, 1, 1);
260     bitstream_byte_aligning(bs, 0);
261 }
262
263 static void nal_start_code_prefix(bitstream *bs)
264 {
265     bitstream_put_ui(bs, 0x00000001, 32);
266 }
267
268 static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type)
269 {
270     bitstream_put_ui(bs, 0, 1);                /* forbidden_zero_bit: 0 */
271     bitstream_put_ui(bs, nal_ref_idc, 2);
272     bitstream_put_ui(bs, nal_unit_type, 5);
273 }
274
275 static void sps_rbsp(bitstream *bs)
276 {
277     int profile_idc = PROFILE_IDC_BASELINE;
278
279     if (h264_profile  == VAProfileH264High)
280         profile_idc = PROFILE_IDC_HIGH;
281     else if (h264_profile  == VAProfileH264Main)
282         profile_idc = PROFILE_IDC_MAIN;
283
284     bitstream_put_ui(bs, profile_idc, 8);               /* profile_idc */
285     bitstream_put_ui(bs, !!(constraint_set_flag & 1), 1);                         /* constraint_set0_flag */
286     bitstream_put_ui(bs, !!(constraint_set_flag & 2), 1);                         /* constraint_set1_flag */
287     bitstream_put_ui(bs, !!(constraint_set_flag & 4), 1);                         /* constraint_set2_flag */
288     bitstream_put_ui(bs, !!(constraint_set_flag & 8), 1);                         /* constraint_set3_flag */
289     bitstream_put_ui(bs, 0, 4);                         /* reserved_zero_4bits */
290     bitstream_put_ui(bs, seq_param.level_idc, 8);      /* level_idc */
291     bitstream_put_ue(bs, seq_param.seq_parameter_set_id);      /* seq_parameter_set_id */
292
293     if ( profile_idc == PROFILE_IDC_HIGH) {
294         bitstream_put_ue(bs, 1);        /* chroma_format_idc = 1, 4:2:0 */ 
295         bitstream_put_ue(bs, 0);        /* bit_depth_luma_minus8 */
296         bitstream_put_ue(bs, 0);        /* bit_depth_chroma_minus8 */
297         bitstream_put_ui(bs, 0, 1);     /* qpprime_y_zero_transform_bypass_flag */
298         bitstream_put_ui(bs, 0, 1);     /* seq_scaling_matrix_present_flag */
299     }
300
301     bitstream_put_ue(bs, seq_param.seq_fields.bits.log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */
302     bitstream_put_ue(bs, seq_param.seq_fields.bits.pic_order_cnt_type);        /* pic_order_cnt_type */
303
304     if (seq_param.seq_fields.bits.pic_order_cnt_type == 0)
305         bitstream_put_ue(bs, seq_param.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);     /* log2_max_pic_order_cnt_lsb_minus4 */
306     else {
307         assert(0);
308     }
309
310     bitstream_put_ue(bs, seq_param.max_num_ref_frames);        /* num_ref_frames */
311     bitstream_put_ui(bs, 0, 1);                                 /* gaps_in_frame_num_value_allowed_flag */
312
313     bitstream_put_ue(bs, seq_param.picture_width_in_mbs - 1);  /* pic_width_in_mbs_minus1 */
314     bitstream_put_ue(bs, seq_param.picture_height_in_mbs - 1); /* pic_height_in_map_units_minus1 */
315     bitstream_put_ui(bs, seq_param.seq_fields.bits.frame_mbs_only_flag, 1);    /* frame_mbs_only_flag */
316
317     if (!seq_param.seq_fields.bits.frame_mbs_only_flag) {
318         assert(0);
319     }
320
321     bitstream_put_ui(bs, seq_param.seq_fields.bits.direct_8x8_inference_flag, 1);      /* direct_8x8_inference_flag */
322     bitstream_put_ui(bs, seq_param.frame_cropping_flag, 1);            /* frame_cropping_flag */
323
324     if (seq_param.frame_cropping_flag) {
325         bitstream_put_ue(bs, seq_param.frame_crop_left_offset);        /* frame_crop_left_offset */
326         bitstream_put_ue(bs, seq_param.frame_crop_right_offset);       /* frame_crop_right_offset */
327         bitstream_put_ue(bs, seq_param.frame_crop_top_offset);         /* frame_crop_top_offset */
328         bitstream_put_ue(bs, seq_param.frame_crop_bottom_offset);      /* frame_crop_bottom_offset */
329     }
330     
331     //if ( frame_bit_rate < 0 ) { //TODO EW: the vui header isn't correct
332     if ( 1 ) {
333         bitstream_put_ui(bs, 0, 1); /* vui_parameters_present_flag */
334     } else {
335         bitstream_put_ui(bs, 1, 1); /* vui_parameters_present_flag */
336         bitstream_put_ui(bs, 0, 1); /* aspect_ratio_info_present_flag */
337         bitstream_put_ui(bs, 0, 1); /* overscan_info_present_flag */
338         bitstream_put_ui(bs, 0, 1); /* video_signal_type_present_flag */
339         bitstream_put_ui(bs, 0, 1); /* chroma_loc_info_present_flag */
340         bitstream_put_ui(bs, 1, 1); /* timing_info_present_flag */
341         {
342             bitstream_put_ui(bs, 15, 32);
343             bitstream_put_ui(bs, 900, 32);
344             bitstream_put_ui(bs, 1, 1);
345         }
346         bitstream_put_ui(bs, 1, 1); /* nal_hrd_parameters_present_flag */
347         {
348             // hrd_parameters 
349             bitstream_put_ue(bs, 0);    /* cpb_cnt_minus1 */
350             bitstream_put_ui(bs, 4, 4); /* bit_rate_scale */
351             bitstream_put_ui(bs, 6, 4); /* cpb_size_scale */
352            
353             bitstream_put_ue(bs, frame_bitrate - 1); /* bit_rate_value_minus1[0] */
354             bitstream_put_ue(bs, frame_bitrate*8 - 1); /* cpb_size_value_minus1[0] */
355             bitstream_put_ui(bs, 1, 1);  /* cbr_flag[0] */
356
357             bitstream_put_ui(bs, 23, 5);   /* initial_cpb_removal_delay_length_minus1 */
358             bitstream_put_ui(bs, 23, 5);   /* cpb_removal_delay_length_minus1 */
359             bitstream_put_ui(bs, 23, 5);   /* dpb_output_delay_length_minus1 */
360             bitstream_put_ui(bs, 23, 5);   /* time_offset_length  */
361         }
362         bitstream_put_ui(bs, 0, 1);   /* vcl_hrd_parameters_present_flag */
363         bitstream_put_ui(bs, 0, 1);   /* low_delay_hrd_flag */ 
364
365         bitstream_put_ui(bs, 0, 1); /* pic_struct_present_flag */
366         bitstream_put_ui(bs, 0, 1); /* bitstream_restriction_flag */
367     }
368
369     rbsp_trailing_bits(bs);     /* rbsp_trailing_bits */
370 }
371
372
373 static void pps_rbsp(bitstream *bs)
374 {
375     bitstream_put_ue(bs, pic_param.pic_parameter_set_id);      /* pic_parameter_set_id */
376     bitstream_put_ue(bs, pic_param.seq_parameter_set_id);      /* seq_parameter_set_id */
377
378     bitstream_put_ui(bs, pic_param.pic_fields.bits.entropy_coding_mode_flag, 1);  /* entropy_coding_mode_flag */
379
380     bitstream_put_ui(bs, 0, 1);                         /* pic_order_present_flag: 0 */
381
382     bitstream_put_ue(bs, 0);                            /* num_slice_groups_minus1 */
383
384     bitstream_put_ue(bs, pic_param.num_ref_idx_l0_active_minus1);      /* num_ref_idx_l0_active_minus1 */
385     bitstream_put_ue(bs, pic_param.num_ref_idx_l1_active_minus1);      /* num_ref_idx_l1_active_minus1 1 */
386
387     bitstream_put_ui(bs, pic_param.pic_fields.bits.weighted_pred_flag, 1);     /* weighted_pred_flag: 0 */
388     bitstream_put_ui(bs, pic_param.pic_fields.bits.weighted_bipred_idc, 2);     /* weighted_bipred_idc: 0 */
389
390     bitstream_put_se(bs, pic_param.pic_init_qp - 26);  /* pic_init_qp_minus26 */
391     bitstream_put_se(bs, 0);                            /* pic_init_qs_minus26 */
392     bitstream_put_se(bs, 0);                            /* chroma_qp_index_offset */
393
394     bitstream_put_ui(bs, pic_param.pic_fields.bits.deblocking_filter_control_present_flag, 1); /* deblocking_filter_control_present_flag */
395     bitstream_put_ui(bs, 0, 1);                         /* constrained_intra_pred_flag */
396     bitstream_put_ui(bs, 0, 1);                         /* redundant_pic_cnt_present_flag */
397     
398     /* more_rbsp_data */
399     bitstream_put_ui(bs, pic_param.pic_fields.bits.transform_8x8_mode_flag, 1);    /*transform_8x8_mode_flag */
400     bitstream_put_ui(bs, 0, 1);                         /* pic_scaling_matrix_present_flag */
401     bitstream_put_se(bs, pic_param.second_chroma_qp_index_offset );    /*second_chroma_qp_index_offset */
402
403     rbsp_trailing_bits(bs);
404 }
405
406
407 static int
408 build_packed_pic_buffer(unsigned char **header_buffer)
409 {
410     bitstream bs;
411
412     bitstream_start(&bs);
413     nal_start_code_prefix(&bs);
414     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
415     pps_rbsp(&bs);
416     bitstream_end(&bs);
417
418     *header_buffer = (unsigned char *)bs.buffer;
419     return bs.bit_offset;
420 }
421
422 static int
423 build_packed_seq_buffer(unsigned char **header_buffer)
424 {
425     bitstream bs;
426
427     bitstream_start(&bs);
428     nal_start_code_prefix(&bs);
429     nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
430     sps_rbsp(&bs);
431     bitstream_end(&bs);
432
433     *header_buffer = (unsigned char *)bs.buffer;
434     return bs.bit_offset;
435 }
436
437 static int 
438 build_packed_sei_buffer_timing(unsigned int init_cpb_removal_length,
439                                 unsigned int init_cpb_removal_delay,
440                                 unsigned int init_cpb_removal_delay_offset,
441                                 unsigned int cpb_removal_length,
442                                 unsigned int cpb_removal_delay,
443                                 unsigned int dpb_output_length,
444                                 unsigned int dpb_output_delay,
445                                 unsigned char **sei_buffer)
446 {
447     unsigned char *byte_buf;
448     int bp_byte_size, i, pic_byte_size;
449
450     bitstream nal_bs;
451     bitstream sei_bp_bs, sei_pic_bs;
452
453     bitstream_start(&sei_bp_bs);
454     bitstream_put_ue(&sei_bp_bs, 0);       /*seq_parameter_set_id*/
455     bitstream_put_ui(&sei_bp_bs, init_cpb_removal_delay, cpb_removal_length); 
456     bitstream_put_ui(&sei_bp_bs, init_cpb_removal_delay_offset, cpb_removal_length); 
457     if ( sei_bp_bs.bit_offset & 0x7) {
458         bitstream_put_ui(&sei_bp_bs, 1, 1);
459     }
460     bitstream_end(&sei_bp_bs);
461     bp_byte_size = (sei_bp_bs.bit_offset + 7) / 8;
462     
463     bitstream_start(&sei_pic_bs);
464     bitstream_put_ui(&sei_pic_bs, cpb_removal_delay, cpb_removal_length); 
465     bitstream_put_ui(&sei_pic_bs, dpb_output_delay, dpb_output_length); 
466     if ( sei_pic_bs.bit_offset & 0x7) {
467         bitstream_put_ui(&sei_pic_bs, 1, 1);
468     }
469     bitstream_end(&sei_pic_bs);
470     pic_byte_size = (sei_pic_bs.bit_offset + 7) / 8;
471     
472     bitstream_start(&nal_bs);
473     nal_start_code_prefix(&nal_bs);
474     nal_header(&nal_bs, NAL_REF_IDC_NONE, NAL_SEI);
475
476         /* Write the SEI buffer period data */    
477     bitstream_put_ui(&nal_bs, 0, 8);
478     bitstream_put_ui(&nal_bs, bp_byte_size, 8);
479     
480     byte_buf = (unsigned char *)sei_bp_bs.buffer;
481     for(i = 0; i < bp_byte_size; i++) {
482         bitstream_put_ui(&nal_bs, byte_buf[i], 8);
483     }
484     free(byte_buf);
485         /* write the SEI timing data */
486     bitstream_put_ui(&nal_bs, 0x01, 8);
487     bitstream_put_ui(&nal_bs, pic_byte_size, 8);
488     
489     byte_buf = (unsigned char *)sei_pic_bs.buffer;
490     for(i = 0; i < pic_byte_size; i++) {
491         bitstream_put_ui(&nal_bs, byte_buf[i], 8);
492     }
493     free(byte_buf);
494
495     rbsp_trailing_bits(&nal_bs);
496     bitstream_end(&nal_bs);
497
498     *sei_buffer = (unsigned char *)nal_bs.buffer; 
499    
500     return nal_bs.bit_offset;
501 }
502
503
504
505 /*
506  * Helper function for profiling purposes
507  */
508 static unsigned int GetTickCount()
509 {
510     struct timeval tv;
511     if (gettimeofday(&tv, NULL))
512         return 0;
513     return tv.tv_usec/1000+tv.tv_sec*1000;
514 }
515
516 /*
517   Assume frame sequence is: Frame#0,#1,#2,...,#M,...,#X,... (encoding order)
518   1) period between Frame #X and Frame #N = #X - #N
519   2) 0 means infinite for intra_period/intra_idr_period, and 0 is invalid for ip_period
520   3) intra_idr_period % intra_period (intra_period > 0) and intra_period % ip_period must be 0
521   4) intra_period and intra_idr_period take precedence over ip_period
522   5) if ip_period > 1, intra_period and intra_idr_period are not  the strict periods 
523      of I/IDR frames, see bellow examples
524   -------------------------------------------------------------------
525   intra_period intra_idr_period ip_period frame sequence (intra_period/intra_idr_period/ip_period)
526   0            ignored          1          IDRPPPPPPP ...     (No IDR/I any more)
527   0            ignored        >=2          IDR(PBB)(PBB)...   (No IDR/I any more)
528   1            0                ignored    IDRIIIIIII...      (No IDR any more)
529   1            1                ignored    IDR IDR IDR IDR...
530   1            >=2              ignored    IDRII IDRII IDR... (1/3/ignore)
531   >=2          0                1          IDRPPP IPPP I...   (3/0/1)
532   >=2          0              >=2          IDR(PBB)(PBB)(IBB) (6/0/3)
533                                               (PBB)(IBB)(PBB)(IBB)... 
534   >=2          >=2              1          IDRPPPPP IPPPPP IPPPPP (6/18/1)
535                                            IDRPPPPP IPPPPP IPPPPP...
536   >=2          >=2              >=2        {IDR(PBB)(PBB)(IBB)(PBB)(IBB)(PBB)} (6/18/3)
537                                            {IDR(PBB)(PBB)(IBB)(PBB)(IBB)(PBB)}...
538                                            {IDR(PBB)(PBB)(IBB)(PBB)}           (6/12/3)
539                                            {IDR(PBB)(PBB)(IBB)(PBB)}...
540                                            {IDR(PBB)(PBB)}                     (6/6/3)
541                                            {IDR(PBB)(PBB)}.
542 */
543
544 /*
545  * Return displaying order with specified periods and encoding order
546  * displaying_order: displaying order
547  * frame_type: frame type 
548  */
549 #define FRAME_P 0
550 #define FRAME_B 1
551 #define FRAME_I 2
552 #define FRAME_IDR 7
553 void encoding2display_order(
554     unsigned long long encoding_order,int intra_period,
555     int intra_idr_period,int ip_period,
556     unsigned long long *displaying_order,
557     int *frame_type)
558 {
559     int encoding_order_gop = 0;
560
561     if (intra_period == 1) { /* all are I/IDR frames */
562         *displaying_order = encoding_order;
563         if (intra_idr_period == 0)
564             *frame_type = (encoding_order == 0)?FRAME_IDR:FRAME_I;
565         else
566             *frame_type = (encoding_order % intra_idr_period == 0)?FRAME_IDR:FRAME_I;
567         return;
568     }
569
570     if (intra_period == 0)
571         intra_idr_period = 0;
572
573     /* new sequence like
574      * IDR PPPPP IPPPPP
575      * IDR (PBB)(PBB)(IBB)(PBB)
576      */
577     encoding_order_gop = (intra_idr_period == 0)? encoding_order:
578         (encoding_order % (intra_idr_period + ((ip_period == 1)?0:1)));
579          
580     if (encoding_order_gop == 0) { /* the first frame */
581         *frame_type = FRAME_IDR;
582         *displaying_order = encoding_order;
583     } else if (((encoding_order_gop - 1) % ip_period) != 0) { /* B frames */
584         *frame_type = FRAME_B;
585         *displaying_order = encoding_order - 1;
586     } else if ((intra_period != 0) && /* have I frames */
587                (encoding_order_gop >= 2) &&
588                ((ip_period == 1 && encoding_order_gop % intra_period == 0) || /* for IDR PPPPP IPPPP */
589                 /* for IDR (PBB)(PBB)(IBB) */
590                 (ip_period >= 2 && ((encoding_order_gop - 1) / ip_period % (intra_period / ip_period)) == 0))) {
591         *frame_type = FRAME_I;
592         *displaying_order = encoding_order + ip_period - 1;
593     } else {
594         *frame_type = FRAME_P;
595         *displaying_order = encoding_order + ip_period - 1;
596     }
597 }
598
599
600 static char *fourcc_to_string(int fourcc)
601 {
602     switch (fourcc) {
603     case VA_FOURCC_NV12:
604         return "NONE";
605     case VA_FOURCC_IYUV:
606         return "IYUV";
607     case VA_FOURCC_YV12:
608         return "YV12";
609     case VA_FOURCC_UYVY:
610         return "UYVY";
611     default:
612         return "Unknown";
613     }
614 }
615
616 static int string_to_fourcc(char *str)
617 {
618     int fourcc;
619     
620     if (strncmp(str, "NV12", 4))
621         fourcc = VA_FOURCC_NV12;
622     else if (strncmp(str, "IYUV", 4))
623         fourcc = VA_FOURCC_IYUV;
624     else if (strncmp(str, "YV12", 4))
625         fourcc = VA_FOURCC_YV12;
626     else if (strncmp(str, "UYVY", 4))
627         fourcc = VA_FOURCC_UYVY;
628     else {
629         printf("Unknow FOURCC\n");
630         fourcc = -1;
631     }
632     return fourcc;
633 }
634
635
636 static char *rc_to_string(int rcmode)
637 {
638     switch (rc_mode) {
639     case VA_RC_NONE:
640         return "NONE";
641     case VA_RC_CBR:
642         return "CBR";
643     case VA_RC_VBR:
644         return "VBR";
645     case VA_RC_VCM:
646         return "VCM";
647     case VA_RC_CQP:
648         return "CQP";
649     case VA_RC_VBR_CONSTRAINED:
650         return "VBR_CONSTRAINED";
651     default:
652         return "Unknown";
653     }
654 }
655
656 static int string_to_rc(char *str)
657 {
658     int rc_mode;
659     
660     if (strncmp(str, "NONE", 4))
661         rc_mode = VA_RC_NONE;
662     else if (strncmp(str, "CBR", 3))
663         rc_mode = VA_RC_CBR;
664     else if (strncmp(str, "VBR", 3))
665         rc_mode = VA_RC_VBR;
666     else if (strncmp(str, "VCM", 3))
667         rc_mode = VA_RC_VCM;
668     else if (strncmp(str, "CQP", 3))
669         rc_mode = VA_RC_CQP;
670     else if (strncmp(str, "VBR_CONSTRAINED", 15))
671         rc_mode = VA_RC_VBR_CONSTRAINED;
672     else {
673         printf("Unknow RC mode\n");
674         rc_mode = -1;
675     }
676     return rc_mode;
677 }
678
679
680 static int print_help(void)
681 {
682     printf("./h264encode <options>\n");
683     printf("   -w <width> -h <height>\n");
684     printf("   -n <frame number>\n");
685     printf("   -o <coded file>\n");
686     printf("   -f <frame rate>\n");
687     printf("   --intra_period <number>\n");
688     printf("   --idr_period <number>\n");
689     printf("   --ip_period <number>\n");
690     printf("   --bitrate <bitrate>\n");
691     printf("   --initialqp <number>\n");
692     printf("   --minqp <number>\n");
693     printf("   --rcmode <NONE|CBR|VBR|VCM|CQP|VBR_CONTRAINED>\n");
694     printf("   --refoverride: use VAEncSliceParameterBufferH264 to override reference frames\n");
695     printf("   --syncmode: sequentially upload source, encoding, save result, no multi-thread\n");
696     printf("   --srcyuv <filename> load YUV from a file\n");
697     printf("   --fourcc <NV12|IYUV|I420|YV12> source YUV fourcc\n");
698
699     return 0;
700 }
701
702 static int process_cmdline(int argc, char *argv[])
703 {
704     char c;
705     const struct option long_opts[] = {
706         {"bitrate", required_argument, NULL, 1 },
707         {"minqp", required_argument, NULL, 2 },
708         {"initialqp", required_argument, NULL, 3 },
709         {"intra_period", required_argument, NULL, 4 },
710         {"idr_period", required_argument, NULL, 5 },
711         {"ip_period", required_argument, NULL, 6 },
712         {"rcmode", required_argument, NULL, 7 },
713         {"refoverride", no_argument, NULL, 8 },
714         {"srcyuv", required_argument, NULL, 9 },
715         {"fourcc", required_argument, NULL, 10 },
716         {"syncmode", no_argument, NULL, 11 },
717         {NULL, no_argument, NULL, 0 }};
718     int long_index;
719     
720     while ((c =getopt_long_only(argc,argv,"w:h:n:f:o:?",long_opts,&long_index)) != EOF) {
721         switch (c) {
722         case 'w':
723             frame_width = atoi(optarg);
724             break;
725         case 'h':
726             frame_height = atoi(optarg);
727             break;
728         case 'n':
729             frame_count = atoi(optarg);
730             break;
731         case 'f':
732             frame_rate = atoi(optarg);
733             break;
734         case 'o':
735             coded_fn = strdup(optarg);
736             break;
737         case 1:
738             frame_bitrate = atoi(optarg);
739             break;
740         case 2:
741             minimal_qp = atoi(optarg);
742             break;
743         case 3:
744             initial_qp = atoi(optarg);
745             break;
746         case 4:
747             intra_period = atoi(optarg);
748             break;
749         case 5:
750             intra_idr_period = atoi(optarg);
751             break;
752         case 6:
753             ip_period = atoi(optarg);
754             break;
755         case 7:
756             rc_mode = string_to_rc(optarg);
757             if (rc_mode < 0) {
758                 print_help();
759                 exit(1);
760             }
761             break;
762         case 8:
763             slice_refoverride = 1;
764             break;
765         case 9:
766             srcyuv_fn = strdup(optarg);
767             break;
768         case 10:
769             srcyuv_fourcc = string_to_fourcc(optarg);
770             if (srcyuv_fourcc < 0) {
771                 print_help();
772                 exit(1);
773             }
774             break;
775         case 11:
776             encode_syncmode = 1;
777             break;
778         case ':':
779         case '?':
780             print_help();
781             exit(0);
782         }
783     }
784
785     if (ip_period < 1) {
786         printf(" ip_period must be greater than 0\n");
787         exit(0);
788     }
789     if (intra_period != 1 && intra_period % ip_period != 0) {
790         printf(" intra_period must be a multiplier of ip_period\n");
791         exit(0);        
792     }
793     if (intra_period != 0 && intra_idr_period % intra_period != 0) {
794         printf(" intra_idr_period must be a multiplier of intra_period\n");
795         exit(0);        
796     }
797
798     if (frame_bitrate == 0) {
799         frame_bitrate = frame_width * frame_height * 12 * frame_rate / 50;
800         printf("Set bitrate to %dbps\n", frame_bitrate);
801     }
802     /* open source file */
803     if (srcyuv_fn) {
804         srcyuv_fp = fopen(srcyuv_fn,"r");
805     
806         if (srcyuv_fp == NULL)
807             printf("Open source YUV file %s failed, use auto-generated YUV data\n", srcyuv_fn);
808         else {
809             fseek(srcyuv_fp, 0L, SEEK_END);
810             srcyuv_frames = ftell(srcyuv_fp) / (frame_width * frame_height * 1.5);
811             printf("Source YUV file %s with %llu frames\n", srcyuv_fn, srcyuv_frames);
812         }
813     }
814     
815     if (coded_fn == NULL) {
816         struct stat buf;
817         if (stat("/tmp", &buf) == 0)
818             coded_fn = strdup("/tmp/test.264");
819         else if (stat("/sdcard", &buf) == 0)
820             coded_fn = strdup("/sdcard/test.264");
821         else
822             coded_fn = strdup("./test.264");
823     }
824     
825     /* store coded data into a file */
826     coded_fp = fopen(coded_fn,"w+");
827     if (coded_fp == NULL) {
828         printf("Open file %s failed, exit\n", coded_fn);
829         exit(1);
830     }
831
832     
833     return 0;
834 }
835
836 static int init_va(void)
837 {
838     VAProfile profile_list[]={VAProfileH264High,VAProfileH264Main,VAProfileH264Baseline,VAProfileH264ConstrainedBaseline};
839     VAEntrypoint entrypoints[VAEntrypointMax]={0};
840     int num_entrypoints,slice_entrypoint;
841     int support_encode = 0;    
842     int major_ver, minor_ver;
843     VAStatus va_status;
844     int i;
845
846     va_dpy = va_open_display();
847     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
848     CHECK_VASTATUS(va_status, "vaInitialize");
849
850     /* use the highest profile */
851     for (i = 0; i < sizeof(profile_list)/sizeof(profile_list[0]); i++) {
852         h264_profile = profile_list[i];
853         vaQueryConfigEntrypoints(va_dpy, h264_profile, entrypoints, &num_entrypoints);
854         for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
855             if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice) {
856                 support_encode = 1;
857                 break;
858             }
859         }
860         if (support_encode == 1)
861             break;
862     }
863     
864     if (support_encode == 0) {
865         printf("Can't find VAEntrypointEncSlice for H264 profiles\n");
866         exit(1);
867     } else {
868         switch (h264_profile) {
869             case VAProfileH264Baseline:
870                 printf("Use profile VAProfileH264Baseline\n");
871                 ip_period = 1;
872                 constraint_set_flag |= (1 << 0); /* Annex A.2.1 */
873                 break;
874             case VAProfileH264ConstrainedBaseline:
875                 printf("Use profile VAProfileH264ConstrainedBaseline\n");
876                 constraint_set_flag |= (1 << 0 | 1 << 1); /* Annex A.2.2 */
877                 ip_period = 1;
878                 break;
879
880             case VAProfileH264Main:
881                 printf("Use profile VAProfileH264Main\n");
882                 constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
883                 break;
884
885             case VAProfileH264High:
886                 constraint_set_flag |= (1 << 3); /* Annex A.2.4 */
887                 printf("Use profile VAProfileH264High\n");
888                 break;
889             default:
890                 printf("unknow profile. Set to Baseline");
891                 h264_profile = VAProfileH264Baseline;
892                 ip_period = 1;
893                 constraint_set_flag |= (1 << 0); /* Annex A.2.1 */
894                 break;
895         }
896     }
897
898     /* find out the format for the render target, and rate control mode */
899     for (i = 0; i < VAConfigAttribTypeMax; i++)
900         attrib[i].type = i;
901
902     va_status = vaGetConfigAttributes(va_dpy, h264_profile, VAEntrypointEncSlice,
903                                       &attrib[0], VAConfigAttribTypeMax);
904     CHECK_VASTATUS(va_status, "vaGetConfigAttributes");
905     /* check the interested configattrib */
906     if ((attrib[VAConfigAttribRTFormat].value & VA_RT_FORMAT_YUV420) == 0) {
907         printf("Not find desired YUV420 RT format\n");
908         exit(1);
909     } else {
910         config_attrib[config_attrib_num].type = VAConfigAttribRTFormat;
911         config_attrib[config_attrib_num].value = VA_RT_FORMAT_YUV420;
912         config_attrib_num++;
913     }
914     
915     if (attrib[VAConfigAttribRateControl].value != VA_ATTRIB_NOT_SUPPORTED) {
916         int tmp = attrib[VAConfigAttribRateControl].value;
917
918         printf("Supported rate control mode (0x%x):", tmp);
919         
920         if (tmp & VA_RC_NONE)
921             printf("NONE ");
922         if (tmp & VA_RC_CBR)
923             printf("CBR ");
924         if (tmp & VA_RC_VBR)
925             printf("VBR ");
926         if (tmp & VA_RC_VCM)
927             printf("VCM ");
928         if (tmp & VA_RC_CQP)
929             printf("CQP ");
930         if (tmp & VA_RC_VBR_CONSTRAINED)
931             printf("VBR_CONSTRAINED ");
932
933         printf("\n");
934
935         /* need to check if support rc_mode */
936         config_attrib[config_attrib_num].type = VAConfigAttribRateControl;
937         config_attrib[config_attrib_num].value = rc_mode;
938         config_attrib_num++;
939     }
940     
941
942     if (attrib[VAConfigAttribEncPackedHeaders].value != VA_ATTRIB_NOT_SUPPORTED) {
943         int tmp = attrib[VAConfigAttribEncPackedHeaders].value;
944
945         printf("Support VAConfigAttribEncPackedHeaders\n");
946         
947         h264_packedheader = 1;
948         config_attrib[config_attrib_num].type = VAConfigAttribEncPackedHeaders;
949         config_attrib[config_attrib_num].value = VA_ENC_PACKED_HEADER_NONE;
950         
951         if (tmp & VA_ENC_PACKED_HEADER_SEQUENCE) {
952             printf("Support packed sequence headers\n");
953             config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_SEQUENCE;
954         }
955         
956         if (tmp & VA_ENC_PACKED_HEADER_PICTURE) {
957             printf("Support packed picture headers\n");
958             config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_PICTURE;
959         }
960         
961         if (tmp & VA_ENC_PACKED_HEADER_SLICE) {
962             printf("Support packed slice headers\n");
963             config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_SLICE;
964         }
965         
966         if (tmp & VA_ENC_PACKED_HEADER_MISC) {
967             printf("Support packed misc headers\n");
968             config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_MISC;
969         }
970         
971         config_attrib_num++;
972     }
973
974     if (attrib[VAConfigAttribEncInterlaced].value != VA_ATTRIB_NOT_SUPPORTED) {
975         int tmp = attrib[VAConfigAttribEncInterlaced].value;
976         
977         printf("Support VAConfigAttribEncInterlaced\n");
978
979         if (tmp & VA_ENC_INTERLACED_FRAME)
980             printf("support VA_ENC_INTERLACED_FRAME\n");
981         if (tmp & VA_ENC_INTERLACED_FIELD)
982             printf("Support VA_ENC_INTERLACED_FIELD\n");
983         if (tmp & VA_ENC_INTERLACED_MBAFF)
984             printf("Support VA_ENC_INTERLACED_MBAFF\n");
985         if (tmp & VA_ENC_INTERLACED_PAFF)
986             printf("Support VA_ENC_INTERLACED_PAFF\n");
987         
988         config_attrib[config_attrib_num].type = VAConfigAttribEncInterlaced;
989         config_attrib[config_attrib_num].value = VA_ENC_PACKED_HEADER_NONE;
990         config_attrib_num++;
991     }
992     
993     if (attrib[VAConfigAttribEncMaxRefFrames].value != VA_ATTRIB_NOT_SUPPORTED) {
994         h264_maxref = attrib[VAConfigAttribEncMaxRefFrames].value;
995         
996         printf("Support %d reference frames\n", h264_maxref);
997     }
998
999     if (attrib[VAConfigAttribEncMaxSlices].value != VA_ATTRIB_NOT_SUPPORTED)
1000         printf("Support %d slices\n", attrib[VAConfigAttribEncMaxSlices].value);
1001
1002     if (attrib[VAConfigAttribEncSliceStructure].value != VA_ATTRIB_NOT_SUPPORTED) {
1003         int tmp = attrib[VAConfigAttribEncSliceStructure].value;
1004         
1005         printf("Support VAConfigAttribEncSliceStructure\n");
1006
1007         if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS)
1008             printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS\n");
1009         if (tmp & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS)
1010             printf("Support VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS\n");
1011         if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS)
1012             printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS\n");
1013     }
1014     if (attrib[VAConfigAttribEncMacroblockInfo].value != VA_ATTRIB_NOT_SUPPORTED) {
1015         printf("Support VAConfigAttribEncMacroblockInfo\n");
1016     }
1017
1018     return 0;
1019 }
1020
1021 static int setup_encode()
1022 {
1023     VAStatus va_status;
1024     VASurfaceID *tmp_surfaceid;
1025     int codedbuf_size, i;
1026     
1027     va_status = vaCreateConfig(va_dpy, h264_profile, VAEntrypointEncSlice,
1028             &config_attrib[0], config_attrib_num, &config_id);
1029     CHECK_VASTATUS(va_status, "vaCreateConfig");
1030
1031     /* create source surfaces */
1032     va_status = vaCreateSurfaces(va_dpy,
1033                                  VA_RT_FORMAT_YUV420, frame_width, frame_height,
1034                                  &src_surface[0], SRC_SURFACE_NUM,
1035                                  NULL, 0);
1036     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
1037
1038     /* create reference surfaces */
1039     va_status = vaCreateSurfaces(
1040             va_dpy,
1041             VA_RT_FORMAT_YUV420, frame_width, frame_height,
1042             &ref_surface[0], h264_maxref,
1043             NULL, 0
1044             );
1045     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
1046
1047     tmp_surfaceid = calloc(SRC_SURFACE_NUM + h264_maxref, sizeof(VASurfaceID));
1048     memcpy(tmp_surfaceid, src_surface, SRC_SURFACE_NUM * sizeof(VASurfaceID));
1049     memcpy(tmp_surfaceid + SRC_SURFACE_NUM, ref_surface, h264_maxref * sizeof(VASurfaceID));
1050     
1051     /* Create a context for this encode pipe */
1052     va_status = vaCreateContext(va_dpy, config_id,
1053                                 frame_width, frame_height,
1054                                 VA_PROGRESSIVE,
1055                                 tmp_surfaceid, SRC_SURFACE_NUM + h264_maxref,
1056                                 &context_id);
1057     CHECK_VASTATUS(va_status, "vaCreateContext");
1058     free(tmp_surfaceid);
1059
1060     codedbuf_size = (frame_width * frame_height * 400) / (16*16);
1061
1062     for (i = 0; i < SRC_SURFACE_NUM; i++) {
1063         /* create coded buffer once for all
1064          * other VA buffers which won't be used again after vaRenderPicture.
1065          * so APP can always vaCreateBuffer for every frame
1066          * but coded buffer need to be mapped and accessed after vaRenderPicture/vaEndPicture
1067          * so VA won't maintain the coded buffer
1068          */
1069         va_status = vaCreateBuffer(va_dpy,context_id,VAEncCodedBufferType,
1070                 codedbuf_size, 1, NULL, &coded_buf[i]);
1071         CHECK_VASTATUS(va_status,"vaCreateBuffer");
1072     }
1073     
1074     return 0;
1075 }
1076
1077 static int render_sequence(void)
1078 {
1079     VABufferID seq_param_buf, rc_param_buf;
1080     VAStatus va_status;
1081     VAEncMiscParameterBuffer *misc_param;
1082     VAEncMiscParameterRateControl *misc_rate_ctrl;
1083     
1084     seq_param.level_idc = 41 /*SH_LEVEL_3*/;
1085     seq_param.picture_width_in_mbs = frame_width / 16;
1086     seq_param.picture_height_in_mbs = frame_height / 16;
1087     seq_param.bits_per_second = frame_bitrate;
1088
1089     seq_param.intra_period = intra_period;
1090     seq_param.intra_idr_period = intra_idr_period;
1091     seq_param.ip_period = ip_period;
1092
1093     seq_param.max_num_ref_frames = h264_maxref;
1094     seq_param.seq_fields.bits.frame_mbs_only_flag = 1;
1095     seq_param.time_scale = 900;
1096     seq_param.num_units_in_tick = 15; /* Tc = num_units_in_tick / time_sacle */
1097     seq_param.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
1098     seq_param.seq_fields.bits.frame_mbs_only_flag = 1;
1099     
1100     va_status = vaCreateBuffer(va_dpy, context_id,
1101                                VAEncSequenceParameterBufferType,
1102                                sizeof(seq_param),1,&seq_param,&seq_param_buf);
1103     CHECK_VASTATUS(va_status,"vaCreateBuffer");
1104     
1105     va_status = vaCreateBuffer(va_dpy, context_id,
1106                                VAEncMiscParameterBufferType,
1107                                sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl),
1108                                1,NULL,&rc_param_buf);
1109     CHECK_VASTATUS(va_status,"vaCreateBuffer");
1110     
1111     vaMapBuffer(va_dpy, rc_param_buf,(void **)&misc_param);
1112     misc_param->type = VAEncMiscParameterTypeRateControl;
1113     misc_rate_ctrl = (VAEncMiscParameterRateControl *)misc_param->data;
1114     memset(misc_rate_ctrl, 0, sizeof(*misc_rate_ctrl));
1115     misc_rate_ctrl->bits_per_second = frame_bitrate;
1116     misc_rate_ctrl->initial_qp = initial_qp;
1117     misc_rate_ctrl->min_qp = minimal_qp;
1118     misc_rate_ctrl->basic_unit_size = 0;
1119     vaUnmapBuffer(va_dpy, rc_param_buf);
1120
1121     va_status = vaRenderPicture(va_dpy,context_id, &seq_param_buf, 1);
1122     CHECK_VASTATUS(va_status,"vaRenderPicture");;
1123
1124     va_status = vaRenderPicture(va_dpy,context_id, &rc_param_buf, 1);
1125     CHECK_VASTATUS(va_status,"vaRenderPicture");;
1126
1127     return 0;
1128 }
1129
1130 static int render_picture(void)
1131 {
1132     VABufferID pic_param_buf;
1133     VAStatus va_status;
1134     int i = 0;
1135
1136     /* use frame_num as reference frame index */
1137     pic_param.CurrPic.picture_id = ref_surface[current_frame_num % h264_maxref];
1138 //    pic_param.CurrPic.frame_idx = current_frame_num % h264_maxref;
1139     pic_param.CurrPic.flags = 0;
1140     pic_param.CurrPic.TopFieldOrderCnt = 2 * current_frame_display;
1141     pic_param.CurrPic.BottomFieldOrderCnt = 0;
1142     if (current_frame_type != FRAME_B)
1143         CurrentCurrPic = pic_param.CurrPic; /* save it */
1144     
1145     if (slice_refoverride) {
1146         /* always setup all reference frame into encoder */
1147         for (i = 0; i < h264_maxref; i++) {
1148             pic_param.ReferenceFrames[i].picture_id = ref_surface[i];
1149             pic_param.ReferenceFrames[i].frame_idx = i;
1150             pic_param.ReferenceFrames[i].flags = 0;
1151             if (pic_param.CurrPic.picture_id == pic_param.ReferenceFrames[i].picture_id) {
1152                 pic_param.ReferenceFrames[i].TopFieldOrderCnt = 2 * current_frame_encoding;
1153                 //pic_param.ReferenceFrames[i].picture_id = VA_INVALID_SURFACE;
1154                 //pic_param.ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID;            
1155             }
1156             pic_param.ReferenceFrames[i].BottomFieldOrderCnt = 0;
1157         }
1158     } else {
1159         if (current_frame_type == FRAME_I || current_frame_type == FRAME_IDR)
1160             i = 0;
1161         else if (current_frame_type == FRAME_P) {
1162             pic_param.ReferenceFrames[0].picture_id = LastCurrPic.picture_id;
1163             i = 1;
1164         } else if (current_frame_type == FRAME_B) {
1165             pic_param.ReferenceFrames[0] = LLastCurrPic;
1166             pic_param.ReferenceFrames[1] = LastCurrPic;
1167             i = 2;
1168         }
1169     }
1170     
1171     for (; i < REF_SURFACE_NUM; i++) {
1172         pic_param.ReferenceFrames[i].picture_id = VA_INVALID_SURFACE;
1173         pic_param.ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID;
1174     }
1175     
1176     pic_param.pic_fields.bits.idr_pic_flag = (current_frame_type == FRAME_IDR);
1177     pic_param.pic_fields.bits.reference_pic_flag = (current_frame_type != FRAME_B);
1178     pic_param.pic_fields.bits.entropy_coding_mode_flag = 1;
1179     pic_param.pic_fields.bits.deblocking_filter_control_present_flag = 1;
1180     pic_param.frame_num = current_frame_num;
1181     if (current_frame_type != FRAME_B)
1182         current_frame_num++;
1183     pic_param.coded_buf = coded_buf[current_frame_display % SRC_SURFACE_NUM];
1184     pic_param.last_picture = (current_frame_encoding == frame_count);
1185     pic_param.pic_init_qp = initial_qp;
1186
1187     va_status = vaCreateBuffer(va_dpy, context_id,VAEncPictureParameterBufferType,
1188                                sizeof(pic_param),1,&pic_param, &pic_param_buf);
1189     CHECK_VASTATUS(va_status,"vaCreateBuffer");;
1190
1191     va_status = vaRenderPicture(va_dpy,context_id, &pic_param_buf, 1);
1192     CHECK_VASTATUS(va_status,"vaRenderPicture");
1193
1194     return 0;
1195 }
1196
1197 static int render_packedsequence(void)
1198 {
1199     VAEncPackedHeaderParameterBuffer packedheader_param_buffer={0};
1200     VABufferID packedseq_para_bufid, packedseq_data_bufid, render_id[2];
1201     unsigned int length_in_bits;
1202     unsigned char *packedseq_buffer = NULL;
1203     VAStatus va_status;
1204
1205     length_in_bits = build_packed_seq_buffer(&packedseq_buffer); 
1206     
1207     packedheader_param_buffer.type = VAEncPackedHeaderSequence;
1208     
1209     packedheader_param_buffer.bit_length = length_in_bits; /*length_in_bits*/
1210     packedheader_param_buffer.has_emulation_bytes = 0;
1211     va_status = vaCreateBuffer(va_dpy,
1212                                context_id,
1213                                VAEncPackedHeaderParameterBufferType,
1214                                sizeof(packedheader_param_buffer), 1, &packedheader_param_buffer,
1215                                &packedseq_para_bufid);
1216     CHECK_VASTATUS(va_status,"vaCreateBuffer");
1217
1218     va_status = vaCreateBuffer(va_dpy,
1219                                context_id,
1220                                VAEncPackedHeaderDataBufferType,
1221                                (length_in_bits + 7) / 8, 1, packedseq_buffer,
1222                                &packedseq_data_bufid);
1223     CHECK_VASTATUS(va_status,"vaCreateBuffer");
1224
1225     render_id[0] = packedseq_para_bufid;
1226     render_id[1] = packedseq_data_bufid;
1227     va_status = vaRenderPicture(va_dpy,context_id, render_id, 2);
1228     CHECK_VASTATUS(va_status,"vaRenderPicture");
1229     
1230     return 0;
1231 }
1232
1233
1234 static int render_packedpicture(void)
1235 {
1236     VAEncPackedHeaderParameterBuffer packedheader_param_buffer={0};
1237     VABufferID packedpic_para_bufid, packedpic_data_bufid, render_id[2];
1238     unsigned int length_in_bits;
1239     unsigned char *packedpic_buffer = NULL;
1240     VAStatus va_status;
1241
1242     length_in_bits = build_packed_pic_buffer(&packedpic_buffer); 
1243     packedheader_param_buffer.type = VAEncPackedHeaderPicture;
1244     packedheader_param_buffer.bit_length = length_in_bits;
1245     packedheader_param_buffer.has_emulation_bytes = 0;
1246
1247     va_status = vaCreateBuffer(va_dpy,
1248                                context_id,
1249                                VAEncPackedHeaderParameterBufferType,
1250                                sizeof(packedheader_param_buffer), 1, &packedheader_param_buffer,
1251                                &packedpic_para_bufid);
1252     CHECK_VASTATUS(va_status,"vaCreateBuffer");
1253
1254     va_status = vaCreateBuffer(va_dpy,
1255                                context_id,
1256                                VAEncPackedHeaderDataBufferType,
1257                                (length_in_bits + 7) / 8, 1, packedpic_buffer,
1258                                &packedpic_data_bufid);
1259     CHECK_VASTATUS(va_status,"vaCreateBuffer");
1260
1261     render_id[0] = packedpic_para_bufid;
1262     render_id[1] = packedpic_data_bufid;
1263     va_status = vaRenderPicture(va_dpy,context_id, render_id, 2);
1264     CHECK_VASTATUS(va_status,"vaRenderPicture");
1265     
1266     return 0;
1267 }
1268
1269 static int render_slice(void)
1270 {
1271     VABufferID slice_param_buf;
1272     VAStatus va_status;
1273     int i;
1274     
1275     /* one frame, one slice */
1276     slice_param.macroblock_address = 0;
1277     slice_param.num_macroblocks = frame_width*frame_height/(16*16); /* Measured by MB */
1278     slice_param.slice_type = (current_frame_type == FRAME_IDR)?2:current_frame_type;
1279
1280     for (i = 0; i < 32; i++) {
1281         slice_param.RefPicList0[i].picture_id = VA_INVALID_SURFACE;
1282         slice_param.RefPicList0[i].flags = VA_PICTURE_H264_INVALID;
1283         slice_param.RefPicList1[i].picture_id = VA_INVALID_SURFACE;
1284         slice_param.RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
1285     }
1286
1287     /* cause issue on some implementation if slice_refoverride = 1 */
1288     if (slice_refoverride) {
1289         /* set the real reference frame */
1290         slice_param.num_ref_idx_active_override_flag = 1;
1291         if (current_frame_type == FRAME_I || current_frame_type == FRAME_IDR) {
1292             slice_param.num_ref_idx_l0_active_minus1 = 0;
1293             slice_param.num_ref_idx_l1_active_minus1 = 0;
1294         } else if (current_frame_type == FRAME_P) {
1295             slice_param.num_ref_idx_l0_active_minus1 = 0;
1296             slice_param.num_ref_idx_l1_active_minus1 = 0;
1297             slice_param.RefPicList0[0] = LastCurrPic;
1298         } else if (current_frame_type == FRAME_B) {
1299             slice_param.num_ref_idx_l0_active_minus1 = 0;
1300             slice_param.num_ref_idx_l1_active_minus1 = 0;
1301             slice_param.RefPicList0[0] = LLastCurrPic;
1302             slice_param.RefPicList1[0] = LastCurrPic;
1303         }
1304     }
1305     slice_param.slice_alpha_c0_offset_div2 = 2;
1306     slice_param.slice_beta_offset_div2 = 2;
1307     slice_param.pic_order_cnt_lsb = current_frame_display % 64;
1308     
1309     va_status = vaCreateBuffer(va_dpy,context_id,VAEncSliceParameterBufferType,
1310                                sizeof(slice_param),1,&slice_param,&slice_param_buf);
1311     CHECK_VASTATUS(va_status,"vaCreateBuffer");;
1312
1313     va_status = vaRenderPicture(va_dpy,context_id, &slice_param_buf, 1);
1314     CHECK_VASTATUS(va_status,"vaRenderPicture");
1315
1316     return 0;
1317 }
1318
1319
1320 static int update_reflist(void)
1321 {
1322     if (current_frame_type == FRAME_B)
1323         return 0;
1324
1325     LLastCurrPic = LastCurrPic;
1326     LastCurrPic = CurrentCurrPic;
1327
1328     return 0;
1329 }
1330
1331
1332 static int upload_source_YUV_once_for_all()
1333 {
1334     int box_width=8;
1335     int row_shift=0;
1336     int i;
1337
1338     for (i = 0; i < SRC_SURFACE_NUM; i++) {
1339         printf("\rLoading data into surface %d.....", i);
1340         upload_surface(va_dpy, src_surface[i], box_width, row_shift, 0);
1341
1342         row_shift++;
1343         if (row_shift==(2*box_width)) row_shift= 0;
1344     }
1345     printf("Completed surface loading\n");
1346
1347     return 0;
1348 }
1349
1350
1351 static int load_surface(VASurfaceID surface_id, unsigned long long display_order)
1352 {
1353     VAImage surface_image;
1354     unsigned char *surface_p, *Y_start, *U_start,*V_start;
1355     int Y_pitch, U_pitch, row, V_pitch;
1356     VAStatus va_status;
1357
1358     if (srcyuv_fp == NULL)
1359         return 0;
1360     
1361     /* rewind the file pointer if encoding more than srcyuv_frames */
1362     display_order = display_order % srcyuv_frames;
1363     
1364     fseek(srcyuv_fp, display_order * frame_width * frame_height * 1.5, SEEK_SET);
1365     
1366     va_status = vaDeriveImage(va_dpy,surface_id, &surface_image);
1367     CHECK_VASTATUS(va_status,"vaDeriveImage");
1368
1369     vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p);
1370     assert(VA_STATUS_SUCCESS == va_status);
1371
1372     Y_start = surface_p;
1373     Y_pitch = surface_image.pitches[0];
1374     switch (surface_image.format.fourcc) {
1375     case VA_FOURCC_NV12:
1376         U_start = (unsigned char *)surface_p + surface_image.offsets[1];
1377         V_start = U_start + 1;
1378         U_pitch = surface_image.pitches[1];
1379         V_pitch = surface_image.pitches[1];
1380         break;
1381     case VA_FOURCC_IYUV:
1382         U_start = (unsigned char *)surface_p + surface_image.offsets[1];
1383         V_start = (unsigned char *)surface_p + surface_image.offsets[2];
1384         U_pitch = surface_image.pitches[1];
1385         V_pitch = surface_image.pitches[2];
1386         break;
1387     case VA_FOURCC_YV12:
1388         U_start = (unsigned char *)surface_p + surface_image.offsets[2];
1389         V_start = (unsigned char *)surface_p + surface_image.offsets[1];
1390         U_pitch = surface_image.pitches[2];
1391         V_pitch = surface_image.pitches[1];
1392         break;
1393     case VA_FOURCC_YUY2:
1394         U_start = surface_p + 1;
1395         V_start = surface_p + 3;
1396         U_pitch = surface_image.pitches[0];
1397         V_pitch = surface_image.pitches[0];
1398         break;
1399     default:
1400         assert(0);
1401     }
1402
1403     /* copy Y plane */
1404     for (row=0;row<surface_image.height;row++) {
1405         unsigned char *Y_row = Y_start + row * Y_pitch;
1406
1407         fread(Y_row, 1, surface_image.width, srcyuv_fp);
1408     }
1409   
1410     /* copy UV data, reset file pointer,
1411      * surface_image.height may not be equal to source YUV height/frame_height
1412      */
1413     fseek(srcyuv_fp,
1414           display_order * frame_width * frame_height * 1.5 + frame_width * frame_height,
1415           SEEK_SET);
1416     
1417     for (row =0; row < surface_image.height/2; row++) {
1418         unsigned char *U_row = U_start + row * U_pitch;
1419         //unsigned char *V_row = V_start + row * V_pitch;
1420         switch (surface_image.format.fourcc) {
1421         case VA_FOURCC_NV12:
1422             if (srcyuv_fourcc == VA_FOURCC_NV12)
1423                 fread(U_row, 1, surface_image.width, srcyuv_fp);
1424             else if (srcyuv_fourcc == VA_FOURCC_IYUV) {
1425                 /* tbd */
1426             }
1427             break;
1428         case VA_FOURCC_YV12:
1429             /* tbd */
1430             break;
1431         case VA_FOURCC_YUY2:
1432             // see above. it is set with Y update.
1433             break;
1434         default:
1435             printf("unsupported fourcc in load_surface\n");
1436             assert(0);
1437         }
1438     }
1439         
1440     vaUnmapBuffer(va_dpy,surface_image.buf);
1441
1442     vaDestroyImage(va_dpy,surface_image.image_id);
1443
1444     return 0;
1445 }
1446
1447
1448 static int save_codeddata(unsigned long long display_order, unsigned long long encode_order)
1449 {    
1450     VACodedBufferSegment *buf_list = NULL;
1451     VAStatus va_status;
1452     unsigned int coded_size = 0;
1453
1454     va_status = vaMapBuffer(va_dpy,coded_buf[display_order % SRC_SURFACE_NUM],(void **)(&buf_list));
1455     CHECK_VASTATUS(va_status,"vaMapBuffer");
1456     while (buf_list != NULL) {
1457         coded_size += fwrite(buf_list->buf, 1, buf_list->size, coded_fp);
1458         buf_list = (VACodedBufferSegment *) buf_list->next;
1459     }
1460     vaUnmapBuffer(va_dpy,coded_buf[display_order % SRC_SURFACE_NUM]);
1461
1462     printf("\r      "); /* return back to startpoint */
1463     switch (encode_order % 4) {
1464         case 0:
1465             printf("|");
1466             break;
1467         case 1:
1468             printf("/");
1469             break;
1470         case 2:
1471             printf("-");
1472             break;
1473         case 3:
1474             printf("\\");
1475             break;
1476     }
1477     printf("%08lld", encode_order);
1478     /*
1479     if (current_frame_encoding % intra_count == 0)
1480         printf("(I)");
1481     else
1482         printf("(P)");
1483     */
1484     printf("(%06d bytes coded)",coded_size);
1485     /* skipped frame ? */
1486     printf("                                    ");
1487
1488     return 0;
1489 }
1490
1491
1492 static struct storage_task_t * storage_task_dequque(void)
1493 {
1494     struct storage_task_t *header;
1495
1496     pthread_mutex_lock(&encode_mutex);
1497
1498     header = storage_task_header;    
1499     if (storage_task_header != NULL) {
1500         if (storage_task_tail == storage_task_header)
1501             storage_task_tail = NULL;
1502         storage_task_header = header->next;
1503     }
1504     
1505     pthread_mutex_unlock(&encode_mutex);
1506     
1507     return header;
1508 }
1509
1510 static int storage_task_queue(unsigned long long display_order, unsigned long long encode_order)
1511 {
1512     struct storage_task_t *tmp;
1513
1514     tmp = calloc(1, sizeof(struct storage_task_t));
1515     tmp->display_order = display_order;
1516     tmp->encode_order = encode_order;
1517
1518     pthread_mutex_lock(&encode_mutex);
1519     
1520     if (storage_task_header == NULL) {
1521         storage_task_header = tmp;
1522         storage_task_tail = tmp;
1523     } else {
1524         storage_task_tail->next = tmp;
1525         storage_task_tail = tmp;
1526     }
1527
1528     srcsurface_status[display_order % SRC_SURFACE_NUM] = SRC_SURFACE_IN_STORAGE;
1529     pthread_cond_signal(&encode_cond);
1530     
1531     pthread_mutex_unlock(&encode_mutex);
1532     
1533     return 0;
1534 }
1535
1536 static void storage_task(unsigned long long display_order, unsigned long encode_order)
1537 {
1538     unsigned int tmp;
1539     VAStatus va_status;
1540     
1541     tmp = GetTickCount();
1542     va_status = vaSyncSurface(va_dpy, src_surface[display_order % SRC_SURFACE_NUM]);
1543     CHECK_VASTATUS(va_status,"vaSyncSurface");
1544     SyncPictureTicks += GetTickCount() - tmp;
1545     tmp = GetTickCount();
1546     save_codeddata(display_order, encode_order);
1547     SavePictureTicks += GetTickCount() - tmp;
1548     /* tbd: save reconstructed frame */
1549         
1550     /* reload a new frame data */
1551     tmp = GetTickCount();
1552     if (srcyuv_fp != NULL)
1553         load_surface(src_surface[display_order % SRC_SURFACE_NUM], display_order);
1554     UploadPictureTicks += GetTickCount() - tmp;
1555
1556     pthread_mutex_lock(&encode_mutex);
1557     srcsurface_status[display_order % SRC_SURFACE_NUM] = SRC_SURFACE_IN_ENCODING;
1558     pthread_mutex_unlock(&encode_mutex);
1559 }
1560
1561         
1562 static void * storage_task_thread(void *t)
1563 {
1564     while (1) {
1565         struct storage_task_t *current;
1566         
1567         current = storage_task_dequque();
1568         if (current == NULL) {
1569             pthread_mutex_lock(&encode_mutex);
1570             pthread_cond_wait(&encode_cond, &encode_mutex);
1571             pthread_mutex_unlock(&encode_mutex);
1572             continue;
1573         }
1574         
1575         storage_task(current->display_order, current->encode_order);
1576         
1577         free(current);
1578
1579         /* all frames are saved, exit the thread */
1580         if (++frame_coded >= frame_count)
1581             break;
1582     }
1583
1584     return 0;
1585 }
1586
1587
1588 static int encode_frames(void)
1589 {
1590     unsigned int i, tmp;
1591     VAStatus va_status;
1592     //VASurfaceStatus surface_status;
1593
1594     /* upload RAW YUV data into all surfaces */
1595     tmp = GetTickCount();
1596     if (srcyuv_fp != NULL) {
1597         for (i = 0; i < SRC_SURFACE_NUM; i++)
1598             load_surface(src_surface[i], i);
1599     } else
1600         upload_source_YUV_once_for_all();
1601     UploadPictureTicks += GetTickCount() - tmp;
1602     
1603     /* ready for encoding */
1604     memset(srcsurface_status, SRC_SURFACE_IN_ENCODING, sizeof(srcsurface_status));
1605     
1606     memset(&seq_param, 0, sizeof(seq_param));
1607     memset(&pic_param, 0, sizeof(pic_param));
1608     memset(&slice_param, 0, sizeof(slice_param));
1609
1610     if (encode_syncmode == 0)
1611         pthread_create(&encode_thread, NULL, storage_task_thread, NULL);
1612     
1613     for (current_frame_encoding = 0; current_frame_encoding < frame_count; current_frame_encoding++) {
1614         encoding2display_order(current_frame_encoding, intra_period, intra_idr_period, ip_period,
1615                                &current_frame_display, &current_frame_type);
1616
1617         /* check if the source frame is ready */
1618         while (srcsurface_status[current_frame_display % SRC_SURFACE_NUM] != SRC_SURFACE_IN_ENCODING);
1619
1620         tmp = GetTickCount();
1621         va_status = vaBeginPicture(va_dpy, context_id, src_surface[current_frame_display % SRC_SURFACE_NUM]);
1622         CHECK_VASTATUS(va_status,"vaBeginPicture");
1623         BeginPictureTicks += GetTickCount() - tmp;
1624         
1625         tmp = GetTickCount();
1626         if (current_frame_encoding  == 0) {
1627             render_sequence();
1628             render_picture();            
1629             if (h264_packedheader) {
1630                 render_packedsequence();
1631                 render_packedpicture();
1632             }
1633         } else {
1634             //render_sequence();
1635             render_picture();
1636         }
1637         render_slice();
1638         RenderPictureTicks += GetTickCount() - tmp;
1639         
1640         tmp = GetTickCount();
1641         va_status = vaEndPicture(va_dpy,context_id);
1642         CHECK_VASTATUS(va_status,"vaEndPicture");;
1643         EndPictureTicks += GetTickCount() - tmp;
1644
1645         if (encode_syncmode)
1646             storage_task(current_frame_display, current_frame_encoding);
1647         else /* queue the storage task queue */
1648             storage_task_queue(current_frame_display, current_frame_encoding);
1649
1650         /* how to process skipped frames
1651            surface_status = (VASurfaceStatus) 0;
1652            va_status = vaQuerySurfaceStatus(va_dpy, src_surface[i%SRC_SURFACE_NUM],&surface_status);
1653            frame_skipped = (surface_status & VASurfaceSkipped);
1654         */
1655
1656         update_reflist();        
1657     }
1658
1659     if (encode_syncmode == 0) {
1660         int ret;
1661         pthread_join(encode_thread, (void **)&ret);
1662     }
1663     
1664     return 0;
1665 }
1666
1667
1668 static int release_encode()
1669 {
1670     int i;
1671     
1672     vaDestroySurfaces(va_dpy,&src_surface[0],SRC_SURFACE_NUM);
1673     vaDestroySurfaces(va_dpy,&ref_surface[0],h264_maxref);
1674
1675     for (i = 0; i < SRC_SURFACE_NUM; i++)
1676         vaDestroyBuffer(va_dpy,coded_buf[i]);
1677     
1678     vaDestroyContext(va_dpy,context_id);
1679     vaDestroyConfig(va_dpy,config_id);
1680
1681     return 0;
1682 }
1683
1684 static int deinit_va()
1685
1686     vaTerminate(va_dpy);
1687
1688     va_close_display(va_dpy);
1689
1690     return 0;
1691 }
1692
1693
1694 static int print_input()
1695 {
1696     printf("\n\nINPUT:Try to encode H264...\n");
1697     printf("INPUT: RateControl  : %s\n", rc_to_string(rc_mode));
1698     printf("INPUT: Resolution   : %dx%d, %d frames\n",
1699            frame_width, frame_height, frame_count);
1700     printf("INPUT: FrameRate    : %d\n", frame_rate);
1701     printf("INPUT: Bitrate      : %d\n", frame_bitrate);
1702     printf("INPUT: Slieces      : %d\n", frame_slices);
1703     printf("INPUT: IntraPeriod  : %d\n", intra_period);
1704     printf("INPUT: IDRPeriod    : %d\n", intra_idr_period);
1705     printf("INPUT: IpPeriod     : %d\n", ip_period);
1706     printf("INPUT: Initial QP   : %d\n", initial_qp);
1707     printf("INPUT: Min QP       : %d\n", minimal_qp);
1708     printf("INPUT: Source YUV   : %s", srcyuv_fn?"FILE":"AUTO generated");
1709     if (srcyuv_fp) 
1710         printf(":%s (fourcc %s)\n", srcyuv_fn, fourcc_to_string(srcyuv_fourcc));
1711     else
1712         printf("\n");
1713     printf("INPUT: Coded Clip   : %s\n", coded_fn);
1714     if (srcyuv_fp == NULL)
1715         printf("INPUT: Rec   Clip   : %s\n", "Not save reconstructed frame");
1716     else
1717         printf("INPUT: Rec   Clip   : Save reconstructed frame into %s (fourcc %s)\n", recyuv_fn,
1718                fourcc_to_string(srcyuv_fourcc));
1719     
1720     printf("\n\n"); /* return back to startpoint */
1721     
1722     return 0;
1723 }
1724
1725
1726 static int print_performance(unsigned int PictureCount)
1727 {
1728     unsigned int others = 0;
1729
1730     others = TotalTicks - UploadPictureTicks - BeginPictureTicks
1731         - RenderPictureTicks - EndPictureTicks - SyncPictureTicks - SavePictureTicks;
1732     
1733     printf("\n\n");
1734
1735     printf("PERFORMANCE:   Frame Rate           : %.2f fps (%d frames, %d ms (%.2f ms per frame))\n",
1736            (double) 1000*PictureCount / TotalTicks, PictureCount,
1737            TotalTicks, ((double)  TotalTicks) / (double) PictureCount);
1738
1739     printf("PERFORMANCE:     UploadPicture      : %d ms (%.2f, %.2f%% percent)\n",
1740            (int) UploadPictureTicks, ((double)  UploadPictureTicks) / (double) PictureCount,
1741            UploadPictureTicks/(double) TotalTicks/0.01);
1742     printf("PERFORMANCE:     vaBeginPicture     : %d ms (%.2f, %.2f%% percent)\n",
1743            (int) BeginPictureTicks, ((double)  BeginPictureTicks) / (double) PictureCount,
1744            BeginPictureTicks/(double) TotalTicks/0.01);
1745     printf("PERFORMANCE:     vaRenderHeader     : %d ms (%.2f, %.2f%% percent)\n",
1746            (int) RenderPictureTicks, ((double)  RenderPictureTicks) / (double) PictureCount,
1747            RenderPictureTicks/(double) TotalTicks/0.01);
1748     printf("PERFORMANCE:     vaEndPicture       : %d ms (%.2f, %.2f%% percent)\n",
1749            (int) EndPictureTicks, ((double)  EndPictureTicks) / (double) PictureCount,
1750            EndPictureTicks/(double) TotalTicks/0.01);
1751     printf("PERFORMANCE:     vaSyncSurface      : %d ms (%.2f, %.2f%% percent)\n",
1752            (int) SyncPictureTicks, ((double) SyncPictureTicks) / (double) PictureCount,
1753            SyncPictureTicks/(double) TotalTicks/0.01);
1754     printf("PERFORMANCE:     SavePicture        : %d ms (%.2f, %.2f%% percent)\n",
1755            (int) SavePictureTicks, ((double)  SavePictureTicks) / (double) PictureCount,
1756            SavePictureTicks/(double) TotalTicks/0.01);
1757
1758     printf("PERFORMANCE:     Others             : %d ms (%.2f, %.2f%% percent)\n",
1759            (int) others, ((double) others) / (double) PictureCount,
1760            others/(double) TotalTicks/0.01);
1761     
1762     return 0;
1763 }
1764
1765
1766 int main(int argc,char **argv)
1767 {
1768     unsigned int start;
1769     
1770     process_cmdline(argc, argv);
1771
1772     print_input();
1773     
1774     start = GetTickCount();
1775     
1776     init_va();
1777     setup_encode();
1778     
1779     encode_frames();
1780
1781     release_encode();
1782     deinit_va();
1783
1784     TotalTicks += GetTickCount() - start;
1785     print_performance(frame_count);
1786     
1787     return 0;
1788 }