• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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