mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
FEI: Add test applications to showcase fei use case
test-fei-enc-out: A simple fei encoding application to output mv, mbcode and distortion eg: ./test-fei-enc-out -i sample_320x240.nv12 -w 320 -h 240 -o out.264 -v mv.out -d out.dist -m out.mbcode -e 1 test-fei-enc-in: A simple fei encoding application for testing input fei buffers eg: ./test-fei-enc-in -c h264 -o out.264 -e 4 -q 1 sample_i420.y4m Fixme: Running test-fei-enc-in in PAK mode with mv and mbcode input buffers from saved files is still not working People contributed: Wang, Yi <yi.a.wang@intel.com> Leilei <leilei.shang@intel.com> Zhong, Xiaoxia <xiaoxia.zhong@intel.com> xiaominc <xiaomin.chen@intel.com> Li, Jing B <jing.b.li@intel.com> https://bugzilla.gnome.org/show_bug.cgi?id=785712 https://bugzilla.gnome.org/show_bug.cgi?id=784667
This commit is contained in:
parent
5750bd7850
commit
9f98a02a05
3 changed files with 998 additions and 0 deletions
|
@ -14,6 +14,13 @@ noinst_PROGRAMS += \
|
|||
$(NULL)
|
||||
endif
|
||||
|
||||
if USE_H264_FEI_ENCODER
|
||||
noinst_PROGRAMS += \
|
||||
test-fei-enc-out \
|
||||
test-fei-enc-in \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
if USE_GLX
|
||||
noinst_PROGRAMS += \
|
||||
test-textures \
|
||||
|
@ -136,6 +143,18 @@ test_textures_CFLAGS = $(TEST_CFLAGS)
|
|||
test_textures_LDFLAGS = $(GST_VAAPI_LIBS)
|
||||
test_textures_LDADD = libutils.la $(TEST_LIBS)
|
||||
|
||||
test_fei_enc_out_SOURCES = test-fei-enc-out.c ../gst/vaapi/gstvaapifeivideometa.h
|
||||
test_fei_enc_out_CFLAGS = $(TEST_CFLAGS)
|
||||
test_fei_enc_out_LDFLAGS = $(GST_VAAPI_LIBS)
|
||||
test_fei_enc_out_LDADD = libutils.la $(TEST_LIBS)
|
||||
|
||||
test_fei_enc_in_sources_c = test-fei-enc-in.c ../gst/vaapi/gstvaapifeivideometa.h y4mreader.c
|
||||
test_fei_enc_in_sources_h = y4mreader.h
|
||||
test_fei_enc_in_SOURCES = $(test_fei_enc_in_sources_c)
|
||||
test_fei_enc_in_CFLAGS = $(TEST_CFLAGS) $(GST_VIDEO_CFLAGS)
|
||||
test_fei_enc_in_LDFLAGS = $(GST_VAAPI_LIBS)
|
||||
test_fei_enc_in_LDADD = libutils.la $(TEST_LIBS) $(GST_VIDEO_LIBS)
|
||||
|
||||
simple_decoder_source_c = simple-decoder.c
|
||||
simple_decoder_source_h =
|
||||
simple_decoder_SOURCES = $(simple_decoder_source_c)
|
||||
|
|
679
tests/test-fei-enc-in.c
Normal file
679
tests/test-fei-enc-in.c
Normal file
|
@ -0,0 +1,679 @@
|
|||
/*
|
||||
* test-fei-enc-in.c - Test FEI input buffer submission
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
/* sample pipeline: ./test-fei-enc-input -c h264 -o out.264 -e 4 -q 1 sample_i420.y4m */
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "gst/vaapi/sysdeps.h"
|
||||
#include <gst/vaapi/gstvaapiencoder.h>
|
||||
#include <gst/vaapi/gstvaapiencoder_h264_fei.h>
|
||||
#include <gst/vaapi/gstvaapisurfacepool.h>
|
||||
#include <gst/vaapi/gstvaapisurfaceproxy.h>
|
||||
#include <gst/vaapi/gstvaapifei_objects.h>
|
||||
#include "output.h"
|
||||
#include "y4mreader.h"
|
||||
#include <va/va.h>
|
||||
|
||||
static guint g_bitrate = 0;
|
||||
static gchar *g_codec_str;
|
||||
static gchar *g_output_file_name;
|
||||
static char **g_input_files = NULL;
|
||||
static gchar *input_mv_name = NULL;
|
||||
static gchar *input_mbmode_name = NULL;
|
||||
static guint input_mv_size;
|
||||
static guint input_mbmode_size;
|
||||
static guint input_qp;
|
||||
static guint enable_mbcntrl;
|
||||
static guint enable_mvpred;
|
||||
static guint fei_mode;
|
||||
|
||||
#define SURFACE_NUM 16
|
||||
|
||||
#define ENC 1
|
||||
#define PAK 2
|
||||
#define ENC_PLUS_PAK 3
|
||||
#define ENC_PAK 4
|
||||
|
||||
static GOptionEntry g_options[] = {
|
||||
{"codec", 'c', 0, G_OPTION_ARG_STRING, &g_codec_str,
|
||||
"codec to use for video encoding (h264)", NULL},
|
||||
{"bitrate", 'b', 0, G_OPTION_ARG_INT, &g_bitrate,
|
||||
"desired bitrate expressed in kbps", NULL},
|
||||
{"output", 'o', 0, G_OPTION_ARG_FILENAME, &g_output_file_name,
|
||||
"output file name", NULL},
|
||||
{"imv", 'v', 0, G_OPTION_ARG_STRING, &input_mv_name,
|
||||
"pak mv input file", NULL},
|
||||
{"imbmode ", 'm', 0, G_OPTION_ARG_STRING, &input_mbmode_name,
|
||||
"pak mbmode input file", NULL},
|
||||
{"imvsize", 's', 0, G_OPTION_ARG_INT, &input_mv_size,
|
||||
"input stream width", NULL},
|
||||
{"imbmodesize", 'd', 0, G_OPTION_ARG_INT, &input_mbmode_size,
|
||||
"input stream height", NULL},
|
||||
{"iqp", 'q', 0, G_OPTION_ARG_INT, &input_qp,
|
||||
"input qp val (it will get replicated for each macrobock)", NULL},
|
||||
{"imbcntrl", 'l', 0, G_OPTION_ARG_INT, &enable_mbcntrl,
|
||||
"enable macroblock control for each macrobock", NULL},
|
||||
{"imbpred", 'p', 0, G_OPTION_ARG_INT, &enable_mvpred,
|
||||
"enable mv predictor for each macroblock", NULL},
|
||||
{"fei-mode", 'e', 0, G_OPTION_ARG_INT, &fei_mode,
|
||||
"1:ENC 2:PAK 3:ENC+PAK 4:ENC_PAK", NULL},
|
||||
|
||||
{G_OPTION_REMAINING, ' ', 0, G_OPTION_ARG_FILENAME_ARRAY, &g_input_files,
|
||||
"input file name", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstVaapiDisplay *display;
|
||||
GstVaapiEncoder *encoder;
|
||||
guint read_frames;
|
||||
guint encoded_frames;
|
||||
guint saved_frames;
|
||||
Y4MReader *parser;
|
||||
FILE *output_file;
|
||||
int mv_fd;
|
||||
int mbmode_fd;
|
||||
guint input_mv_size;
|
||||
guint input_mbmode_size;
|
||||
guint input_stopped:1;
|
||||
guint encode_failed:1;
|
||||
} App;
|
||||
|
||||
static inline gchar *
|
||||
generate_output_filename (const gchar * ext)
|
||||
{
|
||||
gchar *fn;
|
||||
int i = 0;
|
||||
|
||||
while (1) {
|
||||
fn = g_strdup_printf ("temp%02d.%s", i, ext);
|
||||
if (g_file_test (fn, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
|
||||
i++;
|
||||
g_free (fn);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_options (int *argc, char *argv[])
|
||||
{
|
||||
GOptionContext *ctx;
|
||||
gboolean success;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_option_context_new (" - encoder test options");
|
||||
if (!ctx)
|
||||
return FALSE;
|
||||
|
||||
g_option_context_add_group (ctx, gst_init_get_option_group ());
|
||||
g_option_context_add_main_entries (ctx, g_options, NULL);
|
||||
g_option_context_set_help_enabled (ctx, TRUE);
|
||||
success = g_option_context_parse (ctx, argc, &argv, &error);
|
||||
if (!success) {
|
||||
g_printerr ("Option parsing failed: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!g_codec_str)
|
||||
g_codec_str = g_strdup ("h264");
|
||||
if (!g_output_file_name)
|
||||
g_output_file_name = generate_output_filename (g_codec_str);
|
||||
|
||||
bail:
|
||||
g_option_context_free (ctx);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
print_yuv_info (App * app)
|
||||
{
|
||||
g_print ("\n");
|
||||
g_print ("Encode : %s\n", g_codec_str);
|
||||
g_print ("Resolution : %dx%d\n", app->parser->width, app->parser->height);
|
||||
g_print ("Source YUV : %s\n", g_input_files ? g_input_files[0] : "stdin");
|
||||
g_print ("Frame Rate : %0.1f fps\n",
|
||||
1.0 * app->parser->fps_n / app->parser->fps_d);
|
||||
g_print ("Coded file : %s\n", g_output_file_name);
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_num_frame (App * app)
|
||||
{
|
||||
g_print ("\n");
|
||||
g_print ("read frames : %d\n", app->read_frames);
|
||||
g_print ("encoded frames : %d\n", app->encoded_frames);
|
||||
g_print ("saved frames : %d\n", app->saved_frames);
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
static GstVaapiEncoder *
|
||||
encoder_new (GstVaapiDisplay * display)
|
||||
{
|
||||
GstVaapiEncoder *encoder = NULL;
|
||||
|
||||
if (!g_strcmp0 (g_codec_str, "h264")) {
|
||||
encoder = gst_vaapi_encoder_h264_fei_new (display);
|
||||
gst_vaapi_encoder_h264_fei_set_function_mode (GST_VAAPI_ENCODER_H264_FEI
|
||||
(encoder), fei_mode);
|
||||
gst_vaapi_encoder_h264_fei_set_max_profile (GST_VAAPI_ENCODER_H264_FEI
|
||||
(encoder), GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE);
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
static inline GstVideoCodecState *
|
||||
new_codec_state (gint width, gint height, gint fps_n, gint fps_d)
|
||||
{
|
||||
GstVideoCodecState *state;
|
||||
|
||||
state = g_slice_new0 (GstVideoCodecState);
|
||||
state->ref_count = 1;
|
||||
gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, width,
|
||||
height);
|
||||
|
||||
state->info.fps_n = fps_n;
|
||||
state->info.fps_d = fps_d;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_format (GstVaapiEncoder * encoder, gint width, gint height, gint fps_n,
|
||||
gint fps_d)
|
||||
{
|
||||
GstVideoCodecState *in_state;
|
||||
GstVaapiEncoderStatus status;
|
||||
|
||||
in_state = new_codec_state (width, height, fps_n, fps_d);
|
||||
status = gst_vaapi_encoder_set_codec_state (encoder, in_state);
|
||||
g_slice_free (GstVideoCodecState, in_state);
|
||||
|
||||
return (status == GST_VAAPI_ENCODER_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
allocate_buffer (GstVaapiCodedBuffer * vbuf)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
gssize size;
|
||||
|
||||
size = gst_vaapi_coded_buffer_get_size (vbuf);
|
||||
|
||||
if (size <= 0) {
|
||||
g_warning ("Invalid VA buffer size (%zd)", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = gst_buffer_new_and_alloc (size);
|
||||
if (!buf) {
|
||||
g_warning ("Failed to create output buffer of size %zd", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!gst_vaapi_coded_buffer_copy_into (buf, vbuf)) {
|
||||
g_warning ("Failed to copy VA buffer data");
|
||||
gst_buffer_unref (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static GstVaapiEncoderStatus
|
||||
get_encoder_buffer (GstVaapiEncoder * encoder, GstBuffer ** buffer)
|
||||
{
|
||||
GstVaapiCodedBufferProxy *proxy = NULL;
|
||||
GstVaapiEncoderStatus status;
|
||||
|
||||
status = gst_vaapi_encoder_get_buffer_with_timeout (encoder, &proxy, 50000);
|
||||
if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) {
|
||||
g_warning ("Failed to get a buffer from encoder: %d", status);
|
||||
return status;
|
||||
} else if (status > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*buffer = allocate_buffer (GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy));
|
||||
gst_vaapi_coded_buffer_proxy_unref (proxy);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
outputs_to_file (GstBuffer * buffer, FILE * file)
|
||||
{
|
||||
GstMapInfo info;
|
||||
size_t written;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
gst_buffer_map (buffer, &info, GST_MAP_READ);
|
||||
|
||||
if (info.size <= 0 || !info.data)
|
||||
return FALSE;
|
||||
|
||||
written = fwrite (info.data, 1, info.size, file);
|
||||
if (written < info.size) {
|
||||
g_warning ("write file error.");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
bail:
|
||||
gst_buffer_unmap (buffer, &info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
get_buffer_thread (gpointer data)
|
||||
{
|
||||
App *app = data;
|
||||
|
||||
GstVaapiEncoderStatus ret;
|
||||
GstBuffer *obuf;
|
||||
|
||||
while (1) {
|
||||
obuf = NULL;
|
||||
ret = get_encoder_buffer (app->encoder, &obuf);
|
||||
if (app->input_stopped && ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
|
||||
break; /* finished */
|
||||
} else if (ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* another chance */
|
||||
continue;
|
||||
}
|
||||
if (ret < GST_VAAPI_ENCODER_STATUS_SUCCESS) { /* fatal error */
|
||||
app->encode_failed = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
app->encoded_frames++;
|
||||
g_debug ("encoded frame %d, buffer = %p", app->encoded_frames, obuf);
|
||||
|
||||
if (app->output_file && outputs_to_file (obuf, app->output_file))
|
||||
app->saved_frames++;
|
||||
|
||||
gst_buffer_unref (obuf);
|
||||
}
|
||||
if (obuf)
|
||||
gst_buffer_replace (&obuf, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
app_free (App * app)
|
||||
{
|
||||
g_return_if_fail (app);
|
||||
|
||||
if (app->parser)
|
||||
y4m_reader_close (app->parser);
|
||||
|
||||
if (app->encoder) {
|
||||
gst_vaapi_encoder_flush (app->encoder);
|
||||
gst_vaapi_encoder_unref (app->encoder);
|
||||
}
|
||||
|
||||
if (app->display)
|
||||
gst_vaapi_display_unref (app->display);
|
||||
|
||||
if (app->output_file)
|
||||
fclose (app->output_file);
|
||||
|
||||
g_slice_free (App, app);
|
||||
}
|
||||
|
||||
static App *
|
||||
app_new (const gchar * input_fn, const gchar * output_fn)
|
||||
{
|
||||
App *app = g_slice_new0 (App);
|
||||
if (!app)
|
||||
return NULL;
|
||||
app->parser = y4m_reader_open (input_fn);
|
||||
if (!app->parser) {
|
||||
g_warning ("Could not parse input stream.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
app->output_file = fopen (output_fn, "w");
|
||||
if (app->output_file == NULL) {
|
||||
g_warning ("Could not open file \"%s\" for writing: %s.", output_fn,
|
||||
g_strerror (errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* if PAK only */
|
||||
if (fei_mode == 2) {
|
||||
if (!input_mv_name || !input_mbmode_name) {
|
||||
g_warning ("pak only mode need an mv and mbmode files as input");
|
||||
assert (0);
|
||||
}
|
||||
|
||||
if (input_mv_name)
|
||||
app->mv_fd = open (input_mv_name, O_RDONLY, 0);
|
||||
if (input_mbmode_name)
|
||||
app->mbmode_fd = open (input_mbmode_name, O_RDONLY, 0);
|
||||
|
||||
assert (app->mv_fd >= 0);
|
||||
assert (app->mbmode_fd >= 0);
|
||||
}
|
||||
|
||||
app->display = video_output_create_display (NULL);
|
||||
if (!app->display) {
|
||||
g_warning ("Could not create VA display.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
app->encoder = encoder_new (app->display);
|
||||
if (!app->encoder) {
|
||||
g_warning ("Could not create encoder.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!set_format (app->encoder, app->parser->width, app->parser->height,
|
||||
app->parser->fps_n, app->parser->fps_d)) {
|
||||
g_warning ("Could not set format.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return app;
|
||||
|
||||
error:
|
||||
app_free (app);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
upload_frame (GstVaapiEncoder * encoder, GstVaapiSurfaceProxy * proxy)
|
||||
{
|
||||
GstVideoCodecFrame *frame;
|
||||
GstVaapiEncoderStatus ret;
|
||||
|
||||
frame = g_slice_new0 (GstVideoCodecFrame);
|
||||
gst_video_codec_frame_set_user_data (frame,
|
||||
gst_vaapi_surface_proxy_ref (proxy),
|
||||
(GDestroyNotify) gst_vaapi_surface_proxy_unref);
|
||||
|
||||
ret = gst_vaapi_encoder_put_frame (encoder, frame);
|
||||
return (ret == GST_VAAPI_ENCODER_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_frame (App * app, GstVaapiImage * image)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (!gst_vaapi_image_map (image))
|
||||
return FALSE;
|
||||
|
||||
ret = y4m_reader_load_image (app->parser, image);
|
||||
|
||||
if (!gst_vaapi_image_unmap (image))
|
||||
return FALSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
app_run (App * app)
|
||||
{
|
||||
GstVaapiImage *image;
|
||||
GstVaapiVideoPool *pool;
|
||||
GThread *buffer_thread;
|
||||
gsize id;
|
||||
gint i;
|
||||
|
||||
int ret = EXIT_FAILURE;
|
||||
image = gst_vaapi_image_new (app->display, GST_VIDEO_FORMAT_I420,
|
||||
app->parser->width, app->parser->height);
|
||||
|
||||
{
|
||||
GstVideoInfo vi;
|
||||
gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
|
||||
app->parser->width, app->parser->height);
|
||||
pool = gst_vaapi_surface_pool_new_full (app->display, &vi, 0);
|
||||
}
|
||||
buffer_thread = g_thread_new ("get buffer thread", get_buffer_thread, app);
|
||||
|
||||
while (1) {
|
||||
GstVaapiSurfaceProxy *proxy;
|
||||
GstVaapiSurface *surface;
|
||||
gpointer data = NULL;
|
||||
guint size = 0;
|
||||
gint rt = 0;
|
||||
guint mb_width, mb_height, mb_size;
|
||||
|
||||
if (!load_frame (app, image))
|
||||
break;
|
||||
|
||||
if (!gst_vaapi_image_unmap (image))
|
||||
break;
|
||||
|
||||
proxy =
|
||||
gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool));
|
||||
if (!proxy) {
|
||||
g_warning ("Could not get surface proxy from pool.");
|
||||
break;
|
||||
}
|
||||
surface = gst_vaapi_surface_proxy_get_surface (proxy);
|
||||
if (!surface) {
|
||||
g_warning ("Could not get surface from proxy.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!gst_vaapi_surface_put_image (surface, image)) {
|
||||
g_warning ("Could not update surface");
|
||||
break;
|
||||
}
|
||||
|
||||
mb_width = (app->parser->width + 15) >> 4;
|
||||
mb_height = (app->parser->height + 15) >> 4;
|
||||
mb_size = mb_width * mb_height;
|
||||
|
||||
/* PAK Only */
|
||||
if (fei_mode == PAK) {
|
||||
GstVaapiEncFeiMbCode *mbcode;
|
||||
GstVaapiEncFeiMv *mv;
|
||||
guint mv_size, mbmode_size;
|
||||
|
||||
mv_size = mb_width * mb_height * 128;
|
||||
mbmode_size = mb_width * mb_height * 64;
|
||||
|
||||
if (input_mv_size)
|
||||
assert (input_mv_size == mv_size);
|
||||
|
||||
if (input_mbmode_size)
|
||||
assert (input_mbmode_size == mbmode_size);
|
||||
|
||||
/* Upload mbmode data */
|
||||
mbcode = gst_vaapi_enc_fei_mb_code_new (app->encoder, NULL, mbmode_size);
|
||||
rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT (mbcode),
|
||||
&data, &size);
|
||||
assert (rt == 1);
|
||||
rt = read (app->mbmode_fd, data, mbmode_size);
|
||||
assert (rt >= 0);
|
||||
|
||||
/* Upload mv data */
|
||||
mv = gst_vaapi_enc_fei_mv_new (app->encoder, NULL, mv_size);
|
||||
rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT (mv),
|
||||
&data, &size);
|
||||
assert (rt == 1);
|
||||
rt = read (app->mv_fd, data, mv_size);
|
||||
assert (rt >= 0);
|
||||
|
||||
/* assign mv and mbmode buffers to input surface proxy */
|
||||
gst_vaapi_surface_proxy_set_fei_mb_code (proxy, mbcode);
|
||||
gst_vaapi_surface_proxy_set_fei_mv (proxy, mv);
|
||||
|
||||
} else {
|
||||
/* ENC, ENC+PAK and ENC_PAK */
|
||||
|
||||
if (input_qp) {
|
||||
GstVaapiEncFeiQp *qp = NULL;
|
||||
VAEncQPBufferH264 *pqp = NULL;
|
||||
guint qp_size = 0;
|
||||
|
||||
qp_size = mb_width * mb_height * sizeof (VAEncQPBufferH264);
|
||||
|
||||
qp = gst_vaapi_enc_fei_qp_new (app->encoder, NULL, qp_size);
|
||||
rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT (qp),
|
||||
&data, &size);
|
||||
assert (rt == 1);
|
||||
|
||||
pqp = (VAEncQPBufferH264 *) data;
|
||||
for (i = 0; i < mb_size; i++) {
|
||||
pqp->qp = input_qp;
|
||||
pqp++;
|
||||
}
|
||||
gst_vaapi_surface_proxy_set_fei_qp (proxy, qp);
|
||||
}
|
||||
|
||||
if (enable_mbcntrl) {
|
||||
GstVaapiEncFeiMbControl *mbcntrl = NULL;
|
||||
VAEncFEIMBControlH264 *pmbcntrl = NULL;
|
||||
guint mbcntrl_size = 0;
|
||||
|
||||
mbcntrl_size = mb_width * mb_height * sizeof (VAEncFEIMBControlH264);
|
||||
mbcntrl =
|
||||
gst_vaapi_enc_fei_mb_control_new (app->encoder, NULL, mbcntrl_size);
|
||||
rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(mbcntrl), &data, &size);
|
||||
assert (rt == 1);
|
||||
|
||||
pmbcntrl = (VAEncFEIMBControlH264 *) data;
|
||||
for (i = 0; i < mb_size; i++) {
|
||||
pmbcntrl->force_to_intra = 1;
|
||||
pmbcntrl->force_to_skip = 0;
|
||||
pmbcntrl->force_to_nonskip = 0;
|
||||
pmbcntrl->enable_direct_bias_adjustment = 0;
|
||||
pmbcntrl->enable_motion_bias_adjustment = 0;
|
||||
pmbcntrl->ext_mv_cost_scaling_factor = 0;
|
||||
pmbcntrl->target_size_in_word = 0xff;
|
||||
pmbcntrl->max_size_in_word = 0xff;
|
||||
pmbcntrl++;
|
||||
}
|
||||
gst_vaapi_surface_proxy_set_fei_mb_control (proxy, mbcntrl);
|
||||
}
|
||||
|
||||
if (enable_mvpred) {
|
||||
GstVaapiEncFeiMvPredictor *mvpred = NULL;
|
||||
VAEncFEIMVPredictorH264 *pmvpred = NULL;
|
||||
guint mvpred_size = 0, j;
|
||||
|
||||
mvpred_size = mb_width * mb_height * sizeof (VAEncFEIMVPredictorH264);
|
||||
mvpred =
|
||||
gst_vaapi_enc_fei_mv_predictor_new (app->encoder, NULL,
|
||||
mvpred_size);
|
||||
rt = gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(mvpred), &data, &size);
|
||||
assert (rt == 1);
|
||||
|
||||
pmvpred = (VAEncFEIMVPredictorH264 *) data;
|
||||
for (i = 0; i < mb_size; i++) {
|
||||
for (j = 0; i < 4; i++) {
|
||||
pmvpred->ref_idx[j].ref_idx_l0 = 0;
|
||||
pmvpred->ref_idx[j].ref_idx_l1 = 0;
|
||||
|
||||
pmvpred->mv[j].mv0[0] = 0x8000;
|
||||
pmvpred->mv[j].mv0[1] = 0x8000;
|
||||
pmvpred->mv[j].mv1[0] = 0x8000;
|
||||
pmvpred->mv[j].mv1[1] = 0x8000;
|
||||
}
|
||||
pmvpred++;
|
||||
}
|
||||
gst_vaapi_surface_proxy_set_fei_mv_predictor (proxy, mvpred);
|
||||
}
|
||||
}
|
||||
|
||||
if (!upload_frame (app->encoder, proxy)) {
|
||||
g_warning ("put frame failed");
|
||||
break;
|
||||
}
|
||||
|
||||
app->read_frames++;
|
||||
id = gst_vaapi_surface_get_id (surface);
|
||||
g_debug ("input frame %d, surface id = %" G_GSIZE_FORMAT, app->read_frames,
|
||||
id);
|
||||
|
||||
gst_vaapi_surface_proxy_unref (proxy);
|
||||
}
|
||||
|
||||
app->input_stopped = TRUE;
|
||||
|
||||
g_thread_join (buffer_thread);
|
||||
|
||||
if (!app->encode_failed && feof (app->parser->fp))
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
gst_vaapi_video_pool_replace (&pool, NULL);
|
||||
gst_vaapi_object_unref (image);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
App *app;
|
||||
int ret = EXIT_FAILURE;
|
||||
gchar *input_fn;
|
||||
|
||||
if (!parse_options (&argc, argv))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* @TODO: iterate all the input files */
|
||||
input_fn = g_input_files ? g_input_files[0] : NULL;
|
||||
if (input_fn && !g_file_test (input_fn,
|
||||
G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
|
||||
g_warning ("input file \"%s\" doesn't exist", input_fn);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
app = app_new (input_fn, g_output_file_name);
|
||||
if (!app)
|
||||
goto bail;
|
||||
print_yuv_info (app);
|
||||
ret = app_run (app);
|
||||
print_num_frame (app);
|
||||
|
||||
app_free (app);
|
||||
|
||||
bail:
|
||||
g_free (g_codec_str);
|
||||
g_free (g_output_file_name);
|
||||
g_strfreev (g_input_files);
|
||||
|
||||
gst_deinit ();
|
||||
|
||||
return ret;
|
||||
}
|
300
tests/test-fei-enc-out.c
Normal file
300
tests/test-fei-enc-out.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* test-fei-enc-out.c - FEI Encoder Test application to dump output buffers
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* ./test-fei-enc -i sample_320x240.nv12 -f nv12 -w 320 -h 240 -o out.264 -v mv.out -d dist.out -m mbcode.out -e 1 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
#include <stdlib.h>
|
||||
#include "../gst/vaapi/gstvaapifeivideometa.h"
|
||||
#include <gst/video/video.h>
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstElement *pipeline, *filesrc, *videoparse, *enc, *capsfilter, *appsink;
|
||||
GError *err = NULL;
|
||||
GstStateChangeReturn ret;
|
||||
GstSample *sample;
|
||||
GstVideoFormat raw_format = GST_VIDEO_FORMAT_NV12;
|
||||
GOptionContext *ctx;
|
||||
FILE *file = NULL;
|
||||
FILE *mv_file = NULL;
|
||||
FILE *dist_file = NULL;
|
||||
FILE *mbcode_file = NULL;
|
||||
FILE *fei_stat_file = NULL;
|
||||
gchar *input_file_name = NULL;
|
||||
gchar *output_file_name = NULL;
|
||||
gchar *output_mv_name = NULL;
|
||||
gchar *output_distortion_name = NULL;
|
||||
gchar *output_mbcode_name = NULL;
|
||||
gchar *input_format;
|
||||
guint input_width;
|
||||
guint input_height;
|
||||
guint enc_frame_num = 0;
|
||||
guint block_size = 0;
|
||||
guint fei_mode = 1;
|
||||
guint fei_mode_flag = 0x00000004;
|
||||
gboolean link_ok = FALSE;
|
||||
guint mv_buffer_size = 0;
|
||||
guint mbcode_buffer_size = 0;
|
||||
guint dist_buffer_size = 0;
|
||||
gpointer mapped_data = NULL;
|
||||
guint mapped_data_size = 0;
|
||||
const gchar *caps_string = "video/x-h264, profile=constrained-baseline";
|
||||
GstCaps *filter_caps = NULL;
|
||||
|
||||
GOptionEntry options[] = {
|
||||
{"input file", 'i', 0, G_OPTION_ARG_STRING, &input_file_name,
|
||||
"file to encode", NULL},
|
||||
{"output file", 'o', 0, G_OPTION_ARG_STRING, &output_file_name,
|
||||
"encpak output file", NULL},
|
||||
{"output mv file", 'v', 0, G_OPTION_ARG_STRING, &output_mv_name,
|
||||
"encpak mv output file", NULL},
|
||||
{"output distortion file", 'd', 0, G_OPTION_ARG_STRING,
|
||||
&output_distortion_name,
|
||||
"encpak distortion output file", NULL},
|
||||
{"output mbcode file", 'm', 0, G_OPTION_ARG_STRING, &output_mbcode_name,
|
||||
"encpak mbcode output file", NULL},
|
||||
{"format", 'f', 0, G_OPTION_ARG_STRING, &input_format,
|
||||
"input raw format: nv12 or i420", NULL},
|
||||
{"width", 'w', 0, G_OPTION_ARG_INT, &input_width,
|
||||
"input stream width", NULL},
|
||||
{"height", 'h', 0, G_OPTION_ARG_INT, &input_height,
|
||||
"input stream height", NULL},
|
||||
{"frame-num", 'n', 0, G_OPTION_ARG_INT, &enc_frame_num,
|
||||
"numumber of buffers to be encoded", NULL},
|
||||
{"blocksize", 's', 0, G_OPTION_ARG_INT, &block_size,
|
||||
"single buffer size of input stream", NULL},
|
||||
{"fei-mode", 'e', 0, G_OPTION_ARG_INT, &fei_mode,
|
||||
"1: ENC_PAK 2: ENC+PAK", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
ctx =
|
||||
g_option_context_new
|
||||
("encpak with element filesrc, videoparse, vaapih264feienc, appsink");
|
||||
g_option_context_add_main_entries (ctx, options, NULL);
|
||||
g_option_context_add_group (ctx, gst_init_get_option_group ());
|
||||
|
||||
if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
|
||||
g_print ("Error intializing: %s\n", err->message);
|
||||
g_option_context_free (ctx);
|
||||
g_clear_error (&err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (input_file_name == NULL || output_file_name == NULL) {
|
||||
g_print ("%s", g_option_context_get_help (ctx, TRUE, NULL));
|
||||
g_option_context_free (ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_strcmp0 (input_format, "nv12"))
|
||||
raw_format = GST_VIDEO_FORMAT_NV12;
|
||||
else if (!g_strcmp0 (input_format, "i420"))
|
||||
raw_format = GST_VIDEO_FORMAT_I420;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (!input_width || !input_height) {
|
||||
g_print ("%s", g_option_context_get_help (ctx, TRUE, NULL));
|
||||
g_option_context_free (ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (fei_mode) {
|
||||
case 1:
|
||||
fei_mode_flag = 0x00000004;
|
||||
break;
|
||||
case 2:
|
||||
fei_mode_flag = 0x00000001 | 0x00000002;
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown fei mode \n");
|
||||
g_assert (0);
|
||||
break;
|
||||
}
|
||||
|
||||
g_option_context_free (ctx);
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
/* create pipeline */
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
filesrc = gst_element_factory_make ("filesrc", "source");
|
||||
videoparse = gst_element_factory_make ("videoparse", "videoparse");
|
||||
enc = gst_element_factory_make ("vaapih264feienc", "encpak");
|
||||
capsfilter = gst_element_factory_make ("capsfilter", "enccaps");
|
||||
appsink = gst_element_factory_make ("appsink", "sink");
|
||||
|
||||
/* element prop setup */
|
||||
g_object_set (G_OBJECT (filesrc), "location", input_file_name, NULL);
|
||||
g_object_set (G_OBJECT (videoparse), "format", raw_format,
|
||||
"width", input_width, "height", input_height, NULL);
|
||||
|
||||
if (enc_frame_num != 0)
|
||||
g_object_set (G_OBJECT (filesrc), "num-buffers", enc_frame_num, NULL);
|
||||
if (block_size != 0)
|
||||
g_object_set (G_OBJECT (filesrc), "blocksize", block_size, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (enc), "fei-mode", fei_mode_flag, NULL);
|
||||
g_object_set (G_OBJECT (enc), "search-window", 5, NULL);
|
||||
g_object_set (G_OBJECT (enc), "max-bframes", 0, NULL);
|
||||
|
||||
filter_caps = gst_caps_from_string (caps_string);
|
||||
if (filter_caps)
|
||||
g_object_set (G_OBJECT (capsfilter), "caps", filter_caps, NULL);
|
||||
gst_caps_unref (filter_caps);
|
||||
|
||||
gst_bin_add_many (GST_BIN (pipeline), filesrc, videoparse, enc, capsfilter,
|
||||
appsink, NULL);
|
||||
|
||||
link_ok =
|
||||
gst_element_link_many (filesrc, videoparse, enc, capsfilter, appsink,
|
||||
NULL);
|
||||
if (!link_ok) {
|
||||
g_print ("filesrc, enc and appsink link fail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
file = fopen (output_file_name, "wb");
|
||||
|
||||
if (output_mv_name != NULL)
|
||||
mv_file = fopen (output_mv_name, "wb");
|
||||
|
||||
if (output_mbcode_name != NULL)
|
||||
mbcode_file = fopen (output_mbcode_name, "wb");
|
||||
|
||||
if (output_distortion_name != NULL)
|
||||
dist_file = fopen (output_distortion_name, "wb");
|
||||
|
||||
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||
g_printerr ("Unable to set the pipeline to the playing state.\n");
|
||||
gst_object_unref (pipeline);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* pull sample from pipeline */
|
||||
while (1) {
|
||||
g_signal_emit_by_name (appsink, "pull-sample", &sample, NULL);
|
||||
if (sample) {
|
||||
GstBuffer *buffer = NULL;
|
||||
GstMapInfo map, info;
|
||||
GstMemory *mem;
|
||||
GstVaapiFeiVideoMeta *meta = NULL;
|
||||
GstMeta *m = NULL;
|
||||
const GstMetaInfo *meta_info;
|
||||
GType api;
|
||||
|
||||
g_debug ("appsink received sample.\n");
|
||||
buffer = gst_sample_get_buffer (sample);
|
||||
if (gst_buffer_map (buffer, &map, GST_MAP_READ)) {
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
if (gst_memory_map (mem, &info, GST_MAP_READ))
|
||||
fwrite (info.data, 1, info.size, file);
|
||||
|
||||
gst_memory_unmap (mem, &info);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
}
|
||||
|
||||
meta_info = gst_meta_get_info ("GstVaapiFeiVideoMeta");
|
||||
api = meta_info->api;
|
||||
m = gst_buffer_get_meta (buffer, api);
|
||||
if (m != NULL)
|
||||
meta = ((GstVaapiFeiVideoMetaHolder *) (m))->meta;
|
||||
|
||||
if (meta != NULL) {
|
||||
|
||||
if (mv_file != NULL) {
|
||||
mapped_data = NULL;
|
||||
mapped_data_size = 0;
|
||||
if (gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(meta->mv), &mapped_data, &mapped_data_size)) {
|
||||
fwrite (mapped_data, 1, mapped_data_size, mv_file);
|
||||
gst_vaapi_fei_codec_object_unmap (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(meta->mv));
|
||||
mv_buffer_size = mapped_data_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbcode_file != NULL) {
|
||||
mapped_data = NULL;
|
||||
mapped_data_size = 0;
|
||||
if (gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(meta->mbcode), &mapped_data, &mapped_data_size)) {
|
||||
fwrite (mapped_data, 1, mapped_data_size, mbcode_file);
|
||||
gst_vaapi_fei_codec_object_unmap (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(meta->mbcode));
|
||||
mbcode_buffer_size = mapped_data_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (dist_file != NULL) {
|
||||
mapped_data = NULL;
|
||||
mapped_data_size = 0;
|
||||
if (gst_vaapi_fei_codec_object_map (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(meta->dist), &mapped_data, &mapped_data_size)) {
|
||||
fwrite (mapped_data, 1, mapped_data_size, dist_file);
|
||||
gst_vaapi_fei_codec_object_unmap (GST_VAAPI_FEI_CODEC_OBJECT
|
||||
(meta->dist));
|
||||
dist_buffer_size = mapped_data_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gst_sample_unref (sample);
|
||||
} else {
|
||||
g_print ("appsink finished receive sample.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fixme: Currently assuming the input video has only one resoultion
|
||||
* which may not be true */
|
||||
/* create a status file for dumping size of each fei output buffer */
|
||||
if (output_mv_name || output_mbcode_name || output_distortion_name) {
|
||||
fei_stat_file = fopen ("fei_stat.out", "wb");
|
||||
fprintf (fei_stat_file, "Frame_MotionVectorData_Buffer_Size => %d \n",
|
||||
mv_buffer_size);
|
||||
fprintf (fei_stat_file, "Frame_MacroblcokCode_Buffer_Size => %d \n",
|
||||
mbcode_buffer_size);
|
||||
fprintf (fei_stat_file, "Frame_Distortion_Buffer_Size => %d \n",
|
||||
dist_buffer_size);
|
||||
}
|
||||
|
||||
/* free */
|
||||
fclose (file);
|
||||
if (mv_file != NULL)
|
||||
fclose (mv_file);
|
||||
if (mbcode_file != NULL)
|
||||
fclose (mbcode_file);
|
||||
if (dist_file != NULL)
|
||||
fclose (dist_file);
|
||||
if (fei_stat_file)
|
||||
fclose (fei_stat_file);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_object_unref (pipeline);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue