Remove autotools build
[platform/upstream/gstreamer.git] / tests / internal / test-fei-enc-in.c
1 /*
2  * test-fei-enc-in.c - Test FEI input buffer submission
3  *
4  * Copyright (C) 2016 Intel Corporation
5  *
6  * Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301 USA
22  */
23 /* sample pipeline: ./test-fei-enc-input -c h264 -o out.264 -e 4 -q 1 sample_i420.y4m */
24
25 #include <assert.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include "gst/vaapi/sysdeps.h"
32 #include <gst/vaapi/gstvaapiencoder.h>
33 #include <gst/vaapi/gstvaapiencoder_h264_fei.h>
34 #include <gst/vaapi/gstvaapisurfacepool.h>
35 #include <gst/vaapi/gstvaapisurfaceproxy.h>
36 #include <gst/vaapi/gstvaapifei_objects.h>
37 #include "output.h"
38 #include "y4mreader.h"
39 #include <va/va.h>
40
41 static guint g_bitrate = 0;
42 static gchar *g_codec_str;
43 static gchar *g_output_file_name;
44 static char **g_input_files = NULL;
45 static gchar *input_mv_name = NULL;
46 static gchar *input_mbmode_name = NULL;
47 static guint input_mv_size;
48 static guint input_mbmode_size;
49 static guint input_qp;
50 static guint enable_mbcntrl;
51 static guint enable_mvpred;
52 static guint fei_mode;
53
54 #define SURFACE_NUM 16
55
56 #define ENC          1
57 #define PAK          2
58 #define ENC_PLUS_PAK 3
59 #define ENC_PAK      4
60
61 static GOptionEntry g_options[] = {
62   {"codec", 'c', 0, G_OPTION_ARG_STRING, &g_codec_str,
63       "codec to use for video encoding (h264)", NULL},
64   {"bitrate", 'b', 0, G_OPTION_ARG_INT, &g_bitrate,
65       "desired bitrate expressed in kbps", NULL},
66   {"output", 'o', 0, G_OPTION_ARG_FILENAME, &g_output_file_name,
67       "output file name", NULL},
68   {"imv", 'v', 0, G_OPTION_ARG_STRING, &input_mv_name,
69       "pak mv input file", NULL},
70   {"imbmode ", 'm', 0, G_OPTION_ARG_STRING, &input_mbmode_name,
71       "pak mbmode input file", NULL},
72   {"imvsize", 's', 0, G_OPTION_ARG_INT, &input_mv_size,
73       "input stream width", NULL},
74   {"imbmodesize", 'd', 0, G_OPTION_ARG_INT, &input_mbmode_size,
75       "input stream height", NULL},
76   {"iqp", 'q', 0, G_OPTION_ARG_INT, &input_qp,
77       "input qp val (it will get replicated for each macrobock)", NULL},
78   {"imbcntrl", 'l', 0, G_OPTION_ARG_INT, &enable_mbcntrl,
79       "enable macroblock control for each macrobock", NULL},
80   {"imbpred", 'p', 0, G_OPTION_ARG_INT, &enable_mvpred,
81       "enable mv predictor for each macroblock", NULL},
82   {"fei-mode", 'e', 0, G_OPTION_ARG_INT, &fei_mode,
83       "1:ENC 2:PAK 3:ENC+PAK 4:ENC_PAK", NULL},
84
85   {G_OPTION_REMAINING, ' ', 0, G_OPTION_ARG_FILENAME_ARRAY, &g_input_files,
86       "input file name", NULL},
87   {NULL}
88 };
89
90 typedef struct
91 {
92   GstVaapiDisplay *display;
93   GstVaapiEncoder *encoder;
94   guint read_frames;
95   guint encoded_frames;
96   guint saved_frames;
97   Y4MReader *parser;
98   FILE *output_file;
99   int mv_fd;
100   int mbmode_fd;
101   guint input_mv_size;
102   guint input_mbmode_size;
103   guint input_stopped:1;
104   guint encode_failed:1;
105 } App;
106
107 static inline gchar *
108 generate_output_filename (const gchar * ext)
109 {
110   gchar *fn;
111   int i = 0;
112
113   while (1) {
114     fn = g_strdup_printf ("temp%02d.%s", i, ext);
115     if (g_file_test (fn, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
116       i++;
117       g_free (fn);
118     } else {
119       break;
120     }
121   }
122
123   return fn;
124 }
125
126 static gboolean
127 parse_options (int *argc, char *argv[])
128 {
129   GOptionContext *ctx;
130   gboolean success;
131   GError *error = NULL;
132
133   ctx = g_option_context_new (" - encoder test options");
134   if (!ctx)
135     return FALSE;
136
137   g_option_context_add_group (ctx, gst_init_get_option_group ());
138   g_option_context_add_main_entries (ctx, g_options, NULL);
139   g_option_context_set_help_enabled (ctx, TRUE);
140   success = g_option_context_parse (ctx, argc, &argv, &error);
141   if (!success) {
142     g_printerr ("Option parsing failed: %s\n", error->message);
143     g_error_free (error);
144     goto bail;
145   }
146
147   if (!g_codec_str)
148     g_codec_str = g_strdup ("h264");
149   if (!g_output_file_name)
150     g_output_file_name = generate_output_filename (g_codec_str);
151
152 bail:
153   g_option_context_free (ctx);
154   return success;
155 }
156
157 static void
158 print_yuv_info (App * app)
159 {
160   g_print ("\n");
161   g_print ("Encode      : %s\n", g_codec_str);
162   g_print ("Resolution  : %dx%d\n", app->parser->width, app->parser->height);
163   g_print ("Source YUV  : %s\n", g_input_files ? g_input_files[0] : "stdin");
164   g_print ("Frame Rate  : %0.1f fps\n",
165       1.0 * app->parser->fps_n / app->parser->fps_d);
166   g_print ("Coded file  : %s\n", g_output_file_name);
167   g_print ("\n");
168 }
169
170 static void
171 print_num_frame (App * app)
172 {
173   g_print ("\n");
174   g_print ("read frames    : %d\n", app->read_frames);
175   g_print ("encoded frames : %d\n", app->encoded_frames);
176   g_print ("saved frames   : %d\n", app->saved_frames);
177   g_print ("\n");
178 }
179
180 static GstVaapiEncoder *
181 encoder_new (GstVaapiDisplay * display)
182 {
183   GstVaapiEncoder *encoder = NULL;
184
185   if (!g_strcmp0 (g_codec_str, "h264")) {
186     encoder = gst_vaapi_encoder_h264_fei_new (display);
187     gst_vaapi_encoder_h264_fei_set_function_mode (GST_VAAPI_ENCODER_H264_FEI
188         (encoder), fei_mode);
189     gst_vaapi_encoder_h264_fei_set_max_profile (GST_VAAPI_ENCODER_H264_FEI
190         (encoder), GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE);
191   } else
192     return NULL;
193
194   return encoder;
195 }
196
197 static inline GstVideoCodecState *
198 new_codec_state (gint width, gint height, gint fps_n, gint fps_d)
199 {
200   GstVideoCodecState *state;
201
202   state = g_slice_new0 (GstVideoCodecState);
203   state->ref_count = 1;
204   gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, width,
205       height);
206
207   state->info.fps_n = fps_n;
208   state->info.fps_d = fps_d;
209
210   return state;
211 }
212
213 static gboolean
214 set_format (GstVaapiEncoder * encoder, gint width, gint height, gint fps_n,
215     gint fps_d)
216 {
217   GstVideoCodecState *in_state;
218   GstVaapiEncoderStatus status;
219
220   in_state = new_codec_state (width, height, fps_n, fps_d);
221   status = gst_vaapi_encoder_set_codec_state (encoder, in_state);
222   g_slice_free (GstVideoCodecState, in_state);
223
224   return (status == GST_VAAPI_ENCODER_STATUS_SUCCESS);
225 }
226
227 static GstBuffer *
228 allocate_buffer (GstVaapiCodedBuffer * vbuf)
229 {
230   GstBuffer *buf;
231   gssize size;
232
233   size = gst_vaapi_coded_buffer_get_size (vbuf);
234
235   if (size <= 0) {
236     g_warning ("Invalid VA buffer size (%zd)", size);
237     return NULL;
238   }
239
240   buf = gst_buffer_new_and_alloc (size);
241   if (!buf) {
242     g_warning ("Failed to create output buffer of size %zd", size);
243     return NULL;
244   }
245
246   if (!gst_vaapi_coded_buffer_copy_into (buf, vbuf)) {
247     g_warning ("Failed to copy VA buffer data");
248     gst_buffer_unref (buf);
249     return NULL;
250   }
251
252   return buf;
253 }
254
255 static GstVaapiEncoderStatus
256 get_encoder_buffer (GstVaapiEncoder * encoder, GstBuffer ** buffer)
257 {
258   GstVaapiCodedBufferProxy *proxy = NULL;
259   GstVaapiEncoderStatus status;
260
261   status = gst_vaapi_encoder_get_buffer_with_timeout (encoder, &proxy, 50000);
262   if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) {
263     g_warning ("Failed to get a buffer from encoder: %d", status);
264     return status;
265   } else if (status > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
266     return status;
267   }
268
269   *buffer = allocate_buffer (GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy));
270   gst_vaapi_coded_buffer_proxy_unref (proxy);
271
272   return status;
273 }
274
275 static gboolean
276 outputs_to_file (GstBuffer * buffer, FILE * file)
277 {
278   GstMapInfo info;
279   size_t written;
280   gboolean ret = FALSE;
281
282   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
283     return FALSE;
284
285   if (info.size <= 0 || !info.data)
286     return FALSE;
287
288   written = fwrite (info.data, 1, info.size, file);
289   if (written < info.size) {
290     g_warning ("write file error.");
291     goto bail;
292   }
293
294   ret = TRUE;
295
296 bail:
297   gst_buffer_unmap (buffer, &info);
298   return ret;
299 }
300
301 static gpointer
302 get_buffer_thread (gpointer data)
303 {
304   App *app = data;
305
306   GstVaapiEncoderStatus ret;
307   GstBuffer *obuf;
308
309   while (1) {
310     obuf = NULL;
311     ret = get_encoder_buffer (app->encoder, &obuf);
312     if (app->input_stopped && ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
313       break;                    /* finished */
314     } else if (ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {        /* another chance */
315       continue;
316     }
317     if (ret < GST_VAAPI_ENCODER_STATUS_SUCCESS) {       /* fatal error */
318       app->encode_failed = TRUE;
319       break;
320     }
321
322     app->encoded_frames++;
323     g_debug ("encoded frame %d, buffer = %p", app->encoded_frames, obuf);
324
325     if (app->output_file && outputs_to_file (obuf, app->output_file))
326       app->saved_frames++;
327
328     gst_buffer_unref (obuf);
329   }
330   if (obuf)
331     gst_buffer_replace (&obuf, NULL);
332
333   return NULL;
334 }
335
336 static void
337 app_free (App * app)
338 {
339   g_return_if_fail (app);
340
341   if (app->parser)
342     y4m_reader_close (app->parser);
343
344   if (app->encoder) {
345     gst_vaapi_encoder_flush (app->encoder);
346     gst_object_unref (app->encoder);
347   }
348
349   if (app->display)
350     gst_object_unref (app->display);
351
352   if (app->output_file)
353     fclose (app->output_file);
354
355   g_slice_free (App, app);
356 }
357
358 static App *
359 app_new (const gchar * input_fn, const gchar * output_fn)
360 {
361   App *app = g_slice_new0 (App);
362   if (!app)
363     return NULL;
364   app->parser = y4m_reader_open (input_fn);
365   if (!app->parser) {
366     g_warning ("Could not parse input stream.");
367     goto error;
368   }
369
370   app->output_file = fopen (output_fn, "w");
371   if (app->output_file == NULL) {
372     g_warning ("Could not open file \"%s\" for writing: %s.", output_fn,
373         g_strerror (errno));
374     goto error;
375   }
376
377   /* if PAK only */
378   if (fei_mode == 2) {
379     if (!input_mv_name || !input_mbmode_name) {
380       g_warning ("pak only mode need an mv and mbmode files as input");
381       assert (0);
382     }
383
384     if (input_mv_name)
385       app->mv_fd = open (input_mv_name, O_RDONLY, 0);
386     if (input_mbmode_name)
387       app->mbmode_fd = open (input_mbmode_name, O_RDONLY, 0);
388
389     assert (app->mv_fd >= 0);
390     assert (app->mbmode_fd >= 0);
391   }
392
393   app->display = video_output_create_display (NULL);
394   if (!app->display) {
395     g_warning ("Could not create VA display.");
396     goto error;
397   }
398
399   app->encoder = encoder_new (app->display);
400   if (!app->encoder) {
401     g_warning ("Could not create encoder.");
402     goto error;
403   }
404
405   if (!set_format (app->encoder, app->parser->width, app->parser->height,
406           app->parser->fps_n, app->parser->fps_d)) {
407     g_warning ("Could not set format.");
408     goto error;
409   }
410
411   return app;
412
413 error:
414   app_free (app);
415   return NULL;
416 }
417
418 static gboolean
419 upload_frame (GstVaapiEncoder * encoder, GstVaapiSurfaceProxy * proxy)
420 {
421   GstVideoCodecFrame *frame;
422   GstVaapiEncoderStatus ret;
423
424   frame = g_slice_new0 (GstVideoCodecFrame);
425   gst_video_codec_frame_set_user_data (frame,
426       gst_vaapi_surface_proxy_ref (proxy),
427       (GDestroyNotify) gst_vaapi_surface_proxy_unref);
428
429   ret = gst_vaapi_encoder_put_frame (encoder, frame);
430   return (ret == GST_VAAPI_ENCODER_STATUS_SUCCESS);
431 }
432
433 static gboolean
434 load_frame (App * app, GstVaapiImage * image)
435 {
436   gboolean ret = FALSE;
437
438   if (!gst_vaapi_image_map (image))
439     return FALSE;
440
441   ret = y4m_reader_load_image (app->parser, image);
442
443   if (!gst_vaapi_image_unmap (image))
444     return FALSE;
445
446   return ret;
447 }
448
449 static int
450 app_run (App * app)
451 {
452   GstVaapiImage *image;
453   GstVaapiVideoPool *pool;
454   GThread *buffer_thread;
455   gsize id;
456   gint i;
457
458   int ret = EXIT_FAILURE;
459   image = gst_vaapi_image_new (app->display, GST_VIDEO_FORMAT_I420,
460       app->parser->width, app->parser->height);
461
462   {
463     GstVideoInfo vi;
464     gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
465         app->parser->width, app->parser->height);
466     pool = gst_vaapi_surface_pool_new_full (app->display, &vi, 0);
467   }
468   buffer_thread = g_thread_new ("get buffer thread", get_buffer_thread, app);
469
470   while (1) {
471     GstVaapiSurfaceProxy *proxy;
472     GstVaapiSurface *surface;
473     gpointer data = NULL;
474     guint size = 0;
475     gint rt = 0;
476     guint mb_width, mb_height, mb_size;
477
478     if (!load_frame (app, image))
479       break;
480
481     if (!gst_vaapi_image_unmap (image))
482       break;
483
484     proxy =
485         gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool));
486     if (!proxy) {
487       g_warning ("Could not get surface proxy from pool.");
488       break;
489     }
490     surface = gst_vaapi_surface_proxy_get_surface (proxy);
491     if (!surface) {
492       g_warning ("Could not get surface from proxy.");
493       break;
494     }
495
496     if (!gst_vaapi_surface_put_image (surface, image)) {
497       g_warning ("Could not update surface");
498       break;
499     }
500
501     mb_width = (app->parser->width + 15) >> 4;
502     mb_height = (app->parser->height + 15) >> 4;
503     mb_size = mb_width * mb_height;
504
505     /* PAK Only */
506     if (fei_mode == PAK) {
507       GstVaapiEncFeiMbCode *mbcode;
508       GstVaapiEncFeiMv *mv;
509       guint mv_size, mbmode_size;
510
511       mv_size = mb_width * mb_height * 128;
512       mbmode_size = mb_width * mb_height * 64;
513
514       if (input_mv_size)
515         assert (input_mv_size == mv_size);
516
517       if (input_mbmode_size)
518         assert (input_mbmode_size == mbmode_size);
519
520       /* Upload mbmode data */
521       mbcode = gst_vaapi_enc_fei_mb_code_new (app->encoder, NULL, mbmode_size);
522       rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT (mbcode),
523           &data, &size);
524       assert (rt == 1);
525       rt = read (app->mbmode_fd, data, mbmode_size);
526       assert (rt >= 0);
527
528       /* Upload mv data */
529       mv = gst_vaapi_enc_fei_mv_new (app->encoder, NULL, mv_size);
530       rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT (mv),
531           &data, &size);
532       assert (rt == 1);
533       rt = read (app->mv_fd, data, mv_size);
534       assert (rt >= 0);
535
536       /* assign mv and mbmode buffers to input surface proxy */
537       gst_vaapi_surface_proxy_set_fei_mb_code (proxy, mbcode);
538       gst_vaapi_surface_proxy_set_fei_mv (proxy, mv);
539
540     } else {
541       /* ENC, ENC+PAK and ENC_PAK */
542
543       if (input_qp) {
544         GstVaapiEncFeiQp *qp = NULL;
545         VAEncQPBufferH264 *pqp = NULL;
546         guint qp_size = 0;
547
548         qp_size = mb_width * mb_height * sizeof (VAEncQPBufferH264);
549
550         qp = gst_vaapi_enc_fei_qp_new (app->encoder, NULL, qp_size);
551         rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT (qp),
552             &data, &size);
553         assert (rt == 1);
554
555         pqp = (VAEncQPBufferH264 *) data;
556         for (i = 0; i < mb_size; i++) {
557           pqp->qp = input_qp;
558           pqp++;
559         }
560         gst_vaapi_surface_proxy_set_fei_qp (proxy, qp);
561       }
562
563       if (enable_mbcntrl) {
564         GstVaapiEncFeiMbControl *mbcntrl = NULL;
565         VAEncFEIMBControlH264 *pmbcntrl = NULL;
566         guint mbcntrl_size = 0;
567
568         mbcntrl_size = mb_width * mb_height * sizeof (VAEncFEIMBControlH264);
569         mbcntrl =
570             gst_vaapi_enc_fei_mb_control_new (app->encoder, NULL, mbcntrl_size);
571         rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
572             (mbcntrl), &data, &size);
573         assert (rt == 1);
574
575         pmbcntrl = (VAEncFEIMBControlH264 *) data;
576         for (i = 0; i < mb_size; i++) {
577           pmbcntrl->force_to_intra = 1;
578           pmbcntrl->force_to_skip = 0;
579           pmbcntrl->force_to_nonskip = 0;
580           pmbcntrl->enable_direct_bias_adjustment = 0;
581           pmbcntrl->enable_motion_bias_adjustment = 0;
582           pmbcntrl->ext_mv_cost_scaling_factor = 0;
583           pmbcntrl->target_size_in_word = 0xff;
584           pmbcntrl->max_size_in_word = 0xff;
585           pmbcntrl++;
586         }
587         gst_vaapi_surface_proxy_set_fei_mb_control (proxy, mbcntrl);
588       }
589
590       if (enable_mvpred) {
591         GstVaapiEncFeiMvPredictor *mvpred = NULL;
592         VAEncFEIMVPredictorH264 *pmvpred = NULL;
593         guint mvpred_size = 0, j;
594
595         mvpred_size = mb_width * mb_height * sizeof (VAEncFEIMVPredictorH264);
596         mvpred =
597             gst_vaapi_enc_fei_mv_predictor_new (app->encoder, NULL,
598             mvpred_size);
599         rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
600             (mvpred), &data, &size);
601         assert (rt == 1);
602
603         pmvpred = (VAEncFEIMVPredictorH264 *) data;
604         for (i = 0; i < mb_size; i++) {
605           for (j = 0; i < 4; i++) {
606             pmvpred->ref_idx[j].ref_idx_l0 = 0;
607             pmvpred->ref_idx[j].ref_idx_l1 = 0;
608
609             pmvpred->mv[j].mv0[0] = 0x8000;
610             pmvpred->mv[j].mv0[1] = 0x8000;
611             pmvpred->mv[j].mv1[0] = 0x8000;
612             pmvpred->mv[j].mv1[1] = 0x8000;
613           }
614           pmvpred++;
615         }
616         gst_vaapi_surface_proxy_set_fei_mv_predictor (proxy, mvpred);
617       }
618     }
619
620     if (!upload_frame (app->encoder, proxy)) {
621       g_warning ("put frame failed");
622       break;
623     }
624
625     app->read_frames++;
626     id = gst_vaapi_surface_get_id (surface);
627     g_debug ("input frame %d, surface id = %" G_GSIZE_FORMAT, app->read_frames,
628         id);
629
630     gst_vaapi_surface_proxy_unref (proxy);
631   }
632
633   app->input_stopped = TRUE;
634
635   g_thread_join (buffer_thread);
636
637   if (!app->encode_failed && feof (app->parser->fp))
638     ret = EXIT_SUCCESS;
639
640   gst_vaapi_video_pool_replace (&pool, NULL);
641   gst_vaapi_object_unref (image);
642   return ret;
643 }
644
645 int
646 main (int argc, char *argv[])
647 {
648   App *app;
649   int ret = EXIT_FAILURE;
650   gchar *input_fn;
651
652   if (!parse_options (&argc, argv))
653     return EXIT_FAILURE;
654
655   /* @TODO: iterate all the input files */
656   input_fn = g_input_files ? g_input_files[0] : NULL;
657   if (input_fn && !g_file_test (input_fn,
658           G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
659     g_warning ("input file \"%s\" doesn't exist", input_fn);
660     goto bail;
661   }
662
663   app = app_new (input_fn, g_output_file_name);
664   if (!app)
665     goto bail;
666   print_yuv_info (app);
667   ret = app_run (app);
668   print_num_frame (app);
669
670   app_free (app);
671
672 bail:
673   g_free (g_codec_str);
674   g_free (g_output_file_name);
675   g_strfreev (g_input_files);
676
677   gst_deinit ();
678
679   return ret;
680 }