• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017 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 
25 /*
26  * This file has some codes for vp9 bitstream built, and
27  * they are ported from libvpx (https://github.com/webmproject/libvpx/).
28  * The original copyright and licence statement as below.
29  */
30 
31 /*
32  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
33  *
34  *  Use of this source code is governed by a BSD-style license
35  *  that can be found in the LICENSE file in the root of the source
36  *  tree. An additional intellectual property rights grant can be found
37  *  in the file PATENTS.  All contributing project authors may
38  *  be found in the AUTHORS file in the root of the source tree.
39  */
40 
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <getopt.h>
46 #include <unistd.h>
47 
48 #include <sys/time.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <assert.h>
53 #include <time.h>
54 #include <stdlib.h>
55 #include <pthread.h>
56 
57 #include <va/va.h>
58 #include <va/va_enc_vp9.h>
59 #include "va_display.h"
60 
61 #define KEY_FRAME               0
62 #define INTER_FRAME             1
63 
64 #define CHECK_VASTATUS(va_status,func)                                  \
65     if (va_status != VA_STATUS_SUCCESS) {                               \
66         fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
67         exit(1);                                                        \
68     }
69 
70 #define CHECK_CONDITION(cond)                                                \
71     if(!(cond))                                                              \
72     {                                                                        \
73         fprintf(stderr, "Unexpected condition: %s:%d\n", __func__, __LINE__); \
74         exit(1);                                                             \
75     }
76 
77 static VADisplay va_dpy;
78 
79 static int rc_mode;
80 
81 static int picture_width;
82 static int picture_height;
83 static int frame_size;
84 static uint8_t *newImageBuffer = 0;
85 
86 static int hrd_window = 1500;
87 
88 static int vbr_max;
89 
90 static int qp_value = 60;
91 
92 static int intra_period = 30;
93 static int frame_bit_rate = -1;
94 static int frame_rate = 30;
95 
96 static int lf_level = 10;
97 static int opt_header = 0;
98 
99 static int current_slot;
100 
101 static int frame_number;
102 static int current_frame_type;
103 
104 static  VASurfaceID vp9_ref_list[8];
105 
106 #define SURFACE_NUM                             8
107 #define SID_INPUT_PICTURE_0                     0
108 #define SID_INPUT_PICTURE_1                     1
109 #define SID_REFERENCE_PICTURE_L0                2
110 #define SID_REFERENCE_PICTURE_L1                3
111 #define SID_NUMBER                              2
112 
113 static  VASurfaceID surface_ids[SID_NUMBER];
114 static  VASurfaceID ref_surfaces[SURFACE_NUM + SID_NUMBER];
115 static  int use_slot[SURFACE_NUM];
116 
117 #ifndef VA_FOURCC_I420
118 #define VA_FOURCC_I420          0x30323449
119 #endif
120 
121 static int rc_default_mode[4] = {
122     VA_RC_CQP,
123     VA_RC_CBR,
124     VA_RC_VBR,
125     VA_RC_NONE
126 };
127 
128 static int vp9enc_entrypoint_lists[2] = {
129     VAEntrypointEncSlice,
130     VAEntrypointEncSliceLP
131 };
132 
133 static int select_entrypoint = -1;
134 
135 static const struct option long_opts[] = {
136     {"help", no_argument, NULL, 0 },
137     {"rcmode", required_argument, NULL, 1 },
138     {"qp", required_argument, NULL, 2 },
139     {"intra_period", required_argument, NULL, 3 },
140     {"fb", required_argument, NULL, 4 },
141     {"lf_level", required_argument, NULL, 6 },
142     {"opt_header", required_argument, NULL, 7},
143     {"hrd_win", required_argument, NULL, 8},
144     {"vbr_max", required_argument, NULL, 9},
145     {"fn_num", required_argument, NULL, 10},
146     {"low_power", required_argument, NULL, 11},
147     {NULL, no_argument, NULL, 0 }
148 };
149 
150 struct vp9enc_bit_buffer {
151     uint8_t *bit_buffer;
152     int bit_offset;
153 };
154 
155 struct upload_thread_param {
156     FILE *yuv_fp;
157     VASurfaceID surface_id;
158 };
159 
160 struct vp9encode_context {
161     VAProfile profile;
162     VAEncSequenceParameterBufferVP9 seq_param;
163     VAEncPictureParameterBufferVP9 pic_param;
164     VAContextID context_id;
165     VAConfigID config_id;
166     VABufferID seq_param_buf_id;                /* Sequence level parameter */
167     VABufferID pic_param_buf_id;                /* Picture level parameter */
168     VABufferID codedbuf_buf_id;                 /* Output buffer, compressed data */
169     VABufferID misc_parameter_hrd_buf_id;
170     /* for VAEncMiscParameterTypeVP9PerSegmantParam. VAQMatrixBufferType */
171     VABufferID qmatrix_buf_id;
172     /* the buffer for VP9 super block. VAEncMacroblockMapBufferType */
173     VABufferID mb_seg_buf_id;
174     VABufferID raw_data_header_buf_id;
175     VABufferID raw_data_buf_id;
176     VABufferID misc_fr_buf_id;
177     VABufferID misc_rc_buf_id;
178 
179     int codedbuf_i_size;
180     int codedbuf_pb_size;
181     int current_input_surface;
182     int rate_control_method;
183 
184     struct upload_thread_param upload_thread_param;
185     pthread_t upload_thread_id;
186     int upload_thread_value;
187 };
188 
189 static struct vp9encode_context vp9enc_context;
190 
191 static void
vp9enc_write_word(char * ptr,uint32_t value)192 vp9enc_write_word(char *ptr, uint32_t value)
193 {
194     uint8_t *tmp;
195 
196     tmp = (uint8_t *)ptr;
197     *(tmp) = (value >> 0) & 0XFF;
198     *(tmp + 1) = (value >> 8) & 0XFF;
199 }
200 
201 static void
vp9enc_write_dword(char * ptr,uint32_t value)202 vp9enc_write_dword(char *ptr, uint32_t value)
203 {
204     uint8_t *tmp;
205 
206     tmp = (uint8_t *)ptr;
207     *(tmp) = (value >> 0) & 0XFF;
208     *(tmp + 1) = (value >> 8) & 0XFF;
209     *(tmp + 2) = (value >> 16) & 0XFF;
210     *(tmp + 3) = (value >> 24) & 0XFF;
211 }
212 
213 static void
vp9enc_wb_write_bit(struct vp9enc_bit_buffer * wb,int bit)214 vp9enc_wb_write_bit(struct vp9enc_bit_buffer *wb, int bit)
215 {
216     const int off = wb->bit_offset;
217     const int p = off / 8;
218     const int q = 7 - off % 8;
219 
220     if (q == 7) {
221         wb->bit_buffer[p] = bit << q;
222     } else {
223         wb->bit_buffer[p] &= ~(1 << q);
224         wb->bit_buffer[p] |= bit << q;
225     }
226     wb->bit_offset = off + 1;
227 }
228 
229 static void
vp9enc_wb_write_literal(struct vp9enc_bit_buffer * wb,int data,int bits)230 vp9enc_wb_write_literal(struct vp9enc_bit_buffer *wb, int data, int bits)
231 {
232     int bit;
233 
234     for (bit = bits - 1; bit >= 0; bit--)
235         vp9enc_wb_write_bit(wb, (data >> bit) & 1);
236 }
237 
238 static void
vp9enc_write_bitdepth_colorspace_sampling(int codec_profile,struct vp9enc_bit_buffer * wb)239 vp9enc_write_bitdepth_colorspace_sampling(int codec_profile,
240         struct vp9enc_bit_buffer *wb)
241 {
242     if (codec_profile >= 2) {
243         /* the bit-depth will be added for VP9Profile2/3 */
244         /* this will be added later */
245         assert(0);
246     }
247 
248     /* Add the default color-space */
249     vp9enc_wb_write_literal(wb, 0, 3);
250     vp9enc_wb_write_bit(wb, 0);  // 0: [16, 235] (i.e. xvYCC), 1: [0, 255]
251 
252     /* the sampling_x/y will be added for VP9Profile1/2/3 later */
253 }
254 
255 #define    MAX_TILE_WIDTH_B64    64
256 #define    MIN_TILE_WIDTH_B64    4
257 
258 static int
vp9enc_get_min_log2_tile_cols(const int sb_cols)259 vp9enc_get_min_log2_tile_cols(const int sb_cols)
260 {
261     int min_log2 = 0;
262 
263     while ((MAX_TILE_WIDTH_B64 << min_log2) < sb_cols)
264         ++min_log2;
265 
266     return min_log2;
267 }
268 
269 static int
vp9enc_get_max_log2_tile_cols(const int sb_cols)270 vp9enc_get_max_log2_tile_cols(const int sb_cols)
271 {
272     int max_log2 = 1;
273 
274     while ((sb_cols >> max_log2) >= MIN_TILE_WIDTH_B64)
275         ++max_log2;
276 
277     return max_log2 - 1;
278 }
279 
280 static void
vp9enc_write_uncompressed_header(struct vp9encode_context * enc_context,char * header_data,int * header_length)281 vp9enc_write_uncompressed_header(struct vp9encode_context *enc_context,
282                                  char *header_data,
283                                  int *header_length)
284 {
285 #define    VP9_SYNC_CODE_0    0x49
286 #define    VP9_SYNC_CODE_1    0x83
287 #define    VP9_SYNC_CODE_2    0x42
288 
289 #define    VP9_FRAME_MARKER   0x2
290 
291 #define    REFS_PER_FRAME     3
292 
293 #define    REF_FRAMES_LOG2    3
294 #define    REF_FRAMES         (1 << REF_FRAMES_LOG2)
295 
296 #define    VP9_KEY_FRAME      0
297 
298     VAEncPictureParameterBufferVP9 *pic_param;
299     struct vp9enc_bit_buffer *wb, vp9_wb;
300 
301     if (!header_data || !header_length)
302         return;
303 
304     pic_param = &enc_context->pic_param;
305 
306     vp9_wb.bit_buffer = (uint8_t *)header_data;
307     vp9_wb.bit_offset = 0;
308     wb = &vp9_wb;
309     vp9enc_wb_write_literal(wb, VP9_FRAME_MARKER, 2);
310 
311     vp9enc_wb_write_literal(wb, 0, 2);
312 
313     vp9enc_wb_write_bit(wb, 0);  // show_existing_frame
314     vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.frame_type);
315     vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.show_frame);
316     vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.error_resilient_mode);
317 
318     if (pic_param->pic_flags.bits.frame_type == VP9_KEY_FRAME) {
319         vp9enc_wb_write_literal(wb, VP9_SYNC_CODE_0, 8);
320         vp9enc_wb_write_literal(wb, VP9_SYNC_CODE_1, 8);
321         vp9enc_wb_write_literal(wb, VP9_SYNC_CODE_2, 8);
322 
323         vp9enc_write_bitdepth_colorspace_sampling(0, wb);
324 
325         /* write the encoded frame size */
326         vp9enc_wb_write_literal(wb, pic_param->frame_width_dst - 1, 16);
327         vp9enc_wb_write_literal(wb, pic_param->frame_height_dst - 1, 16);
328         /* write display size */
329         if ((pic_param->frame_width_dst != pic_param->frame_width_src) ||
330             (pic_param->frame_height_dst != pic_param->frame_height_src)) {
331             vp9enc_wb_write_bit(wb, 1);
332             vp9enc_wb_write_literal(wb, pic_param->frame_width_src - 1, 16);
333             vp9enc_wb_write_literal(wb, pic_param->frame_height_src - 1, 16);
334         } else
335             vp9enc_wb_write_bit(wb, 0);
336     } else {
337         /* for the non-Key frame */
338         if (!pic_param->pic_flags.bits.show_frame)
339             vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.intra_only);
340 
341         if (!pic_param->pic_flags.bits.error_resilient_mode)
342             vp9enc_wb_write_literal(wb, pic_param->pic_flags.bits.reset_frame_context, 2);
343 
344         if (pic_param->pic_flags.bits.intra_only) {
345             vp9enc_wb_write_literal(wb, VP9_SYNC_CODE_0, 8);
346             vp9enc_wb_write_literal(wb, VP9_SYNC_CODE_1, 8);
347             vp9enc_wb_write_literal(wb, VP9_SYNC_CODE_2, 8);
348 
349             /* Add the bit_depth for VP9Profile1/2/3 */
350             /* write the refreshed_frame_flags */
351             vp9enc_wb_write_literal(wb, pic_param->refresh_frame_flags, REF_FRAMES);
352             /* write the encoded frame size */
353             vp9enc_wb_write_literal(wb, pic_param->frame_width_dst - 1, 16);
354             vp9enc_wb_write_literal(wb, pic_param->frame_height_dst - 1, 16);
355             /* write display size */
356             if ((pic_param->frame_width_dst != pic_param->frame_width_src) ||
357                 (pic_param->frame_height_dst != pic_param->frame_height_src)) {
358                 vp9enc_wb_write_bit(wb, 1);
359                 vp9enc_wb_write_literal(wb, pic_param->frame_width_src - 1, 16);
360                 vp9enc_wb_write_literal(wb, pic_param->frame_height_src - 1, 16);
361             } else
362                 vp9enc_wb_write_bit(wb, 0);
363 
364         } else {
365             /* The refresh_frame_map is  for the next frame so that it can select Last/Godlen/Alt ref_index */
366             vp9enc_wb_write_literal(wb, pic_param->refresh_frame_flags, REF_FRAMES);
367 
368             vp9enc_wb_write_literal(wb, pic_param->ref_flags.bits.ref_last_idx, REF_FRAMES_LOG2);
369             vp9enc_wb_write_bit(wb, pic_param->ref_flags.bits.ref_last_sign_bias);
370             vp9enc_wb_write_literal(wb, pic_param->ref_flags.bits.ref_gf_idx, REF_FRAMES_LOG2);
371             vp9enc_wb_write_bit(wb, pic_param->ref_flags.bits.ref_gf_sign_bias);
372             vp9enc_wb_write_literal(wb, pic_param->ref_flags.bits.ref_arf_idx, REF_FRAMES_LOG2);
373             vp9enc_wb_write_bit(wb, pic_param->ref_flags.bits.ref_arf_sign_bias);
374 
375             /* write three bits with zero so that it can parse width/height directly */
376             vp9enc_wb_write_literal(wb, 0, 3);
377             vp9enc_wb_write_literal(wb, pic_param->frame_width_dst - 1, 16);
378             vp9enc_wb_write_literal(wb, pic_param->frame_height_dst - 1, 16);
379 
380             /* write display size */
381             if ((pic_param->frame_width_dst != pic_param->frame_width_src) ||
382                 (pic_param->frame_height_dst != pic_param->frame_height_src)) {
383 
384                 vp9enc_wb_write_bit(wb, 1);
385                 vp9enc_wb_write_literal(wb, pic_param->frame_width_src - 1, 16);
386                 vp9enc_wb_write_literal(wb, pic_param->frame_height_src - 1, 16);
387             } else
388                 vp9enc_wb_write_bit(wb, 0);
389 
390             vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.allow_high_precision_mv);
391 
392 #define    SWITCHABLE_FILTER    4
393 #define    FILTER_MASK          3
394 
395             if (pic_param->pic_flags.bits.mcomp_filter_type == SWITCHABLE_FILTER)
396                 vp9enc_wb_write_bit(wb, 1);
397             else {
398                 const int filter_to_literal[4] = { 1, 0, 2, 3 };
399                 uint8_t filter_flag = pic_param->pic_flags.bits.mcomp_filter_type;
400                 filter_flag = filter_flag & FILTER_MASK;
401                 vp9enc_wb_write_bit(wb, 0);
402                 vp9enc_wb_write_literal(wb, filter_to_literal[filter_flag], 2);
403             }
404         }
405     }
406 
407     /* write refresh_frame_context/paralle frame_decoding */
408     if (!pic_param->pic_flags.bits.error_resilient_mode) {
409         vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.refresh_frame_context);
410         vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.frame_parallel_decoding_mode);
411     }
412 
413     vp9enc_wb_write_literal(wb, pic_param->pic_flags.bits.frame_context_idx, 2);
414 
415     /* write loop filter */
416     pic_param->bit_offset_lf_level = wb->bit_offset;
417     vp9enc_wb_write_literal(wb, pic_param->filter_level, 6);
418     vp9enc_wb_write_literal(wb, pic_param->sharpness_level, 3);
419 
420     {
421         int i, mode_flag;
422 
423         vp9enc_wb_write_bit(wb, 1);
424         vp9enc_wb_write_bit(wb, 1);
425         pic_param->bit_offset_ref_lf_delta = wb->bit_offset;
426         for (i = 0; i < 4; i++) {
427             /*
428              * This check is skipped to prepare the bit_offset_lf_ref
429             if (pic_param->ref_lf_delta[i] == 0) {
430                 vp9enc_wb_write_bit(wb, 0);
431                 continue;
432             }
433              */
434 
435             vp9enc_wb_write_bit(wb, 1);
436             mode_flag = pic_param->ref_lf_delta[i];
437             if (mode_flag >= 0) {
438                 vp9enc_wb_write_literal(wb, mode_flag & (0x3F), 6);
439                 vp9enc_wb_write_bit(wb, 0);
440             } else {
441                 mode_flag = -mode_flag;
442                 vp9enc_wb_write_literal(wb, mode_flag & (0x3F), 6);
443                 vp9enc_wb_write_bit(wb, 1);
444             }
445         }
446 
447         pic_param->bit_offset_mode_lf_delta = wb->bit_offset;
448         for (i = 0; i < 2; i++) {
449             /*
450              * This check is skipped to prepare the bit_offset_lf_ref
451             if (pic_param->mode_lf_delta[i] == 0) {
452                 vp9enc_wb_write_bit(wb, 0);
453                 continue;
454             }
455              */
456             vp9enc_wb_write_bit(wb, 1);
457             mode_flag = pic_param->mode_lf_delta[i];
458             if (mode_flag >= 0) {
459                 vp9enc_wb_write_literal(wb, mode_flag & (0x3F), 6);
460                 vp9enc_wb_write_bit(wb, 0);
461             } else {
462                 mode_flag = -mode_flag;
463                 vp9enc_wb_write_literal(wb, mode_flag & (0x3F), 6);
464                 vp9enc_wb_write_bit(wb, 1);
465             }
466         }
467     }
468 
469     /* write basic quantizer */
470     pic_param->bit_offset_qindex = wb->bit_offset;
471     vp9enc_wb_write_literal(wb, pic_param->luma_ac_qindex, 8);
472     if (pic_param->luma_dc_qindex_delta) {
473         int delta_q = pic_param->luma_dc_qindex_delta;
474         vp9enc_wb_write_bit(wb, 1);
475         vp9enc_wb_write_literal(wb, abs(delta_q), 4);
476         vp9enc_wb_write_bit(wb, delta_q < 0);
477     } else
478         vp9enc_wb_write_bit(wb, 0);
479 
480     if (pic_param->chroma_dc_qindex_delta) {
481         int delta_q = pic_param->chroma_dc_qindex_delta;
482         vp9enc_wb_write_bit(wb, 1);
483         vp9enc_wb_write_literal(wb, abs(delta_q), 4);
484         vp9enc_wb_write_bit(wb, delta_q < 0);
485     } else
486         vp9enc_wb_write_bit(wb, 0);
487 
488     if (pic_param->chroma_ac_qindex_delta) {
489         int delta_q = pic_param->chroma_ac_qindex_delta;
490         vp9enc_wb_write_bit(wb, 1);
491         vp9enc_wb_write_literal(wb, abs(delta_q), 4);
492         vp9enc_wb_write_bit(wb, delta_q < 0);
493     } else
494         vp9enc_wb_write_bit(wb, 0);
495 
496     /* segment is not enabled */
497     //vp9enc_wb_write_bit(wb, pic_param->pic_flags.bits.segmentation_enabled);
498     vp9enc_wb_write_bit(wb, 0);
499 
500     {
501         int sb_cols = (pic_param->frame_width_dst + 63) / 64;
502         int min_log2_tile_cols, max_log2_tile_cols;
503         int col_data;
504 
505         /* write tile column info */
506         min_log2_tile_cols = vp9enc_get_min_log2_tile_cols(sb_cols);
507         max_log2_tile_cols = vp9enc_get_max_log2_tile_cols(sb_cols);
508 
509         col_data = pic_param->log2_tile_columns - min_log2_tile_cols;
510         while (col_data--) {
511             vp9enc_wb_write_bit(wb, 1);
512         }
513         if (pic_param->log2_tile_columns < max_log2_tile_cols)
514             vp9enc_wb_write_bit(wb, 0);
515 
516         /* write tile row info */
517         vp9enc_wb_write_bit(wb, pic_param->log2_tile_rows);
518         if (pic_param->log2_tile_rows)
519             vp9enc_wb_write_bit(wb, (pic_param->log2_tile_rows != 1));
520     }
521 
522     /* get the bit_offset of the first partition size */
523     pic_param->bit_offset_first_partition_size = wb->bit_offset;
524 
525     /* reserve the space for writing the first partitions ize */
526     vp9enc_wb_write_literal(wb, 0, 16);
527 
528     *header_length = (wb->bit_offset + 7) / 8;
529 }
530 
531 static void
vp9enc_upload_yuv_to_surface(FILE * yuv_fp,VASurfaceID surface_id)532 vp9enc_upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id)
533 {
534     VAImage surface_image;
535     VAStatus va_status;
536     void *surface_p = NULL;
537     uint8_t *y_src, *u_src, *v_src;
538     uint8_t *y_dst, *u_dst, *v_dst;
539     int y_size = picture_width * picture_height;
540     int u_size = (picture_width >> 1) * (picture_height >> 1);
541     int row, col;
542     size_t n_items;
543 
544     do {
545         n_items = fread(newImageBuffer, frame_size, 1, yuv_fp);
546     } while (n_items != 1);
547 
548     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
549     CHECK_VASTATUS(va_status, "vaDeriveImage");
550 
551     vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
552     assert(VA_STATUS_SUCCESS == va_status);
553 
554     y_src = newImageBuffer;
555     u_src = newImageBuffer + y_size; /* UV offset for NV12 */
556     v_src = newImageBuffer + y_size + u_size;
557 
558     y_dst = (unsigned char *)surface_p + surface_image.offsets[0];
559     u_dst = (unsigned char *)surface_p +
560             surface_image.offsets[1]; /* UV offset for NV12 */
561     v_dst = (unsigned char *)surface_p + surface_image.offsets[2];
562 
563     /* Y plane */
564     for (row = 0; row < surface_image.height; row++) {
565         memcpy(y_dst, y_src, surface_image.width);
566         y_dst += surface_image.pitches[0];
567         y_src += picture_width;
568     }
569 
570     if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */
571         for (row = 0; row < surface_image.height / 2; row++) {
572             for (col = 0; col < surface_image.width / 2; col++) {
573                 u_dst[col * 2] = u_src[col];
574                 u_dst[col * 2 + 1] = v_src[col];
575             }
576 
577             u_dst += surface_image.pitches[1];
578             u_src += (picture_width / 2);
579             v_src += (picture_width / 2);
580         }
581     } else if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
582                surface_image.format.fourcc == VA_FOURCC_I420) {
583         const int U = surface_image.format.fourcc == VA_FOURCC_I420 ? 1 : 2;
584         const int V = surface_image.format.fourcc == VA_FOURCC_I420 ? 2 : 1;
585 
586         u_dst = (unsigned char *)surface_p + surface_image.offsets[U];
587         v_dst = (unsigned char *)surface_p + surface_image.offsets[V];
588 
589         for (row = 0; row < surface_image.height / 2; row++) {
590             memcpy(u_dst, u_src, surface_image.width / 2);
591             memcpy(v_dst, v_src, surface_image.width / 2);
592             u_dst += surface_image.pitches[U];
593             v_dst += surface_image.pitches[V];
594             u_src += (picture_width / 2);
595             v_src += (picture_width / 2);
596         }
597     }
598 
599     vaUnmapBuffer(va_dpy, surface_image.buf);
600     vaDestroyImage(va_dpy, surface_image.image_id);
601 }
602 
603 static void *
vp9enc_upload_thread_function(void * data)604 vp9enc_upload_thread_function(void *data)
605 {
606     struct upload_thread_param *param = data;
607 
608     vp9enc_upload_yuv_to_surface(param->yuv_fp, param->surface_id);
609 
610     return NULL;
611 }
612 
613 static void
vp9enc_alloc_encode_resource(FILE * yuv_fp)614 vp9enc_alloc_encode_resource(FILE *yuv_fp)
615 {
616     VAStatus va_status;
617     VASurfaceAttrib attrib;
618     int i;
619 
620     attrib.type = VASurfaceAttribPixelFormat;
621     attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
622     attrib.value.type = VAGenericValueTypeInteger;
623     attrib.value.value.i = VA_FOURCC_NV12;
624 
625     // Create surface
626     va_status = vaCreateSurfaces(
627                     va_dpy,
628                     VA_RT_FORMAT_YUV420, picture_width, picture_height,
629                     surface_ids, SID_NUMBER,
630                     &attrib, 1
631                 );
632 
633     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
634 
635     // Create surface
636     va_status = vaCreateSurfaces(
637                     va_dpy,
638                     VA_RT_FORMAT_YUV420, picture_width, picture_height,
639                     ref_surfaces, SURFACE_NUM,
640                     &attrib, 1
641                 );
642 
643     for (i = 0; i < SID_NUMBER; i++)
644         ref_surfaces[i + SURFACE_NUM] = surface_ids[i];
645 
646     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
647 
648     newImageBuffer = (uint8_t *)malloc(frame_size);
649 
650     /* firstly upload YUV data to SID_INPUT_PICTURE_0 */
651     vp9enc_context.upload_thread_param.yuv_fp = yuv_fp;
652     vp9enc_context.upload_thread_param.surface_id = surface_ids[SID_INPUT_PICTURE_0];
653 
654     vp9enc_context.upload_thread_value = pthread_create(&vp9enc_context.upload_thread_id,
655                                          NULL,
656                                          vp9enc_upload_thread_function,
657                                          (void*)&vp9enc_context.upload_thread_param);
658 }
659 
660 static void
vp9enc_create_encode_pipe(FILE * yuv_fp)661 vp9enc_create_encode_pipe(FILE *yuv_fp)
662 {
663     VAEntrypoint entrypoints[5];
664     int num_entrypoints, slice_entrypoint;
665     VAConfigAttrib attrib[2];
666     int major_ver, minor_ver;
667     VAStatus va_status;
668     int i;
669 
670     va_dpy = va_open_display();
671     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
672     CHECK_VASTATUS(va_status, "vaInitialize");
673 
674     vaQueryConfigEntrypoints(va_dpy, vp9enc_context.profile, entrypoints,
675                              &num_entrypoints);
676 
677     for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
678         if (select_entrypoint == -1) {
679             for (i = 0; i < 2; i++) {
680                 if (entrypoints[slice_entrypoint] == vp9enc_entrypoint_lists[i])
681                     break;
682             }
683 
684             if (i < 2) {
685                 select_entrypoint = i;
686                 break;
687             }
688         } else {
689             assert(select_entrypoint == 0 || select_entrypoint == 1);
690 
691             if (entrypoints[slice_entrypoint] == vp9enc_entrypoint_lists[select_entrypoint])
692                 break;
693         }
694     }
695 
696     if (slice_entrypoint == num_entrypoints) {
697         /* not find Slice entry point */
698         assert(0);
699     }
700 
701     /* find out the format for the render target, and rate control mode */
702     attrib[0].type = VAConfigAttribRTFormat;
703     attrib[1].type = VAConfigAttribRateControl;
704     vaGetConfigAttributes(va_dpy, vp9enc_context.profile, vp9enc_entrypoint_lists[select_entrypoint],
705                           &attrib[0], 2);
706 
707     if ((attrib[0].value & VA_RT_FORMAT_YUV420) == 0) {
708         /* not find desired YUV420 RT format */
709         assert(0);
710     }
711 
712     if ((attrib[1].value & vp9enc_context.rate_control_method) == 0) {
713         /* Can't find matched RC mode */
714         printf("Can't find the desired RC mode, exit\n");
715         assert(0);
716     }
717 
718     attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
719     attrib[1].value = vp9enc_context.rate_control_method; /* set to desired RC mode */
720 
721     va_status = vaCreateConfig(va_dpy, vp9enc_context.profile, vp9enc_entrypoint_lists[select_entrypoint],
722                                &attrib[0], 2, &vp9enc_context.config_id);
723     CHECK_VASTATUS(va_status, "vaCreateConfig");
724 
725     vp9enc_alloc_encode_resource(yuv_fp);
726 
727     /* Create a context for this decode pipe */
728     /* the surface is added to the render_target list when creating the context */
729     va_status = vaCreateContext(va_dpy, vp9enc_context.config_id,
730                                 picture_width, picture_height,
731                                 VA_PROGRESSIVE,
732                                 ref_surfaces, SURFACE_NUM + 2,
733                                 &vp9enc_context.context_id);
734     CHECK_VASTATUS(va_status, "vaCreateContext");
735 }
736 
737 static void
vp9enc_destory_encode_pipe()738 vp9enc_destory_encode_pipe()
739 {
740     vaDestroyContext(va_dpy, vp9enc_context.context_id);
741     vaDestroyConfig(va_dpy, vp9enc_context.config_id);
742     vaTerminate(va_dpy);
743     va_close_display(va_dpy);
744 }
745 
746 static void
vp9enc_release_encode_resource()747 vp9enc_release_encode_resource()
748 {
749     pthread_join(vp9enc_context.upload_thread_id, NULL);
750     free(newImageBuffer);
751 
752     vaDestroySurfaces(va_dpy, surface_ids, SID_NUMBER);
753     vaDestroySurfaces(va_dpy, ref_surfaces, SURFACE_NUM);
754 }
755 
756 static int
vp9enc_get_free_slot()757 vp9enc_get_free_slot()
758 {
759     int i, index = -1;
760 
761     for (i = 0; i < SURFACE_NUM; i++) {
762         if (use_slot[i] == 0) {
763             index = i;
764             break;
765         }
766     }
767 
768     if (index < 0) {
769         printf("WARNING: No free slot to store the reconstructed frame \n");
770         index = SURFACE_NUM - 1;
771     }
772 
773     return index;
774 }
775 
776 static void
vp9enc_update_reference_list(void)777 vp9enc_update_reference_list(void)
778 {
779     VASurfaceID last_surf;
780     int last_slot;
781     int i;
782 
783     /* Todo: Add the full support of reference frames */
784 
785     if (current_frame_type == KEY_FRAME) {
786         memset(use_slot, 0, sizeof(use_slot));
787         use_slot[current_slot] = 1;
788         for (i = 0; i < SURFACE_NUM; i++)
789             vp9_ref_list[i] = ref_surfaces[current_slot];
790 
791         return;
792     }
793 
794     last_slot = -1;
795     use_slot[current_slot] = 1;
796     last_surf = vp9_ref_list[0];
797 
798     vp9_ref_list[0] = ref_surfaces[current_slot];
799 
800     for (i = 0; i < SURFACE_NUM; i++) {
801         if (ref_surfaces[i] == last_surf) {
802             last_slot = i;
803             break;
804         }
805     }
806 
807     if (last_slot != -1) {
808         int used_flag = 0;
809 
810         for (i = 1; i < SURFACE_NUM; i++) {
811             if (vp9_ref_list[i] == last_surf) {
812                 used_flag = 1;
813                 break;
814             }
815         }
816 
817         if (!used_flag)
818             use_slot[last_slot] = 0;
819     }
820 }
821 
822 static void
vp9enc_update_picture_parameter(int frame_type)823 vp9enc_update_picture_parameter(int frame_type)
824 {
825     VAEncPictureParameterBufferVP9 *pic_param;
826     int recon_index;
827     VASurfaceID current_surface;
828     int ref_num = 0;
829     int i = 0;
830 
831     recon_index = vp9enc_get_free_slot();
832     current_slot = recon_index;
833     current_surface = ref_surfaces[recon_index];
834 
835     pic_param = &vp9enc_context.pic_param;
836 
837     pic_param->reconstructed_frame = current_surface;
838     pic_param->coded_buf = vp9enc_context.codedbuf_buf_id;
839 
840     ref_num = sizeof(pic_param->reference_frames) / sizeof(VASurfaceID);
841 
842     if (frame_type == KEY_FRAME) {
843         pic_param->pic_flags.bits.frame_type = KEY_FRAME;
844         pic_param->pic_flags.bits.frame_context_idx = 0;
845         pic_param->ref_flags.bits.ref_last_idx = 0;
846         pic_param->ref_flags.bits.ref_gf_idx = 0;
847         pic_param->ref_flags.bits.ref_arf_idx = 0;
848         pic_param->pic_flags.bits.frame_context_idx = 0;
849         pic_param->ref_flags.bits.ref_frame_ctrl_l0 = 0;
850 
851         for (i = 0; i < ref_num; i++)
852             pic_param->reference_frames[i] = VA_INVALID_ID;
853     } else {
854         pic_param->refresh_frame_flags = 0x01;
855         pic_param->pic_flags.bits.frame_type = INTER_FRAME;
856         pic_param->ref_flags.bits.ref_frame_ctrl_l0 = 0x7;
857 
858         pic_param->ref_flags.bits.ref_last_idx = 0;
859         pic_param->ref_flags.bits.ref_gf_idx = 1;
860         pic_param->ref_flags.bits.ref_arf_idx = 2;
861         pic_param->pic_flags.bits.frame_context_idx = 0;
862 
863         memcpy(&pic_param->reference_frames, vp9_ref_list, sizeof(vp9_ref_list));
864     }
865 }
866 
867 static void
vp9enc_create_picture_parameter_buf()868 vp9enc_create_picture_parameter_buf()
869 {
870     VAStatus va_status;
871 
872     va_status = vaCreateBuffer(va_dpy,
873                                vp9enc_context.context_id,
874                                VAEncPictureParameterBufferType,
875                                sizeof(vp9enc_context.pic_param), 1,
876                                &vp9enc_context.pic_param,
877                                &vp9enc_context.pic_param_buf_id);
878     CHECK_VASTATUS(va_status, "vaCreateBuffer");
879 }
880 
881 static void
vp9enc_begin_picture(FILE * yuv_fp,int frame_num,int frame_type)882 vp9enc_begin_picture(FILE *yuv_fp, int frame_num, int frame_type)
883 {
884     VAStatus va_status;
885 
886     if (vp9enc_context.upload_thread_value != 0) {
887         fprintf(stderr, "FATAL error!!!\n");
888         exit(1);
889     }
890 
891     pthread_join(vp9enc_context.upload_thread_id, NULL);
892 
893     vp9enc_context.upload_thread_value = -1;
894 
895     /* sequence parameter set */
896     VAEncSequenceParameterBufferVP9 *seq_param = &vp9enc_context.seq_param;
897     va_status = vaCreateBuffer(va_dpy,
898                                vp9enc_context.context_id,
899                                VAEncSequenceParameterBufferType,
900                                sizeof(*seq_param), 1, seq_param,
901                                &vp9enc_context.seq_param_buf_id);
902     CHECK_VASTATUS(va_status, "vaCreateBuffer");
903 
904     /* hrd parameter */
905     VAEncMiscParameterBuffer *misc_param;
906     VAEncMiscParameterHRD *misc_hrd_param;
907     va_status = vaCreateBuffer(va_dpy,
908                    vp9enc_context.context_id,
909                    VAEncMiscParameterBufferType,
910                    sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl),
911                    1,
912                    NULL,
913                    &vp9enc_context.misc_parameter_hrd_buf_id);
914     CHECK_VASTATUS(va_status, "vaCreateBuffer");
915 
916     vaMapBuffer(va_dpy,
917                 vp9enc_context.misc_parameter_hrd_buf_id,
918                 (void **)&misc_param);
919 
920     misc_param->type = VAEncMiscParameterTypeHRD;
921     misc_hrd_param = (VAEncMiscParameterHRD *)misc_param->data;
922 
923     if (frame_bit_rate > 0) {
924         misc_hrd_param->initial_buffer_fullness = frame_bit_rate * hrd_window / 2;
925         misc_hrd_param->buffer_size = frame_bit_rate * hrd_window;
926     } else {
927         misc_hrd_param->initial_buffer_fullness = 0;
928         misc_hrd_param->buffer_size = 0;
929     }
930 
931     vaUnmapBuffer(va_dpy, vp9enc_context.misc_parameter_hrd_buf_id);
932 
933     VAEncMiscParameterTypeVP9PerSegmantParam seg_param;
934 
935     memset(&seg_param, 0, sizeof(seg_param));
936 
937     va_status = vaCreateBuffer(va_dpy,
938                                vp9enc_context.context_id,
939                                VAQMatrixBufferType,
940                                sizeof(seg_param), 1, &seg_param,
941                                &vp9enc_context.qmatrix_buf_id);
942     CHECK_VASTATUS(va_status, "vaCreateBuffer");
943 
944     /* Create the Misc FR/RC buffer under non-CQP mode */
945     if (rc_mode != VA_RC_CQP && frame_type == KEY_FRAME) {
946         VAEncMiscParameterFrameRate *misc_fr;
947         VAEncMiscParameterRateControl *misc_rc;
948 
949         va_status = vaCreateBuffer(va_dpy,
950                        vp9enc_context.context_id,
951                        VAEncMiscParameterBufferType,
952                        sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterFrameRate),
953                        1,
954                        NULL,
955                        &vp9enc_context.misc_fr_buf_id);
956         CHECK_VASTATUS(va_status, "vaCreateBuffer");
957 
958         vaMapBuffer(va_dpy,
959                     vp9enc_context.misc_fr_buf_id,
960                     (void **)&misc_param);
961         misc_param->type = VAEncMiscParameterTypeFrameRate;
962         misc_fr = (VAEncMiscParameterFrameRate *)misc_param->data;
963         misc_fr->framerate = frame_rate;
964         vaUnmapBuffer(va_dpy, vp9enc_context.misc_fr_buf_id);
965 
966         va_status = vaCreateBuffer(va_dpy,
967                        vp9enc_context.context_id,
968                        VAEncMiscParameterBufferType,
969                        sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl),
970                        1,
971                        NULL,
972                        &vp9enc_context.misc_rc_buf_id);
973         CHECK_VASTATUS(va_status, "vaCreateBuffer");
974 
975         vaMapBuffer(va_dpy,
976                     vp9enc_context.misc_rc_buf_id,
977                     (void **)&misc_param);
978         misc_param->type = VAEncMiscParameterTypeRateControl;
979         misc_rc = (VAEncMiscParameterRateControl *)misc_param->data;
980 
981         misc_rc->bits_per_second = frame_bit_rate * 1000;
982         misc_rc->window_size = hrd_window;
983         misc_rc->initial_qp = qp_value;
984         /* The target percentage is only for VBR. It is ignored in CBR */
985         misc_rc->target_percentage = 95;
986         if (rc_mode == VA_RC_VBR) {
987             misc_rc->bits_per_second = vbr_max * 1000;
988             misc_rc->target_percentage = (frame_bit_rate * 100) / vbr_max;
989         }
990         vaUnmapBuffer(va_dpy, vp9enc_context.misc_rc_buf_id);
991     }
992 }
993 
994 static void
vp9enc_render_picture()995 vp9enc_render_picture()
996 {
997     VAStatus va_status;
998     VABufferID va_buffers[10];
999     uint32_t num_va_buffers = 0;
1000 
1001     va_buffers[num_va_buffers++] = vp9enc_context.seq_param_buf_id;
1002     va_buffers[num_va_buffers++] = vp9enc_context.pic_param_buf_id;
1003 
1004     if (vp9enc_context.misc_parameter_hrd_buf_id != VA_INVALID_ID)
1005         va_buffers[num_va_buffers++] =  vp9enc_context.misc_parameter_hrd_buf_id;
1006 
1007     if (vp9enc_context.qmatrix_buf_id != VA_INVALID_ID)
1008         va_buffers[num_va_buffers++] =  vp9enc_context.qmatrix_buf_id;
1009 
1010     if (vp9enc_context.mb_seg_buf_id != VA_INVALID_ID)
1011         va_buffers[num_va_buffers++] =  vp9enc_context.mb_seg_buf_id;
1012 
1013     if (vp9enc_context.raw_data_header_buf_id != VA_INVALID_ID)
1014         va_buffers[num_va_buffers++] = vp9enc_context.raw_data_header_buf_id;
1015 
1016     if (vp9enc_context.raw_data_buf_id != VA_INVALID_ID)
1017         va_buffers[num_va_buffers++] = vp9enc_context.raw_data_buf_id;
1018 
1019     if (vp9enc_context.misc_fr_buf_id != VA_INVALID_ID)
1020         va_buffers[num_va_buffers++] = vp9enc_context.misc_fr_buf_id;
1021 
1022     if (vp9enc_context.misc_rc_buf_id != VA_INVALID_ID)
1023         va_buffers[num_va_buffers++] = vp9enc_context.misc_rc_buf_id;
1024 
1025     va_status = vaBeginPicture(va_dpy,
1026                                vp9enc_context.context_id,
1027                                surface_ids[vp9enc_context.current_input_surface]);
1028     CHECK_VASTATUS(va_status, "vaBeginPicture");
1029 
1030     va_status = vaRenderPicture(va_dpy,
1031                                 vp9enc_context.context_id,
1032                                 va_buffers,
1033                                 num_va_buffers);
1034     CHECK_VASTATUS(va_status, "vaRenderPicture");
1035 
1036     va_status = vaEndPicture(va_dpy, vp9enc_context.context_id);
1037     CHECK_VASTATUS(va_status, "vaEndPicture");
1038 }
1039 
1040 static void
vp9enc_destroy_buffers(VABufferID * va_buffers,uint32_t num_va_buffers)1041 vp9enc_destroy_buffers(VABufferID *va_buffers, uint32_t num_va_buffers)
1042 {
1043     VAStatus va_status;
1044     uint32_t i;
1045 
1046     for (i = 0; i < num_va_buffers; i++) {
1047         if (va_buffers[i] != VA_INVALID_ID) {
1048             va_status = vaDestroyBuffer(va_dpy, va_buffers[i]);
1049             CHECK_VASTATUS(va_status, "vaDestroyBuffer");
1050             va_buffers[i] = VA_INVALID_ID;
1051         }
1052     }
1053 }
1054 
1055 static void
vp9enc_write_frame_header(FILE * vp9_output,int frame_size)1056 vp9enc_write_frame_header(FILE *vp9_output, int frame_size)
1057 {
1058     char header[12];
1059 
1060     vp9enc_write_dword(header, (uint32_t)frame_size);
1061     vp9enc_write_dword(header + 4, 0);
1062     vp9enc_write_dword(header + 8, 0);
1063 
1064     fwrite(header, 1, 12, vp9_output);
1065 }
1066 
1067 static int
vp9enc_store_coded_buffer(FILE * vp9_fp,int frame_type)1068 vp9enc_store_coded_buffer(FILE *vp9_fp, int frame_type)
1069 {
1070     VACodedBufferSegment *coded_buffer_segment;
1071     uint8_t *coded_mem;
1072     int data_length;
1073     VAStatus va_status;
1074     VASurfaceStatus surface_status;
1075     size_t w_items;
1076 
1077     va_status = vaSyncSurface(va_dpy, surface_ids[vp9enc_context.current_input_surface]);
1078     CHECK_VASTATUS(va_status, "vaSyncSurface");
1079 
1080     surface_status = 0;
1081     va_status = vaQuerySurfaceStatus(va_dpy, surface_ids[vp9enc_context.current_input_surface], &surface_status);
1082     CHECK_VASTATUS(va_status, "vaQuerySurfaceStatus");
1083 
1084     va_status = vaMapBuffer(va_dpy, vp9enc_context.codedbuf_buf_id, (void **)(&coded_buffer_segment));
1085     CHECK_VASTATUS(va_status, "vaMapBuffer");
1086     coded_mem = coded_buffer_segment->buf;
1087 
1088     if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
1089         if (frame_type == KEY_FRAME)
1090             vp9enc_context.codedbuf_i_size *= 2;
1091         else
1092             vp9enc_context.codedbuf_pb_size *= 2;
1093 
1094         vaUnmapBuffer(va_dpy, vp9enc_context.codedbuf_buf_id);
1095         return -1;
1096     }
1097 
1098     data_length = coded_buffer_segment->size;
1099 
1100     vp9enc_write_frame_header(vp9_fp, data_length);
1101 
1102     do {
1103         w_items = fwrite(coded_mem, data_length, 1, vp9_fp);
1104     } while (w_items != 1);
1105 
1106     vaUnmapBuffer(va_dpy, vp9enc_context.codedbuf_buf_id);
1107 
1108     return 0;
1109 }
1110 
1111 static void
vp9enc_write_ivf_header(FILE * vp9_file,int width,int height,int frame_num,int frame_rate)1112 vp9enc_write_ivf_header(FILE *vp9_file,
1113                         int width, int height,
1114                         int frame_num,
1115                         int frame_rate)
1116 {
1117 
1118 #define VP9_FOURCC    0x30395056
1119 
1120     char header[32];
1121 
1122     header[0] = 'D';
1123     header[1] = 'K';
1124     header[2] = 'I';
1125     header[3] = 'F';
1126 
1127     vp9enc_write_word(header + 4, 0);
1128     vp9enc_write_word(header + 6, 32);
1129     vp9enc_write_dword(header + 8, VP9_FOURCC);
1130     vp9enc_write_word(header + 12, width);
1131     vp9enc_write_word(header + 14, height);
1132     vp9enc_write_dword(header + 16, 1);
1133     vp9enc_write_dword(header + 20, frame_rate);
1134     vp9enc_write_dword(header + 24, frame_num);
1135     vp9enc_write_dword(header + 28, 0);
1136 
1137     fwrite(header, 1, 32, vp9_file);
1138 }
1139 
1140 static void
vp9enc_get_frame_type(int encoding_order,int gop_size,int ip_period,int * frame_type)1141 vp9enc_get_frame_type(int encoding_order,
1142                       int gop_size,
1143                       int ip_period,
1144                       int *frame_type)
1145 {
1146     if (ip_period == 0 ||
1147         (encoding_order % gop_size == 0))
1148         *frame_type = KEY_FRAME;
1149     else
1150         *frame_type = INTER_FRAME;
1151 }
1152 
1153 static void
vp9enc_end_picture()1154 vp9enc_end_picture()
1155 {
1156     vp9enc_destroy_buffers(&vp9enc_context.seq_param_buf_id, 1);
1157     vp9enc_destroy_buffers(&vp9enc_context.pic_param_buf_id, 1);
1158     vp9enc_destroy_buffers(&vp9enc_context.codedbuf_buf_id, 1);
1159     vp9enc_destroy_buffers(&vp9enc_context.qmatrix_buf_id, 1);
1160     vp9enc_destroy_buffers(&vp9enc_context.misc_parameter_hrd_buf_id, 1);
1161     vp9enc_destroy_buffers(&vp9enc_context.mb_seg_buf_id, 1);
1162     vp9enc_destroy_buffers(&vp9enc_context.raw_data_header_buf_id, 1);
1163     vp9enc_destroy_buffers(&vp9enc_context.raw_data_buf_id, 1);
1164     vp9enc_destroy_buffers(&vp9enc_context.misc_fr_buf_id, 1);
1165     vp9enc_destroy_buffers(&vp9enc_context.misc_rc_buf_id, 1);
1166 
1167     if (vp9enc_context.current_input_surface == SID_INPUT_PICTURE_0)
1168         vp9enc_context.current_input_surface = SID_INPUT_PICTURE_1;
1169     else
1170         vp9enc_context.current_input_surface = SID_INPUT_PICTURE_0;
1171 }
1172 
1173 static void
vp9enc_encode_picture(FILE * yuv_fp,FILE * vp9_fp,int frame_num,int frame_type,int next_enc_frame)1174 vp9enc_encode_picture(FILE *yuv_fp, FILE *vp9_fp,
1175                       int frame_num,
1176                       int frame_type,
1177                       int next_enc_frame)
1178 {
1179     VAStatus va_status;
1180     int ret = 0, codedbuf_size;
1181 
1182     vp9enc_begin_picture(yuv_fp, frame_num, frame_type);
1183 
1184     if (next_enc_frame < frame_num) {
1185         int index;
1186 
1187         /* prepare for next frame */
1188         if (vp9enc_context.current_input_surface == SID_INPUT_PICTURE_0)
1189             index = SID_INPUT_PICTURE_1;
1190         else
1191             index = SID_INPUT_PICTURE_0;
1192 
1193         ret = fseeko(yuv_fp, (off_t)frame_size * next_enc_frame, SEEK_SET);
1194         CHECK_CONDITION(ret == 0);
1195 
1196         vp9enc_context.upload_thread_param.yuv_fp = yuv_fp;
1197         vp9enc_context.upload_thread_param.surface_id = surface_ids[index];
1198 
1199         vp9enc_context.upload_thread_value = pthread_create(&vp9enc_context.upload_thread_id,
1200                                              NULL,
1201                                              vp9enc_upload_thread_function,
1202                                              (void*)&vp9enc_context.upload_thread_param);
1203     }
1204 
1205     do {
1206         vp9enc_destroy_buffers(&vp9enc_context.codedbuf_buf_id, 1);
1207         vp9enc_destroy_buffers(&vp9enc_context.pic_param_buf_id, 1);
1208 
1209         if (frame_type == KEY_FRAME)
1210             codedbuf_size = vp9enc_context.codedbuf_i_size;
1211         else
1212             codedbuf_size = vp9enc_context.codedbuf_pb_size;
1213 
1214         /* coded buffer */
1215         va_status = vaCreateBuffer(va_dpy,
1216                                    vp9enc_context.context_id,
1217                                    VAEncCodedBufferType,
1218                                    codedbuf_size, 1, NULL,
1219                                    &vp9enc_context.codedbuf_buf_id);
1220         CHECK_VASTATUS(va_status, "vaCreateBuffer");
1221 
1222         /* picture parameter set */
1223         vp9enc_update_picture_parameter(current_frame_type);
1224 
1225         if (opt_header) {
1226             char raw_data[64];
1227             int raw_data_length;
1228             VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
1229 
1230             memset(raw_data, 0, sizeof(raw_data));
1231             vp9enc_write_uncompressed_header(&vp9enc_context,
1232                                              raw_data,
1233                                              &raw_data_length);
1234 
1235             packed_header_param_buffer.type = VAEncPackedHeaderRawData;
1236             packed_header_param_buffer.bit_length = raw_data_length * 8;
1237             packed_header_param_buffer.has_emulation_bytes = 0;
1238 
1239             va_status = vaCreateBuffer(va_dpy,
1240                            vp9enc_context.context_id,
1241                            VAEncPackedHeaderParameterBufferType,
1242                            sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
1243                            &vp9enc_context.raw_data_header_buf_id);
1244             CHECK_VASTATUS(va_status, "vaCreateBuffer");
1245 
1246             va_status = vaCreateBuffer(va_dpy,
1247                            vp9enc_context.context_id,
1248                            VAEncPackedHeaderDataBufferType,
1249                            raw_data_length, 1, raw_data,
1250                            &vp9enc_context.raw_data_buf_id);
1251             CHECK_VASTATUS(va_status, "vaCreateBuffer");
1252         }
1253 
1254         vp9enc_create_picture_parameter_buf();
1255 
1256         vp9enc_render_picture();
1257 
1258         ret = vp9enc_store_coded_buffer(vp9_fp, current_frame_type);
1259     } while (ret);
1260 
1261     vp9enc_update_reference_list();
1262 
1263     vp9enc_end_picture();
1264 }
1265 
1266 static void
vp9enc_context_seq_param_init(VAEncSequenceParameterBufferVP9 * seq_param,int width,int height)1267 vp9enc_context_seq_param_init(VAEncSequenceParameterBufferVP9 *seq_param,
1268                               int width, int height)
1269 {
1270     seq_param->intra_period = intra_period;
1271     seq_param->max_frame_width = width;
1272     seq_param->max_frame_height = height;
1273     seq_param->kf_auto = 0;
1274     seq_param->kf_min_dist = 1;
1275     seq_param->kf_max_dist = intra_period;
1276 
1277     if (frame_bit_rate > 0)
1278         seq_param->bits_per_second = 1000 * frame_bit_rate; /* use kbps as input */
1279     else
1280         seq_param->bits_per_second = 0;
1281 }
1282 
1283 static void
vp9enc_context_pic_param_init(VAEncPictureParameterBufferVP9 * pic_param,int width,int height)1284 vp9enc_context_pic_param_init(VAEncPictureParameterBufferVP9 *pic_param,
1285                               int width, int height)
1286 {
1287     int i, ref_num;
1288 
1289     memset(pic_param, 0, sizeof(VAEncPictureParameterBufferVP9));
1290 
1291     ref_num = sizeof(pic_param->reference_frames) / sizeof(VASurfaceID);
1292     for (i = 0; i < ref_num; i++)
1293         pic_param->reference_frames[i] = VA_INVALID_ID;
1294 
1295     pic_param->coded_buf = VA_INVALID_ID;
1296     pic_param->reconstructed_frame = VA_INVALID_ID;
1297 
1298     pic_param->frame_width_src = width;
1299     pic_param->frame_height_src = height;
1300     pic_param->frame_width_dst = width;
1301     pic_param->frame_height_dst = height;
1302 
1303     pic_param->ref_flags.bits.force_kf = 0;
1304     /* always show it */
1305     pic_param->pic_flags.bits.show_frame = 1;
1306     /* Not use silience mode */
1307     pic_param->pic_flags.bits.error_resilient_mode = 0;
1308     /* Not use the frame parallel mode */
1309     pic_param->pic_flags.bits.frame_parallel_decoding_mode = 0;
1310 
1311     pic_param->luma_ac_qindex = qp_value;
1312     pic_param->luma_dc_qindex_delta = 1;
1313     pic_param->chroma_ac_qindex_delta = 1;
1314     pic_param->chroma_dc_qindex_delta = 1;
1315     /* use the zero sharpness_level/lf_ref&mode deltas */
1316     pic_param->filter_level = lf_level;
1317 
1318     for (i = 0; i < 4; i++)
1319         pic_param->ref_lf_delta[i] = 1;
1320 
1321     for (i = 0; i < 2; i++)
1322         pic_param->mode_lf_delta[i] = 1;
1323 }
1324 
1325 
1326 static void
vp9enc_context_init(int width,int height)1327 vp9enc_context_init(int width, int height)
1328 {
1329     memset(&vp9enc_context, 0, sizeof(vp9enc_context));
1330     vp9enc_context.profile = VAProfileVP9Profile0;
1331 
1332     memset(&use_slot, 0, sizeof(use_slot));
1333 
1334     vp9enc_context.seq_param_buf_id = VA_INVALID_ID;
1335     vp9enc_context.pic_param_buf_id = VA_INVALID_ID;
1336     vp9enc_context.mb_seg_buf_id = VA_INVALID_ID;
1337     vp9enc_context.misc_parameter_hrd_buf_id = VA_INVALID_ID;
1338     vp9enc_context.qmatrix_buf_id = VA_INVALID_ID;
1339     vp9enc_context.codedbuf_buf_id = VA_INVALID_ID;
1340     vp9enc_context.raw_data_header_buf_id = VA_INVALID_ID;
1341     vp9enc_context.raw_data_buf_id = VA_INVALID_ID;
1342     vp9enc_context.misc_fr_buf_id = VA_INVALID_ID;
1343     vp9enc_context.misc_rc_buf_id = VA_INVALID_ID;
1344 
1345     vp9enc_context.codedbuf_i_size = width * height;
1346     vp9enc_context.codedbuf_pb_size = width * height;
1347     vp9enc_context.current_input_surface = SID_INPUT_PICTURE_0;
1348     vp9enc_context.upload_thread_value = -1;
1349 
1350     vp9enc_context.rate_control_method = rc_mode;
1351 
1352     vp9enc_context_seq_param_init(&vp9enc_context.seq_param, 8192, 8192);
1353     vp9enc_context_pic_param_init(&vp9enc_context.pic_param, width, height);
1354 }
1355 
1356 static void
vp9enc_show_help()1357 vp9enc_show_help()
1358 {
1359     printf("Usage: vp9encode <width> <height> <input_yuvfile> <output_vp9> additional_option\n");
1360     printf("output_vp9 should use *.ivf\n");
1361     printf("The additional option is listed\n");
1362     printf("-f <frame rate> \n");
1363     printf("--intra_period <key_frame interval>\n");
1364     printf("--qp <quantization parameter> \n");
1365     printf("--rcmode <rate control mode> 0: CQP, 1: CBR, 2: VBR\n");
1366     printf("--fb <bitrate> (kbps unit)\n");
1367     printf("--lf_level <loop filter level>  [0-63]\n");
1368     printf("--hrd_win <num>  [1000-8000]\n");
1369     printf("--vbr_max <num> (kbps unit. It should be greater than fb)\n");
1370     printf("--opt_header \n  write the uncompressed header manually. without this, the driver will add those headers by itself\n");
1371     printf("--fn_num <num>\n  how many frames to be encoded\n");
1372     printf("--low_power <num> 0: Normal mode, 1: Low power mode, others: auto mode\n");
1373 }
1374 
1375 int
main(int argc,char * argv[])1376 main(int argc, char *argv[])
1377 {
1378     char *yuv_input, *vp9_output, *tmp_vp9;
1379     FILE *yuv_fp;
1380     FILE *vp9_fp;
1381     off_t file_size;
1382     struct timeval tpstart, tpend;
1383     float  timeuse;
1384     int ip_period;
1385     int fn_num;
1386     int frame_idx;
1387 
1388     va_init_display_args(&argc, argv);
1389 
1390     //TODO may be we should using option analytics library
1391     if (argc < 5) {
1392         vp9enc_show_help();
1393         exit(0);
1394     }
1395 
1396     picture_width = atoi(argv[1]);
1397     picture_height = atoi(argv[2]);
1398     yuv_input = argv[3];
1399     vp9_output = argv[4];
1400     fn_num = -1;
1401 
1402     if (!yuv_input || !vp9_output) {
1403         vp9enc_show_help();
1404         exit(0);
1405     }
1406 
1407     tmp_vp9 = strdup(argv[4]);
1408     assert(tmp_vp9);
1409 
1410     if (!strstr(tmp_vp9, ".ivf")) {
1411         free(tmp_vp9);
1412         vp9enc_show_help();
1413         exit(0);
1414     }
1415 
1416     free(tmp_vp9);
1417 
1418     rc_mode = VA_RC_CQP;
1419     frame_rate = 30;
1420     qp_value = 60;
1421     intra_period = 30;
1422     frame_bit_rate = -1;
1423     vbr_max = -1;
1424     if (argc > 5) {
1425         int c, long_index, tmp_input;
1426         while (1) {
1427             c = getopt_long_only(argc - 4, argv + 4, "hf:?", long_opts, &long_index);
1428 
1429             if (c == -1)
1430                 break;
1431 
1432             switch (c) {
1433             case 'h':
1434             case 0:
1435                 vp9enc_show_help();
1436                 exit(0);
1437                 break;
1438             case 'f':
1439                 frame_rate = atoi(optarg);
1440                 break;
1441             case 1:
1442                 tmp_input = atoi(optarg);
1443                 if (tmp_input > 3 || tmp_input < 0)
1444                     tmp_input = 0;
1445                 rc_mode = rc_default_mode[tmp_input];
1446                 break;
1447             case 2:
1448                 tmp_input = atoi(optarg);
1449                 if (tmp_input < 0 || tmp_input > 255)
1450                     tmp_input = 60;
1451                 qp_value = tmp_input;
1452                 break;
1453             case 3:
1454                 tmp_input = atoi(optarg);
1455                 if (tmp_input < 0)
1456                     tmp_input = 30;
1457                 intra_period = tmp_input;
1458                 break;
1459             case 4:
1460                 tmp_input = atoi(optarg);
1461                 frame_bit_rate = tmp_input;
1462                 break;
1463             case 6:
1464                 tmp_input = atoi(optarg);
1465                 if (tmp_input < 0 || tmp_input > 63)
1466                     tmp_input = 10;
1467                 lf_level = tmp_input;
1468                 break;
1469             case 7:
1470                 tmp_input = atoi(optarg);
1471                 if (tmp_input)
1472                     tmp_input = 1;
1473                 opt_header = tmp_input;
1474                 break;
1475             case 8:
1476                 tmp_input = atoi(optarg);
1477                 if (tmp_input > 8000 || tmp_input < 1000)
1478                     tmp_input = 1500;
1479                 hrd_window = tmp_input;
1480                 break;
1481             case 9:
1482                 tmp_input = atoi(optarg);
1483                 if (tmp_input < 0)
1484                     tmp_input = 20000;
1485                 else if (tmp_input > 100000)
1486                     tmp_input = 100000;
1487                 vbr_max = tmp_input;
1488                 break;
1489             case 10:
1490                 tmp_input = atoi(optarg);
1491                 fn_num = tmp_input;
1492                 break;
1493             case 11:
1494                 tmp_input = atoi(optarg);
1495 
1496                 if (tmp_input == 0 || tmp_input == 1)
1497                     select_entrypoint = tmp_input;
1498                 else
1499                     select_entrypoint = -1;
1500 
1501                 break;
1502 
1503             default:
1504                 vp9enc_show_help();
1505                 exit(0);
1506                 break;
1507             }
1508         }
1509     }
1510 
1511     if (rc_mode != VA_RC_CQP && (frame_bit_rate < 0)) {
1512         printf("Please specifiy the bit rate for CBR/VBR\n");
1513         vp9enc_show_help();
1514         exit(0);
1515     }
1516 
1517     if (rc_mode == VA_RC_VBR) {
1518         if (vbr_max < 0) {
1519             vbr_max = frame_bit_rate;
1520             frame_bit_rate = (vbr_max * 95 / 100);
1521         }
1522 
1523         if (vbr_max < frame_bit_rate) {
1524             printf("Under VBR, the max bit rate should be greater than or equal to fb\n");
1525             vp9enc_show_help();
1526             exit(0);
1527         }
1528 
1529         if (vbr_max > (frame_bit_rate * 2)) {
1530             printf("under VBR, the max bit rate is too much greater than the average bit\n");
1531             vp9enc_show_help();
1532             exit(0);
1533         }
1534     }
1535 
1536     yuv_fp = fopen(yuv_input, "rb");
1537     if (yuv_fp == NULL) {
1538         printf("Can't open input YUV file\n");
1539         return -1;
1540     }
1541     fseeko(yuv_fp, (off_t)0, SEEK_END);
1542     file_size = ftello(yuv_fp);
1543     frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ;
1544 
1545     if (frame_size == 0) {
1546         fclose(yuv_fp);
1547         printf("Frame size is not correct\n");
1548         return -1;
1549     }
1550     if ((file_size < frame_size) || (file_size % frame_size)) {
1551         fclose(yuv_fp);
1552         printf("The YUV file's size is not correct\n");
1553         return -1;
1554     }
1555     frame_number = file_size / frame_size;
1556     fseeko(yuv_fp, (off_t)0, SEEK_SET);
1557 
1558     if (fn_num > 0 && fn_num <= frame_number)
1559         frame_number = fn_num;
1560 
1561     vp9_fp = fopen(vp9_output, "wb");
1562     if (vp9_fp == NULL) {
1563         fclose(yuv_fp);
1564         printf("Can't open output avc file\n");
1565         return -1;
1566     }
1567 
1568     if (intra_period == 0)
1569         intra_period = frame_number;
1570 
1571     ip_period = 1;
1572     if (intra_period == 1)
1573         ip_period = 0;
1574 
1575     gettimeofday(&tpstart, NULL);
1576 
1577     vp9enc_write_ivf_header(vp9_fp, picture_width, picture_height,
1578                             frame_number, frame_rate);
1579     vp9enc_context_init(picture_width, picture_height);
1580     vp9enc_create_encode_pipe(yuv_fp);
1581 
1582     for (frame_idx = 0; frame_idx < frame_number; frame_idx++) {
1583         vp9enc_get_frame_type(frame_idx, intra_period, ip_period,
1584                               &current_frame_type);
1585 
1586         vp9enc_encode_picture(yuv_fp, vp9_fp, frame_number,
1587                               current_frame_type, frame_idx + 1);
1588 
1589         printf("\r %d/%d ...", (frame_idx + 1), frame_number);
1590         fflush(stdout);
1591     }
1592 
1593     gettimeofday(&tpend, NULL);
1594     timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
1595     timeuse /= 1000000;
1596 
1597     printf("\ndone!\n");
1598     printf("encode %d frames in %f secondes, FPS is %.1f\n", frame_number, timeuse, frame_number / timeuse);
1599 
1600     vp9enc_release_encode_resource();
1601     vp9enc_destory_encode_pipe();
1602 
1603     fclose(yuv_fp);
1604     fclose(vp9_fp);
1605 
1606     return 0;
1607 }
1608