1 /*
2 * Copyright (c) 2018 Georg Ottinger. 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 /* This file includes code taken from vp9enc.c (libva-utils) copyright 2017
26 * by Intel Cooperation and licensed under same conditions.
27 * This file includes code ported from vaapiencoder_vp8.cpp (libyami) copyright
28 * by 2014-2016 Intel Corporation. https://github.com/intel/libyami
29 * The original copyright and licence statement as below.
30 */
31
32 /*
33 * Copyright (C) 2014-2016 Intel Corporation. All rights reserved.
34 *
35 * Licensed under the Apache License, Version 2.0 (the "License");
36 * you may not use this file except in compliance with the License.
37 * You may obtain a copy of the License at
38 *
39 * http://www.apache.org/licenses/LICENSE-2.0
40 *
41 * Unless required by applicable law or agreed to in writing, software
42 * distributed under the License is distributed on an "AS IS" BASIS,
43 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
44 * See the License for the specific language governing permissions and
45 * limitations under the License.
46 */
47
48 #include <stdbool.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <getopt.h>
53 #include <unistd.h>
54 #include <inttypes.h>
55
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/mman.h>
60 #include <fcntl.h>
61 #include <assert.h>
62 #include <time.h>
63 #include <stdlib.h>
64 #include <pthread.h>
65
66 #include <va/va.h>
67 #include <va/va_enc_vp8.h>
68 #include "va_display.h"
69
70 #define MAX_XY_RESOLUTION 16364
71
72 #define KEY_FRAME 0
73 #define INTER_FRAME 1
74
75 #define NUM_REF_SURFACES 4
76 #define NUM_INPUT_SURFACES 2
77 #define NUM_SURFACES_TOTAL (NUM_REF_SURFACES+NUM_INPUT_SURFACES)
78 #define SID_INPUT_PICTURE_0 (NUM_REF_SURFACES)
79 #define SID_INPUT_PICTURE_1 (NUM_REF_SURFACES+1)
80 #define NUM_BUFFERS 10
81
82 #define VP8ENC_OK 0
83 #define VP8ENC_FAIL -1
84 #define PARSE_OPTIONS_OK 0
85 #define PARSE_OPTIONS_FAIL -1
86
87 #ifndef N_ELEMENTS
88 #define N_ELEMENTS(array) (sizeof(array)/sizeof(array[0]))
89 #endif
90
91 #ifndef CHECK_VASTATUS
92 #define CHECK_VASTATUS(va_status,func) \
93 if (va_status != VA_STATUS_SUCCESS) { \
94 fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
95 exit(1); \
96 }
97 #endif
98
99 #define CHECK_CONDITION(cond) \
100 if(!(cond)) \
101 { \
102 fprintf(stderr, "Unexpected condition: %s:%d\n", __func__, __LINE__); \
103 exit(1); \
104 }
105
106 static const struct option long_opts[] = {
107 {"help", no_argument, NULL, 0 },
108 {"rcmode", required_argument, NULL, 1 },
109 {"qp", required_argument, NULL, 2 },
110 {"intra_period", required_argument, NULL, 3 },
111 {"fb", required_argument, NULL, 4 },
112 {"lf_level", required_argument, NULL, 5 },
113 {"hrd_win", required_argument, NULL, 6},
114 {"vbr_max", required_argument, NULL, 7},
115 {"fn_num", required_argument, NULL, 8},
116 {"error_resilient", no_argument, NULL, 9},
117 {"debug", no_argument, NULL, 10},
118 {"temp_svc", required_argument, NULL, 11},
119 {"repeat", required_argument, NULL, 12},
120 {NULL, no_argument, NULL, 0 }
121 };
122
123
124 static const int default_rc_modes[4] = {
125 VA_RC_CQP, // 0
126 VA_RC_CBR, // 1
127 VA_RC_VBR, // 2
128 VA_RC_NONE
129 };
130
131 struct vp8enc_settings {
132 int width;
133 int height;
134 int frame_rate;
135 int frame_size;
136 int loop_filter_level;
137 int clamp_qindex_low;
138 int clamp_qindex_high;
139 int intra_period;
140 int quantization_parameter;
141 int frame_bitrate;
142 int max_variable_bitrate;
143 int rc_mode;
144 int num_frames;
145 VAEntrypoint vaapi_entry_point;
146 int codedbuf_size;
147 int hrd_window;
148 int error_resilient;
149 int debug;
150 int temporal_svc_layers;
151 int repeat_times;
152 };
153
154
155 static struct vp8enc_settings settings = {
156 //Default Values - unless otherwise specified with command line options
157 .frame_rate = 30,
158 .loop_filter_level = 19,
159 .clamp_qindex_low = 9,
160 .clamp_qindex_high = 127,
161 .intra_period = 30,
162 .quantization_parameter = 60,
163 .frame_bitrate = -1,
164 .max_variable_bitrate = -1,
165 .num_frames = 0,
166 .rc_mode = VA_RC_CQP,
167 .vaapi_entry_point = VAEntrypointEncSlice, //VAEntrypointEncSliceLP would be LowPower Mode - but not supported with VP8Encoder
168 .hrd_window = 1500,
169 .error_resilient = 0,
170 .debug = 0,
171 .temporal_svc_layers = 1,
172 .repeat_times = 1,
173 };
174
175 struct vp8enc_vaapi_context {
176 VADisplay display;
177 VAProfile profile;
178 VAContextID context_id;
179 VAConfigID config_id;
180 VAEncSequenceParameterBufferVP8 seq_param;
181 VAEncPictureParameterBufferVP8 pic_param;
182 VAQMatrixBufferVP8 q_matrix;
183 VASurfaceID surfaces[NUM_SURFACES_TOTAL];
184 VASurfaceID recon_surface, last_ref_surface, golden_ref_surface, alt_ref_surface;
185 VASurfaceID input_surface;
186 VABufferID codedbuf_buf_id;
187 VABufferID va_buffers[NUM_BUFFERS];
188 int num_va_buffers;
189 int is_golden_refreshed;
190 struct {
191 VAEncMiscParameterBuffer header;
192 VAEncMiscParameterHRD data;
193 } hrd_param;
194 struct {
195 VAEncMiscParameterBuffer header;
196 VAEncMiscParameterFrameRate data;
197 } frame_rate_param;
198 struct {
199 VAEncMiscParameterBuffer header;
200 VAEncMiscParameterRateControl data;
201 } rate_control_param;
202 struct {
203 pthread_t id;
204 int value;
205 FILE *input_fp;
206 int input_surface_num;
207 VASurfaceID input_surface;
208 int processed_frame;
209 } upload_thread;
210 };
211
212 static struct vp8enc_vaapi_context vaapi_context;
213
214
215 /********************************************
216 *
217 * START: IVF Container Releated Stuff
218 *
219 ********************************************/
220 static void
vp8enc_write_word(char * ptr,uint32_t value)221 vp8enc_write_word(char *ptr, uint32_t value)
222 {
223 uint8_t *tmp;
224
225 tmp = (uint8_t *)ptr;
226 *(tmp) = (value >> 0) & 0XFF;
227 *(tmp + 1) = (value >> 8) & 0XFF;
228 }
229
230 static void
vp8enc_write_dword(char * ptr,uint32_t value)231 vp8enc_write_dword(char *ptr, uint32_t value)
232 {
233 uint8_t *tmp;
234
235 tmp = (uint8_t *)ptr;
236 *(tmp) = (value >> 0) & 0XFF;
237 *(tmp + 1) = (value >> 8) & 0XFF;
238 *(tmp + 2) = (value >> 16) & 0XFF;
239 *(tmp + 3) = (value >> 24) & 0XFF;
240 }
241
242 static void
vp8enc_write_qword(char * ptr,uint64_t value)243 vp8enc_write_qword(char *ptr, uint64_t value)
244 {
245 uint8_t *tmp;
246
247 tmp = (uint8_t *)ptr;
248 *(tmp) = (value >> 0) & 0XFF;
249 *(tmp + 1) = (value >> 8) & 0XFF;
250 *(tmp + 2) = (value >> 16) & 0XFF;
251 *(tmp + 3) = (value >> 24) & 0XFF;
252 *(tmp + 4) = (value >> 32) & 0XFF;
253 *(tmp + 5) = (value >> 40) & 0XFF;
254 *(tmp + 6) = (value >> 48) & 0XFF;
255 *(tmp + 7) = (value >> 56) & 0XFF;
256 }
257
258 static void
vp8enc_write_frame_header(FILE * vp8_output,uint32_t data_length,uint64_t timestamp)259 vp8enc_write_frame_header(FILE *vp8_output, uint32_t data_length, uint64_t timestamp)
260 {
261 char header[12];
262
263 vp8enc_write_dword(header, data_length);
264 vp8enc_write_qword(header + 4, timestamp);
265
266 fwrite(header, 1, 12, vp8_output);
267 }
268
269 static void
vp8enc_write_ivf_header(FILE * vp8_file)270 vp8enc_write_ivf_header(FILE *vp8_file)
271 {
272
273
274 #define VP8_FOURCC 0x30385056
275
276 char header[32];
277
278 header[0] = 'D';
279 header[1] = 'K';
280 header[2] = 'I';
281 header[3] = 'F';
282
283 vp8enc_write_word(header + 4, 0);
284 vp8enc_write_word(header + 6, 32);
285 vp8enc_write_dword(header + 8, VP8_FOURCC);
286 vp8enc_write_word(header + 12, settings.width);
287 vp8enc_write_word(header + 14, settings.height);
288 vp8enc_write_dword(header + 16, settings.frame_rate);
289 vp8enc_write_dword(header + 20, 1);
290 vp8enc_write_dword(header + 24, settings.num_frames * settings.repeat_times);
291 vp8enc_write_dword(header + 28, 0);
292
293 fwrite(header, 1, 32, vp8_file);
294 }
295
296 /********************************************
297 *
298 * END: IVF Container Releated Stuff
299 *
300 ********************************************/
301
302
303 /********************************************
304 *
305 * START: Read YUV Input File Releated Stuff
306 *
307 ********************************************/
308 static void
vp8enc_upload_yuv_to_surface(FILE * yuv_fp,VASurfaceID surface_id,int current_frame)309 vp8enc_upload_yuv_to_surface(FILE *yuv_fp, VASurfaceID surface_id, int current_frame)
310 {
311 VAImage surface_image;
312 VAStatus va_status;
313 void *surface_p = NULL;
314 uint8_t *y_src, *u_src, *v_src;
315 uint8_t *y_dst, *u_dst, *v_dst;
316 int y_size = settings.width * settings.height;
317 int u_size = (settings.width >> 1) * (settings.height >> 1);
318 int row, col;
319 char *yuv_mmap_ptr = NULL;
320 unsigned long long frame_start_pos, mmap_start;
321 int mmap_size;
322
323 frame_start_pos = (unsigned long long)current_frame * settings.frame_size;
324
325 mmap_start = frame_start_pos & (~0xfff);
326 mmap_size = (settings.frame_size + (frame_start_pos & 0xfff) + 0xfff) & (~0xfff);
327 yuv_mmap_ptr = mmap(0, mmap_size, PROT_READ, MAP_SHARED,
328 fileno(yuv_fp), mmap_start);
329
330 if (yuv_mmap_ptr == MAP_FAILED) {
331 fprintf(stderr, "Error: Failed to mmap YUV file.\n");
332 assert(0);
333 }
334
335 y_src = (uint8_t*)yuv_mmap_ptr + (frame_start_pos & 0xfff);
336 u_src = y_src + y_size; /* UV offset for NV12 */
337 v_src = y_src + y_size + u_size;
338
339
340 va_status = vaDeriveImage(vaapi_context.display, surface_id, &surface_image);
341 CHECK_VASTATUS(va_status, "vaDeriveImage");
342
343 vaMapBuffer(vaapi_context.display, surface_image.buf, &surface_p);
344 assert(VA_STATUS_SUCCESS == va_status);
345
346 y_dst = (unsigned char *)surface_p + surface_image.offsets[0];
347 u_dst = (unsigned char *)surface_p +
348 surface_image.offsets[1]; /* UV offset for NV12 */
349 v_dst = (unsigned char *)surface_p + surface_image.offsets[2];
350
351 /* Y plane */
352 for (row = 0; row < surface_image.height; row++) {
353 memcpy(y_dst, y_src, surface_image.width);
354 y_dst += surface_image.pitches[0];
355 y_src += settings.width;
356 }
357
358 if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */
359 for (row = 0; row < surface_image.height / 2; row++) {
360 for (col = 0; col < surface_image.width / 2; col++) {
361 u_dst[col * 2] = u_src[col];
362 u_dst[col * 2 + 1] = v_src[col];
363 }
364
365 u_dst += surface_image.pitches[1];
366 u_src += (settings.width / 2);
367 v_src += (settings.width / 2);
368 }
369 } else if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
370 surface_image.format.fourcc == VA_FOURCC_I420) {
371 const int U = surface_image.format.fourcc == VA_FOURCC_I420 ? 1 : 2;
372 const int V = surface_image.format.fourcc == VA_FOURCC_I420 ? 2 : 1;
373
374 u_dst = (unsigned char *)surface_p + surface_image.offsets[U];
375 v_dst = (unsigned char *)surface_p + surface_image.offsets[V];
376
377 for (row = 0; row < surface_image.height / 2; row++) {
378 memcpy(u_dst, u_src, surface_image.width / 2);
379 memcpy(v_dst, v_src, surface_image.width / 2);
380 u_dst += surface_image.pitches[U];
381 v_dst += surface_image.pitches[V];
382 u_src += (settings.width / 2);
383 v_src += (settings.width / 2);
384 }
385 }
386
387 vaUnmapBuffer(vaapi_context.display, surface_image.buf);
388 vaDestroyImage(vaapi_context.display, surface_image.image_id);
389
390 if (yuv_mmap_ptr)
391 munmap(yuv_mmap_ptr, mmap_size);
392 }
393
394 static void *
vp8enc_upload_thread_function(void * data)395 vp8enc_upload_thread_function(void *data)
396 {
397 vp8enc_upload_yuv_to_surface(vaapi_context.upload_thread.input_fp, vaapi_context.upload_thread.input_surface, vaapi_context.upload_thread.processed_frame);
398
399 return NULL;
400 }
401 /********************************************
402 *
403 * END: Read YUV Input File Releated Stuff
404 *
405 ********************************************/
406
vp8enc_init_QMatrix(VAQMatrixBufferVP8 * qMatrix)407 void vp8enc_init_QMatrix(VAQMatrixBufferVP8 *qMatrix)
408 {
409 // When segmentation is disabled, only quantization_index[0] will be used
410 size_t i;
411 for (i = 0; i < N_ELEMENTS(qMatrix->quantization_index); i++) {
412 qMatrix->quantization_index[i] = settings.quantization_parameter;
413 }
414
415 for (i = 0; i < N_ELEMENTS(qMatrix->quantization_index_delta); i++) {
416 qMatrix->quantization_index_delta[i] = 0;
417 }
418 }
419
vp8enc_init_SequenceParameterBuffer(VAEncSequenceParameterBufferVP8 * seqParam)420 void vp8enc_init_SequenceParameterBuffer(VAEncSequenceParameterBufferVP8* seqParam)
421 {
422 size_t i;
423
424 memset(seqParam, 0, sizeof(VAEncSequenceParameterBufferVP8));
425
426 seqParam->frame_width = settings.width;
427 seqParam->frame_height = settings.height;
428
429 if (settings.frame_bitrate > 0)
430 seqParam->bits_per_second = settings.frame_bitrate * 1000;
431 else
432 seqParam->bits_per_second = 0;
433
434 seqParam->intra_period = settings.intra_period;
435 seqParam->error_resilient = settings.error_resilient;
436
437 for (i = 0; i < N_ELEMENTS(seqParam->reference_frames); i++)
438 seqParam->reference_frames[i] = VA_INVALID_ID;
439 }
440
vp8enc_init_PictureParameterBuffer(VAEncPictureParameterBufferVP8 * picParam)441 void vp8enc_init_PictureParameterBuffer(VAEncPictureParameterBufferVP8 *picParam)
442 {
443 size_t i;
444 memset(picParam, 0, sizeof(VAEncPictureParameterBufferVP8));
445
446 picParam->ref_last_frame = VA_INVALID_SURFACE;
447 picParam->ref_gf_frame = VA_INVALID_SURFACE;
448 picParam->ref_arf_frame = VA_INVALID_SURFACE;
449
450 /* always show it */
451 picParam->pic_flags.bits.show_frame = 1;
452
453 for (i = 0; i < N_ELEMENTS(picParam->loop_filter_level); i++) {
454 picParam->loop_filter_level[i] = settings.loop_filter_level;
455 }
456
457 picParam->clamp_qindex_low = settings.clamp_qindex_low;
458 picParam->clamp_qindex_high = settings.clamp_qindex_high;
459
460 }
461
vp8enc_set_refreshparameter_for_svct_2layers(VAEncPictureParameterBufferVP8 * picParam,int current_frame,int * is_golden_refreshed)462 void vp8enc_set_refreshparameter_for_svct_2layers(VAEncPictureParameterBufferVP8 *picParam, int current_frame, int *is_golden_refreshed)
463 {
464 //Pattern taken from libyami
465
466 picParam->ref_flags.bits.no_ref_arf = 1;
467
468 if (! *is_golden_refreshed)
469 picParam->ref_flags.bits.no_ref_gf = 1;
470
471 switch (current_frame % 2) {
472 case 0:
473 //Layer 0
474 picParam->pic_flags.bits.refresh_last = 1;
475 picParam->ref_flags.bits.no_ref_gf = 1;
476 picParam->ref_flags.bits.temporal_id = 0;
477 break;
478 case 1:
479 //Layer 1
480 picParam->pic_flags.bits.refresh_golden_frame = 1;
481 *is_golden_refreshed = 1;
482 picParam->ref_flags.bits.temporal_id = 1;
483 break;
484 }
485 }
486
vp8enc_set_refreshparameter_for_svct_3layers(VAEncPictureParameterBufferVP8 * picParam,int current_frame,int * is_golden_refreshed)487 void vp8enc_set_refreshparameter_for_svct_3layers(VAEncPictureParameterBufferVP8 *picParam, int current_frame, int *is_golden_refreshed)
488 {
489 //Pattern taken from libyami - Note that the alternate frame is never referenced,
490 //this is because, libyami implementation suggests to be able to drop individual
491 //frames from Layer 2 on bad network connections
492 picParam->ref_flags.bits.no_ref_arf = 1;
493
494 if (! *is_golden_refreshed)
495 picParam->ref_flags.bits.no_ref_gf = 1;
496
497 switch (current_frame % 4) {
498 case 0:
499 //Layer 0
500 picParam->pic_flags.bits.refresh_last = 1;
501 picParam->ref_flags.bits.no_ref_gf = 1;
502 picParam->ref_flags.bits.temporal_id = 0;
503 break;
504 case 1:
505 case 3:
506 //Layer 2
507 picParam->pic_flags.bits.refresh_alternate_frame = 1;
508 picParam->ref_flags.bits.temporal_id = 2;
509 break;
510 case 2:
511 //Layer 1
512 picParam->pic_flags.bits.refresh_golden_frame = 1;
513 *is_golden_refreshed = 1;
514 picParam->ref_flags.bits.temporal_id = 1;
515 break;
516 }
517 }
518
vp8enc_reset_picture_parameter_references(VAEncPictureParameterBufferVP8 * picParam)519 void vp8enc_reset_picture_parameter_references(VAEncPictureParameterBufferVP8 *picParam)
520 {
521 picParam->ref_last_frame = VA_INVALID_SURFACE;
522 picParam->ref_gf_frame = VA_INVALID_SURFACE;
523 picParam->ref_arf_frame = VA_INVALID_SURFACE;
524 picParam->pic_flags.bits.refresh_last = 0;
525 picParam->pic_flags.bits.refresh_golden_frame = 0;
526 picParam->pic_flags.bits.refresh_alternate_frame = 0;
527 picParam->pic_flags.bits.copy_buffer_to_golden = 0;
528 picParam->pic_flags.bits.copy_buffer_to_alternate = 0;
529 picParam->ref_flags.bits.no_ref_last = 0;
530 picParam->ref_flags.bits.no_ref_gf = 0;
531 picParam->ref_flags.bits.no_ref_arf = 0;
532 }
533
vp8enc_update_picture_parameter(int frame_type,int current_frame)534 void vp8enc_update_picture_parameter(int frame_type, int current_frame)
535 {
536 VAEncPictureParameterBufferVP8 *picParam = &vaapi_context.pic_param;
537
538 picParam->reconstructed_frame = vaapi_context.recon_surface;
539
540 vp8enc_reset_picture_parameter_references(picParam);
541
542 if (frame_type == KEY_FRAME) {
543 picParam->ref_flags.bits.force_kf = 1;
544 picParam->pic_flags.bits.frame_type = KEY_FRAME;
545 vaapi_context.is_golden_refreshed = 0;
546 return;
547 }
548
549 // INTER_FRAME
550 picParam->ref_flags.bits.force_kf = 0;
551 picParam->pic_flags.bits.frame_type = INTER_FRAME;
552
553 switch (settings.temporal_svc_layers) {
554 case 1:
555 //Standard behavoir only 1 Temporal Layer
556 picParam->pic_flags.bits.refresh_last = 1;
557 picParam->pic_flags.bits.copy_buffer_to_golden = 1;
558 picParam->pic_flags.bits.copy_buffer_to_alternate = 2;
559 picParam->ref_flags.bits.temporal_id = 0;
560 break;
561 case 2:
562 //2 Temporal Layers
563 vp8enc_set_refreshparameter_for_svct_2layers(picParam, current_frame, &vaapi_context.is_golden_refreshed);
564 break;
565 case 3:
566 //3 Temporal Layers
567 vp8enc_set_refreshparameter_for_svct_3layers(picParam, current_frame, &vaapi_context.is_golden_refreshed);
568 break;
569 default:
570 //should never happen
571 fprintf(stderr, "Error: Only 1,2 or 3 TemporalLayers supported.\n");
572 assert(0);
573 break;
574 }
575
576 if (!picParam->ref_flags.bits.no_ref_last)
577 picParam->ref_last_frame = vaapi_context.last_ref_surface;
578 if (!picParam->ref_flags.bits.no_ref_gf)
579 picParam->ref_gf_frame = vaapi_context.golden_ref_surface;
580 if (!picParam->ref_flags.bits.no_ref_arf)
581 picParam->ref_arf_frame = vaapi_context.alt_ref_surface;
582
583 }
584
vp8enc_get_unused_surface()585 VASurfaceID vp8enc_get_unused_surface()
586 {
587 VASurfaceID current_surface;
588 size_t i = 0;
589
590 for (i = 0; i < NUM_REF_SURFACES; i++) {
591 current_surface = vaapi_context.surfaces[i];
592
593 if (current_surface != vaapi_context.last_ref_surface && current_surface != vaapi_context.golden_ref_surface && current_surface != vaapi_context.alt_ref_surface)
594 return current_surface;
595 }
596
597 //No unused surface found - should never happen.
598 fprintf(stderr, "Error: No unused surface found!\n");
599 assert(0);
600
601 return VA_INVALID_ID; // should never happen
602 }
603
vp8enc_update_reference(VASurfaceID current_surface,VASurfaceID second_copy_surface,bool refresh_with_recon,int copy_flag)604 VASurfaceID vp8enc_update_reference(VASurfaceID current_surface, VASurfaceID second_copy_surface, bool refresh_with_recon, int copy_flag)
605 {
606 if (refresh_with_recon)
607 return vaapi_context.recon_surface;
608 switch (copy_flag) {
609 case 0:
610 return current_surface;
611 case 1:
612 return vaapi_context.last_ref_surface;
613 case 2:
614 return second_copy_surface;
615 default: // should never happen
616 fprintf(stderr, "Error: Invalid copy_buffer_to_X flag\n");
617 assert(0);
618 }
619
620 return VA_INVALID_ID; // should never happen
621 }
622
623
vp8enc_update_reference_list(int frame_type)624 void vp8enc_update_reference_list(int frame_type)
625 {
626
627 VAEncPictureParameterBufferVP8 *picParam = &vaapi_context.pic_param;
628
629 if (frame_type == KEY_FRAME) {
630 vaapi_context.last_ref_surface = vaapi_context.recon_surface;
631 vaapi_context.golden_ref_surface = vaapi_context.recon_surface;
632 vaapi_context.alt_ref_surface = vaapi_context.recon_surface;
633 } else { // INTER_FRAME
634 //check refresh_X and copy_buffer_to_golden_X and update references accordingly
635 if (picParam->pic_flags.bits.refresh_last)
636 vaapi_context.last_ref_surface = vaapi_context.recon_surface;
637 vaapi_context.golden_ref_surface = vp8enc_update_reference(vaapi_context.golden_ref_surface, vaapi_context.alt_ref_surface, picParam->pic_flags.bits.refresh_golden_frame, picParam->pic_flags.bits.copy_buffer_to_golden);
638 vaapi_context.alt_ref_surface = vp8enc_update_reference(vaapi_context.alt_ref_surface, vaapi_context.golden_ref_surface, picParam->pic_flags.bits.refresh_alternate_frame, picParam->pic_flags.bits.copy_buffer_to_alternate);
639 }
640
641 vaapi_context.recon_surface = vp8enc_get_unused_surface();
642 }
643
vp8enc_init_MiscParameterBuffers(VAEncMiscParameterHRD * hrd,VAEncMiscParameterFrameRate * frame_rate,VAEncMiscParameterRateControl * rate_control)644 void vp8enc_init_MiscParameterBuffers(VAEncMiscParameterHRD *hrd, VAEncMiscParameterFrameRate *frame_rate, VAEncMiscParameterRateControl *rate_control)
645 {
646 if (hrd != NULL) {
647 if (settings.frame_bitrate) {
648 hrd->initial_buffer_fullness = settings.frame_bitrate * settings.hrd_window / 2;
649 hrd->buffer_size = settings.frame_bitrate * settings.hrd_window;
650 } else {
651 hrd->initial_buffer_fullness = 0;
652 hrd->buffer_size = 0;
653 }
654 }
655
656 if (frame_rate != NULL) {
657 frame_rate->framerate = settings.frame_rate;
658 }
659
660 if (rate_control != NULL) {
661 rate_control->window_size = settings.hrd_window;
662 rate_control->initial_qp = settings.quantization_parameter;
663 rate_control->min_qp = settings.clamp_qindex_low;
664 //rate_control->rc_flags.bits.disable_bit_stuffing = 1;
665
666 if (settings.rc_mode == VA_RC_VBR) {
667 rate_control->bits_per_second = settings.max_variable_bitrate * 1000;
668 rate_control->target_percentage = (settings.frame_bitrate * 100) / settings.max_variable_bitrate;
669 } else {
670 rate_control->bits_per_second = settings.frame_bitrate * 1000;
671 rate_control->target_percentage = 95;
672
673 }
674 }
675 }
676
vp8enc_create_EncoderPipe()677 void vp8enc_create_EncoderPipe()
678 {
679 VAEntrypoint entrypoints[5];
680 int num_entrypoints;
681 VAConfigAttrib conf_attrib[2];
682 VASurfaceAttrib surface_attrib;
683 int major_ver, minor_ver;
684 VAStatus va_status;
685
686 vaapi_context.display = va_open_display();
687 va_status = vaInitialize(vaapi_context.display, &major_ver, &minor_ver);
688 CHECK_VASTATUS(va_status, "vaInitialize");
689
690 vaQueryConfigEntrypoints(vaapi_context.display, vaapi_context.profile, entrypoints,
691 &num_entrypoints);
692
693 /* find out the format for the render target, and rate control mode */
694 conf_attrib[0].type = VAConfigAttribRTFormat;
695 conf_attrib[1].type = VAConfigAttribRateControl;
696 vaGetConfigAttributes(vaapi_context.display, vaapi_context.profile, settings.vaapi_entry_point,
697 &conf_attrib[0], 2);
698
699 if ((conf_attrib[0].value & VA_RT_FORMAT_YUV420) == 0) {
700 fprintf(stderr, "Error: Input colorspace YUV420 not supported, exit\n");
701 assert(0);
702 }
703
704 if ((conf_attrib[1].value & settings.rc_mode) == 0) {
705 /* Can't find matched RC mode */
706 fprintf(stderr, "Error: Can't find the desired RC mode, exit\n");
707 assert(0);
708 }
709
710 conf_attrib[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
711 conf_attrib[1].value = settings.rc_mode; /* set to desired RC mode */
712
713 va_status = vaCreateConfig(vaapi_context.display, vaapi_context.profile, settings.vaapi_entry_point,
714 &conf_attrib[0], 2, &vaapi_context.config_id);
715 CHECK_VASTATUS(va_status, "vaCreateConfig");
716
717 surface_attrib.type = VASurfaceAttribPixelFormat;
718 surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
719 surface_attrib.value.type = VAGenericValueTypeInteger;
720 surface_attrib.value.value.i = VA_FOURCC_NV12;
721
722 // Create surface (Reference Surfaces + Input Surfaces)
723 va_status = vaCreateSurfaces(
724 vaapi_context.display,
725 VA_RT_FORMAT_YUV420, settings.width, settings.height,
726 vaapi_context.surfaces, NUM_SURFACES_TOTAL,
727 &surface_attrib, 1
728 );
729
730 CHECK_VASTATUS(va_status, "vaCreateSurfaces");
731
732 vaapi_context.recon_surface = vaapi_context.surfaces[0];
733 vaapi_context.last_ref_surface = VA_INVALID_SURFACE;
734 vaapi_context.golden_ref_surface = VA_INVALID_SURFACE;
735 vaapi_context.alt_ref_surface = VA_INVALID_SURFACE;
736 vaapi_context.input_surface = vaapi_context.surfaces[NUM_REF_SURFACES]; // input surfaces trail the reference surfaces
737
738 /* Create a context for this Encoder pipe */
739 /* the surface is added to the render_target list when creating the context */
740 va_status = vaCreateContext(vaapi_context.display, vaapi_context.config_id,
741 settings.width, settings.height,
742 VA_PROGRESSIVE,
743 vaapi_context.surfaces, NUM_SURFACES_TOTAL,
744 &vaapi_context.context_id);
745
746 CHECK_VASTATUS(va_status, "vaCreateContext");
747
748
749 }
750
vp8enc_destory_EncoderPipe()751 void vp8enc_destory_EncoderPipe()
752 {
753 pthread_join(vaapi_context.upload_thread.id, NULL);
754 vaDestroySurfaces(vaapi_context.display, vaapi_context.surfaces, NUM_SURFACES_TOTAL);
755 vaDestroyContext(vaapi_context.display, vaapi_context.context_id);
756 vaDestroyConfig(vaapi_context.display, vaapi_context.config_id);
757 vaTerminate(vaapi_context.display);
758 va_close_display(vaapi_context.display);
759 }
760
761
vp8enc_init_VaapiContext()762 void vp8enc_init_VaapiContext()
763 {
764 size_t i;
765 vaapi_context.profile = VAProfileVP8Version0_3;
766
767 vp8enc_init_SequenceParameterBuffer(&vaapi_context.seq_param);
768 vp8enc_init_PictureParameterBuffer(&vaapi_context.pic_param);
769 vp8enc_init_QMatrix(&vaapi_context.q_matrix);
770
771 vaapi_context.hrd_param.header.type = VAEncMiscParameterTypeHRD;
772 vaapi_context.frame_rate_param.header.type = VAEncMiscParameterTypeFrameRate;
773 vaapi_context.rate_control_param.header.type = VAEncMiscParameterTypeRateControl;
774 vp8enc_init_MiscParameterBuffers(&vaapi_context.hrd_param.data, &vaapi_context.frame_rate_param.data, &vaapi_context.rate_control_param.data);
775
776 for (i = 0; i < N_ELEMENTS(vaapi_context.va_buffers); i++)
777 vaapi_context.va_buffers[i] = VA_INVALID_ID;
778 vaapi_context.num_va_buffers = 0;
779
780 vaapi_context.is_golden_refreshed = 0;
781 }
782
783
784
785 static int
vp8enc_store_coded_buffer(FILE * vp8_fp,uint64_t timestamp)786 vp8enc_store_coded_buffer(FILE *vp8_fp, uint64_t timestamp)
787 {
788 VACodedBufferSegment *coded_buffer_segment;
789 uint8_t *coded_mem;
790 int data_length;
791 VAStatus va_status;
792 VASurfaceStatus surface_status;
793 size_t w_items;
794
795 va_status = vaSyncSurface(vaapi_context.display, vaapi_context.recon_surface);
796 CHECK_VASTATUS(va_status, "vaSyncSurface");
797
798 surface_status = 0;
799 va_status = vaQuerySurfaceStatus(vaapi_context.display, vaapi_context.recon_surface, &surface_status);
800 CHECK_VASTATUS(va_status, "vaQuerySurfaceStatus");
801
802 va_status = vaMapBuffer(vaapi_context.display, vaapi_context.codedbuf_buf_id, (void **)(&coded_buffer_segment));
803 CHECK_VASTATUS(va_status, "vaMapBuffer");
804 coded_mem = coded_buffer_segment->buf;
805
806 if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
807 fprintf(stderr, "Error: CodeBuffer Size too small\n");
808 vaUnmapBuffer(vaapi_context.display, vaapi_context.codedbuf_buf_id);
809 assert(0);
810 }
811
812 data_length = coded_buffer_segment->size;
813
814 vp8enc_write_frame_header(vp8_fp, data_length, timestamp);
815
816 do {
817 w_items = fwrite(coded_mem, data_length, 1, vp8_fp);
818 } while (w_items != 1);
819
820 if (settings.debug)
821 fprintf(stderr, "Timestamp: %ld Bytes written %d\n", timestamp, data_length);
822
823 vaUnmapBuffer(vaapi_context.display, vaapi_context.codedbuf_buf_id);
824
825 return 0;
826 }
827
vp8enc_get_FileSize(FILE * fp)828 size_t vp8enc_get_FileSize(FILE *fp)
829 {
830 struct stat st;
831 int ret = fstat(fileno(fp), &st);
832 CHECK_CONDITION(ret == 0);
833 return st.st_size;
834 }
835
vp8enc_prepare_buffers(int frame_type)836 int vp8enc_prepare_buffers(int frame_type)
837 {
838 int num_buffers = 0;
839 VABufferID *va_buffers;
840 VAStatus va_status;
841 VAEncPictureParameterBufferVP8 *picParam = &vaapi_context.pic_param;
842
843
844 va_buffers = vaapi_context.va_buffers;
845 /* coded buffer */
846 va_status = vaCreateBuffer(vaapi_context.display,
847 vaapi_context.context_id,
848 VAEncCodedBufferType,
849 settings.codedbuf_size, 1, NULL,
850 &vaapi_context.codedbuf_buf_id);
851 CHECK_VASTATUS(va_status, "vaCreateBuffer");
852
853 /* sequence parameter set */
854 va_status = vaCreateBuffer(vaapi_context.display,
855 vaapi_context.context_id,
856 VAEncSequenceParameterBufferType,
857 sizeof(vaapi_context.seq_param), 1, &vaapi_context.seq_param,
858 va_buffers);
859 CHECK_VASTATUS(va_status, "vaCreateBuffer");
860
861 va_buffers ++;
862 num_buffers++;
863
864 /* picture parameter set */
865 picParam->coded_buf = vaapi_context.codedbuf_buf_id;
866
867 va_status = vaCreateBuffer(vaapi_context.display,
868 vaapi_context.context_id,
869 VAEncPictureParameterBufferType,
870 sizeof(vaapi_context.pic_param), 1, &vaapi_context.pic_param,
871 va_buffers);
872 CHECK_VASTATUS(va_status, "vaCreateBuffer");
873 va_buffers ++;
874 num_buffers++;
875
876
877
878 /* hrd parameter */
879 va_status = vaCreateBuffer(vaapi_context.display,
880 vaapi_context.context_id,
881 VAEncMiscParameterBufferType,
882 sizeof(vaapi_context.hrd_param), 1, &vaapi_context.hrd_param,
883 va_buffers);
884 CHECK_VASTATUS(va_status, "vaCreateBuffer");
885
886 va_buffers ++;
887 num_buffers++;
888
889 /* QMatrix */
890 va_status = vaCreateBuffer(vaapi_context.display,
891 vaapi_context.context_id,
892 VAQMatrixBufferType,
893 sizeof(vaapi_context.q_matrix), 1, &vaapi_context.q_matrix,
894 va_buffers);
895 CHECK_VASTATUS(va_status, "vaCreateBuffer");
896
897
898 va_buffers ++;
899 num_buffers++;
900 /* Create the Misc FR/RC buffer under non-CQP mode */
901 if (settings.rc_mode != VA_RC_CQP && frame_type == KEY_FRAME) {
902 va_status = vaCreateBuffer(vaapi_context.display,
903 vaapi_context.context_id,
904 VAEncMiscParameterBufferType,
905 sizeof(vaapi_context.frame_rate_param), 1, &vaapi_context.frame_rate_param,
906 va_buffers);
907 CHECK_VASTATUS(va_status, "vaCreateBuffer");
908
909 va_buffers ++;
910 num_buffers++;
911
912 va_status = vaCreateBuffer(vaapi_context.display,
913 vaapi_context.context_id,
914 VAEncMiscParameterBufferType,
915 sizeof(vaapi_context.rate_control_param), 1, &vaapi_context.rate_control_param,
916 va_buffers);
917 CHECK_VASTATUS(va_status, "vaCreateBuffer");
918
919 va_buffers ++;
920 num_buffers++;
921 }
922
923 vaapi_context.num_va_buffers = num_buffers;
924
925 return num_buffers;
926 }
927
928
929
930
931 static void
vp8enc_render_picture()932 vp8enc_render_picture()
933 {
934 VAStatus va_status;
935
936 va_status = vaBeginPicture(vaapi_context.display,
937 vaapi_context.context_id,
938 vaapi_context.input_surface);
939 CHECK_VASTATUS(va_status, "vaBeginPicture");
940
941
942 va_status = vaRenderPicture(vaapi_context.display,
943 vaapi_context.context_id,
944 vaapi_context.va_buffers,
945 vaapi_context.num_va_buffers);
946 CHECK_VASTATUS(va_status, "vaRenderPicture");
947
948 va_status = vaEndPicture(vaapi_context.display, vaapi_context.context_id);
949 CHECK_VASTATUS(va_status, "vaEndPicture");
950
951 }
952
vp8enc_destroy_buffers()953 void vp8enc_destroy_buffers()
954 {
955 int i;
956 VAStatus va_status;
957
958 for (i = 0; i < vaapi_context.num_va_buffers; i++) {
959 if (vaapi_context.va_buffers[i] != VA_INVALID_ID) {
960 va_status = vaDestroyBuffer(vaapi_context.display, vaapi_context.va_buffers[i]);
961 CHECK_VASTATUS(va_status, "vaDestroyBuffer");
962 vaapi_context.va_buffers[i] = VA_INVALID_ID;
963 }
964 }
965
966 if (vaapi_context.codedbuf_buf_id != VA_INVALID_ID) {
967 va_status = vaDestroyBuffer(vaapi_context.display, vaapi_context.codedbuf_buf_id);
968 CHECK_VASTATUS(va_status, "vaDestroyBuffer");
969 vaapi_context.codedbuf_buf_id = VA_INVALID_ID;
970 }
971
972 }
vp8enc_show_help()973 void vp8enc_show_help()
974 {
975 printf("Usage: vp8enc <width> <height> <input_yuvfile> <output_vp8> additional_option\n");
976 printf("output_vp8 should use *.ivf\n");
977 printf("The additional option is listed\n");
978 printf("-f <frame rate> \n");
979 printf("--intra_period <key_frame interval>\n");
980 printf("--qp <quantization parameter> \n");
981 printf("--rcmode <rate control mode> 0: CQP, 1: CBR, 2: VBR\n");
982 printf("--fb <bitrate> (kbps unit)\n");
983 printf("--lf_level <loop filter level> [0-63]\n");
984 printf("--hrd_win <num> [1000-8000]\n");
985 printf("--vbr_max <num> (kbps unit. It should be greater than fb)\n");
986 printf("--fn_num <num>\n how many frames to be encoded\n");
987 printf("--error_resilient Turn on Error resilient mode\n");
988 printf("--debug Turn debug info on\n");
989 printf("--temp_svc <num> Number of temporal layers 2 or 3\n");
990 printf("--repeat <num> Number of times to repeat the encoding\n");
991 }
992
parameter_check(const char * param,int val,int min,int max)993 void parameter_check(const char *param, int val, int min, int max)
994 {
995 if (val < min || val > max) {
996 fprintf(stderr, "Error: %s out of range (%d..%d) \n", param, min, max);
997 exit(VP8ENC_FAIL);
998 }
999 }
1000
parameter_check_positive(const char * param,int val,int min)1001 void parameter_check_positive(const char *param, int val, int min)
1002 {
1003 if (val < 1) {
1004 fprintf(stderr, "Error: %s demands a positive value greater than %d \n", param, min);
1005 exit(VP8ENC_FAIL);
1006 }
1007 }
1008
parse_options(int ac,char * av[])1009 int parse_options(int ac, char *av[])
1010 {
1011 int c, long_index, tmp_input;
1012 while (1) {
1013 c = getopt_long_only(ac, av, "hf:?", long_opts, &long_index);
1014
1015 if (c == -1)
1016 break;
1017
1018 switch (c) {
1019 case 'f':
1020 tmp_input = atoi(optarg);
1021 parameter_check_positive("-f", tmp_input, 1);
1022 settings.frame_rate = tmp_input;
1023 break;
1024 case 1:
1025 tmp_input = atoi(optarg);
1026 parameter_check("--rcmode", tmp_input, 0, 2);
1027 settings.rc_mode = default_rc_modes[tmp_input];
1028 break;
1029 case 2:
1030 tmp_input = atoi(optarg);
1031 parameter_check("--qp", tmp_input, 0, 255);
1032 settings.quantization_parameter = tmp_input;
1033 break;
1034 case 3:
1035 tmp_input = atoi(optarg);
1036 parameter_check_positive("--intra_period", tmp_input, 1);
1037 settings.intra_period = tmp_input;
1038 break;
1039 case 4:
1040 tmp_input = atoi(optarg);
1041 parameter_check_positive("--fb", tmp_input, 1);
1042 settings.frame_bitrate = tmp_input;
1043 break;
1044 case 5:
1045 tmp_input = atoi(optarg);
1046 parameter_check("--lf_level", tmp_input, 0, 63);
1047 settings.loop_filter_level = tmp_input;
1048 break;
1049 case 6:
1050 tmp_input = atoi(optarg);
1051 parameter_check("--hrd_win", tmp_input, 1000, 8000);
1052 settings.hrd_window = tmp_input;
1053 break;
1054 case 7:
1055 tmp_input = atoi(optarg);
1056 parameter_check_positive("--vbr_max", tmp_input, 1);
1057 settings.max_variable_bitrate = tmp_input;
1058 break;
1059 case 8:
1060 tmp_input = atoi(optarg);
1061 parameter_check_positive("--fn_num", tmp_input, 1);
1062 settings.num_frames = tmp_input;
1063 break;
1064 case 9:
1065 settings.error_resilient = 1;
1066 break;
1067 case 10:
1068 settings.debug = 1;
1069 break;
1070 case 11:
1071 tmp_input = atoi(optarg);
1072 parameter_check("--temp_svc", tmp_input, 2, 3);
1073 settings.temporal_svc_layers = tmp_input;
1074 break;
1075 case 12:
1076 tmp_input = atoi(optarg);
1077 parameter_check("--repeat", tmp_input, 1, 1000000);
1078 settings.repeat_times = tmp_input;
1079 break;
1080 case 'h':
1081 case 0:
1082 default:
1083 return PARSE_OPTIONS_FAIL;
1084 break;
1085 }
1086 }
1087 return PARSE_OPTIONS_OK;
1088 }
1089
main(int argc,char * argv[])1090 int main(int argc, char *argv[])
1091 {
1092 int current_frame, frame_type;
1093 FILE *fp_vp8_output = NULL;
1094 FILE *fp_yuv_input = NULL;
1095 uint64_t timestamp;
1096 struct timeval t1, t2;
1097 double fps, elapsed_time;
1098
1099
1100 if (argc < 5) {
1101 vp8enc_show_help();
1102 return VP8ENC_FAIL;
1103 }
1104
1105 if (parse_options(argc - 4, &argv[4]) != PARSE_OPTIONS_OK) {
1106 vp8enc_show_help();
1107 return VP8ENC_FAIL;
1108 }
1109
1110 settings.width = atoi(argv[1]);
1111 parameter_check("Width", settings.width, 16, MAX_XY_RESOLUTION);
1112
1113 settings.height = atoi(argv[2]);
1114 parameter_check("Height", settings.height, 16, MAX_XY_RESOLUTION);
1115
1116 if (settings.rc_mode == VA_RC_VBR && settings.max_variable_bitrate < settings.frame_bitrate) {
1117 fprintf(stderr, "Error: max. variable bitrate should be greater than frame bitrate (--vbr_max >= --fb)\n");
1118 return VP8ENC_FAIL;
1119 }
1120
1121 if (argv[3]) {
1122 fp_yuv_input = fopen(argv[3], "rb");
1123 }
1124 if (fp_yuv_input == NULL) {
1125 fprintf(stderr, "Error: Couldn't open input file.\n");
1126 return VP8ENC_FAIL;
1127 }
1128 vaapi_context.upload_thread.input_fp = fp_yuv_input;
1129
1130 fp_vp8_output = fopen(argv[4], "wb");
1131 if (fp_vp8_output == NULL) {
1132 fprintf(stderr, "Error: Couldn't open output file.\n");
1133 return VP8ENC_FAIL;
1134 }
1135
1136 if (settings.temporal_svc_layers == 2 && settings.intra_period % 2)
1137 fprintf(stderr, "Warning: Choose Key-Frame interval (--intra_period) to be integer mutliply of 2 to match temporal layer pattern");
1138
1139 if (settings.temporal_svc_layers == 3 && settings.intra_period % 4)
1140 fprintf(stderr, "Warning: Choose Key-Frame interval (--intra_period) to be integer mutliply of 4 to match temporal layer pattern");
1141
1142
1143 settings.frame_size = settings.width * settings.height * 3 / 2; //NV12 Colorspace - For a 2x2 group of pixels, you have 4 Y samples and 1 U and 1 V sample.
1144 if (!settings.num_frames)
1145 settings.num_frames = vp8enc_get_FileSize(fp_yuv_input) / (size_t)settings.frame_size;
1146 settings.codedbuf_size = settings.width * settings.height; //just a generous assumptions
1147
1148 fprintf(stderr, "Info: Encoding total of %d frames.\n", settings.num_frames);
1149
1150 gettimeofday(&t1, 0); //Measure Runtime
1151
1152 vp8enc_init_VaapiContext();
1153 vp8enc_create_EncoderPipe();
1154
1155 vp8enc_write_ivf_header(fp_vp8_output);
1156
1157 current_frame = 0;
1158 timestamp = 0;
1159 vaapi_context.input_surface = vaapi_context.surfaces[SID_INPUT_PICTURE_0];
1160 vaapi_context.upload_thread.input_surface_num = SID_INPUT_PICTURE_0;
1161
1162 while (current_frame < settings.num_frames * settings.repeat_times) {
1163 fprintf(stderr, "\rProcessing frame: %d", current_frame);
1164
1165 if ((current_frame % settings.intra_period) == 0)
1166 frame_type = KEY_FRAME;
1167 else
1168 frame_type = INTER_FRAME;
1169
1170 if (current_frame == 0) {
1171 // Preload first input_surface
1172 vp8enc_upload_yuv_to_surface(fp_yuv_input, vaapi_context.input_surface, current_frame); //prefill
1173 } else {
1174 // wait for input processing thread to finish
1175 pthread_join(vaapi_context.upload_thread.id, NULL);
1176 vaapi_context.input_surface = vaapi_context.upload_thread.input_surface;
1177 }
1178
1179 // Start Upload thread
1180 if ((current_frame + 1) < settings.num_frames * settings.repeat_times) {
1181 vaapi_context.upload_thread.processed_frame = (current_frame % settings.num_frames - 1) + 1;
1182
1183 if (vaapi_context.upload_thread.input_surface_num == SID_INPUT_PICTURE_0)
1184 vaapi_context.upload_thread.input_surface_num = SID_INPUT_PICTURE_1;
1185 else
1186 vaapi_context.upload_thread.input_surface_num = SID_INPUT_PICTURE_0;
1187
1188 vaapi_context.upload_thread.input_surface = vaapi_context.surfaces[vaapi_context.upload_thread.input_surface_num];
1189 vaapi_context.upload_thread.value = pthread_create(&vaapi_context.upload_thread.id, NULL, vp8enc_upload_thread_function, NULL);
1190 }
1191
1192
1193 vp8enc_update_picture_parameter(frame_type, current_frame);
1194 vp8enc_prepare_buffers(frame_type);
1195
1196 vp8enc_render_picture();
1197
1198 vp8enc_store_coded_buffer(fp_vp8_output, timestamp);
1199 vp8enc_destroy_buffers();
1200
1201 vp8enc_update_reference_list(frame_type);
1202
1203 current_frame ++;
1204 timestamp ++;
1205 }
1206
1207 vp8enc_destory_EncoderPipe();
1208 fclose(fp_vp8_output);
1209 fclose(fp_yuv_input);
1210
1211 gettimeofday(&t2, 0);
1212 elapsed_time = (double)(t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec) / 1000000.0;
1213 fps = (double)current_frame / elapsed_time;
1214
1215 fprintf(stderr, "\nProcessed %d frames in %.0f ms (%.2f FPS)\n", current_frame, elapsed_time * 1000.0, fps);
1216
1217 return VP8ENC_OK;
1218 }
1219