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 ¤t_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