After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 719528 - tests: add simple-encoder program
tests: add simple-encoder program
Status: RESOLVED FIXED
Product: gstreamer-vaapi
Classification: Other
Component: general
git master
Other Linux
: Normal enhancement
: ---
Assigned To: gstreamer-vaapi maintainer(s)
gstreamer-vaapi maintainer(s)
Depends on:
Blocks: 743569
 
 
Reported: 2013-11-29 05:06 UTC by Gwenole Beauchesne
Modified: 2015-05-12 10:10 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
0001-add-a-simple-encoder-test-program-that-uses-libgstva (33.88 KB, patch)
2013-12-13 04:32 UTC, Wind Yuan
none Details | Review
free surface queue (4.93 KB, patch)
2013-12-19 10:06 UTC, changzhix.wei@intel.com
none Details | Review
the patch of simple-encoder (24.28 KB, patch)
2014-01-03 11:49 UTC, changzhix.wei@intel.com
none Details | Review
tests: add simple-encoder program (24.36 KB, patch)
2015-05-01 14:52 UTC, Víctor Manuel Jáquez Leal
none Details | Review
tests: add simple-encoder program (20.90 KB, patch)
2015-05-05 11:30 UTC, Víctor Manuel Jáquez Leal
none Details | Review
tests: add simple-encoder program (22.84 KB, patch)
2015-05-06 10:16 UTC, Víctor Manuel Jáquez Leal
none Details | Review
tests: add simple-encoder program (22.82 KB, patch)
2015-05-06 10:19 UTC, Víctor Manuel Jáquez Leal
committed Details | Review

Description Gwenole Beauchesne 2013-11-29 05:06:14 UTC
Purpose: add a simple-encoder test program that uses libgstvaapi for video encoding to elementary (raw) streams. Input stream is raw YUV in the Y4M format. That can be from a regular file or standard input when the input filename is "-".

Usage: simple-encoder [options]* <source>

Options:
--output|-o     output file name
--codec|-c      codec to use for video encoding
--bitrate|-b    desired bitrate (kbps)

By default, and as an initial patch, the encoded stream shall conform to the minimally supported profile. That is "Constrained Baseline Profile" for H.264 and "Simple Profile" for MPEG-2. Though, those are the defaults to be generated by libgstvaapi. No extra work or option needed.
Comment 1 Wind Yuan 2013-12-04 09:32:52 UTC
Hi Gwenole,
   I see you add a <source> argument for simple-encoder. I think maybe some black/white/blue/red... pictures(or blocks) generated by the simple-encoder should be enough. Otherwise, gst-vaapi package may need to have a Y4M file for user to test. Simple-encoder is only for unit tests not to encoding real file.

Thanks,
Wind
Comment 2 Gwenole Beauchesne 2013-12-05 05:16:34 UTC
Hi,

(In reply to comment #1)

>    I see you add a <source> argument for simple-encoder. I think maybe some
> black/white/blue/red... pictures(or blocks) generated by the simple-encoder
> should be enough. Otherwise, gst-vaapi package may need to have a Y4M file for
> user to test. Simple-encoder is only for unit tests not to encoding real file.

simple-encoder test program is meant to encode real files too, i.e. show how to use libgstvaapi APIs, not simply for unit testing. Unit tests are in test-* sources. We probably could have a test-encode program to encode a single frame too, but the most useful thing is to have that simple-encoder. It will also serve performance evaluation and tuning purposes.

Besides, I opted for Y4M source format because it's very trivial to implement and generate. It should be less than 70 lines with comments.
Comment 3 Wind Yuan 2013-12-05 06:06:51 UTC
I thought it was only a simple test-encode. where you hope the code can be put, still in test directory?
even Y4M, we need only support I420 format, right?
Comment 4 Gwenole Beauchesne 2013-12-06 08:55:47 UTC
(In reply to comment #3)
> I thought it was only a simple test-encode. where you hope the code can be put,
> still in test directory?

Yes, alongside with simple-decoder there. We probably could move that to some tools/ directory, but tests/ was convenient so that to share some common files.

> even Y4M, we need only support I420 format, right?

Yes. Thanks.
Comment 5 Wind Yuan 2013-12-13 04:32:18 UTC
Created attachment 264111 [details] [review]
0001-add-a-simple-encoder-test-program-that-uses-libgstva

Hi Gwenole,
   Changzhi <changzhix.wei@intel.com> has wrote a patch for the simple encoder. please review, anything, please comment.

Thanks,
Wind
Comment 6 changzhix.wei@intel.com 2013-12-19 10:06:14 UTC
Created attachment 264522 [details] [review]
free surface queue

1.free surface queue 
2.if there is no source file, auto generated a image, after encode ,save to test.h264/test.mpeg2
Comment 7 Gwenole Beauchesne 2013-12-19 17:51:05 UTC
Review of attachment 264111 [details] [review]:

Overall:
- Squash patch two into patch one ;
- Use gst-indent(*) over any new file ;
- Remove auto-generation of VA surface contents. If no filename is supplied, <stdin> could be used instead so that you can have y4mcolorbars | simple-encoder [...].
- Update the code to match current libgstvaapi APIs.

(*) The tool is available from any upstream gstreamer git master repo in common/ submodule.

::: tests/simple-encoder.c
@@ +114,3 @@
+    GstVaapiEncObjUserDataHead head;
+    GstBuffer *vaapi_buf;
+} GstVaapiEncodeFrameUserData;

This is not needed. You always get a GstVaapiCodedBufferProxy from gst_vaapi_encoder_get_buffer_with_timeout().

@@ +311,3 @@
+
+    vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p);
+

Always use libgstvaapi APIs. Direct usage of VA-API calls is needed and not desired.

::: tests/y4mreader.c
@@ +1,3 @@
+#include "y4mreader.h"
+
+#define MAX_YUV4_HEADER 80

Not really useful?

@@ +4,3 @@
+#define Y4M_MAGIC "YUV4MPEG2"
+#define Y4M_FRAME_MAGIC "FRAME"
+

struct _Y4MImageFile {
  FILE *fp;
  guchar *header;
  guint header_size;
  Y4MImageFileInfo info;
};

static gboolean
read_header(Y4MImageFile *file)
{
}

static gboolean
parse_header(Y4MImageFile *file)
{
}

@@ +5,3 @@
+#define Y4M_FRAME_MAGIC "FRAME"
+
+int y4m_read_head(FILE* stream,y4m_info *y4minfo)

Y4MImageFile *
y4m_image_file_open(const gchar *filename)
{
}

The function will:
- Allocate Y4MImageFile structure ;
- Open the file with supplied name. Or stdin if NULL ;
- Call read_header() to fill up the header data ;
- Call parse_header() to parse the header (Y4MImageFileInfo).

@@ +34,3 @@
+        switch (*tokstart++) {
+        case 'W': // Width. Required.
+            width    = strtol(tokstart, &tokend, 10);

Correct way to read unsigned int would normally be:

unsigned long v = strtoul(tokstart, &tokend, 10);
if (*tokstart && *tokend == '\0')
  <value> e.g. info->width = v;
else {
  // error out
}

@@ +43,3 @@
+        case 'C': // Color space
+            if (strncmp("420", tokstart, 3) == 0) {
+                info.format = 1;

info->format = GST_VIDEO_FORMAT_I420;

@@ +66,3 @@
+            break;
+        case 'F': // Frame rate
+            sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown

if (sscanf(...) != 2)
   // error out

@@ +107,3 @@
+    if(current_location>0)
+        frame_count = (filelength-current_location)/one_frame_length;
+    info.framecount = frame_count;

The frame count calculation is not deterministic. There could be parameters after the "FRAME" token. Just drop it.

@@ +112,3 @@
+}
+
+int y4m_locate_first_frame(FILE* stream)

This won't be needed now that, on return from y4m_image_file_open(), you'd already be at the first "FRAME" token.

@@ +135,3 @@
+}
+
+int y4m_read_one_frame(FILE* stream,char**yuvdata,int size)

gboolean
y4m_image_file_read_frame(Y4MImageFile *file, GstVaapiImage *image, GError **out_error_ptr)
{
  // the user allocated GstVaapiImage is filled up, plane by plane to cope with stride requirements from GstVaapiImage.
}

::: tests/y4mreader.h
@@ +1,3 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>

This header, <sys/stat.h> is not needed.

@@ +15,3 @@
+int y4m_read_head(FILE* stream,y4m_info *info);
+int y4m_locate_first_frame(FILE* stream);
+int y4m_read_one_frame(FILE* stream,char**yuvdata,int size);

typedef struct _Y4MImageFile Y4MImageFile;
typedef struct _Y4MImageFileInfo Y4MImageFileInfo;

typedef struct _Y4MImageFileInfo {
  GstVideoFormat format;
  guint width;
  guint height;
  gfloat fps;
  guint flags; // a combination of GST_VAAPI_PICTURE_STRUCTURE ("mixed" not supported yet)
};

Y4MImageFile *
y4m_image_file_open(const gchar *filename);

void
y4m_image_file_close(Y4MImageFile *file);

gboolean
y4m_image_file_get_info(Y4MImageFile *file, Y4MImageFileInfo *out_info_ptr);

gboolean
y4m_image_file_read_image(Y4ImageFile *file, GstVaapiImage *image, GError **out_error_ptr);
Comment 8 Gwenole Beauchesne 2013-12-19 18:11:09 UTC
Review of attachment 264111 [details] [review]:

::: tests/simple-encoder.c
@@ +30,3 @@
+#include <gst/vaapi/gstvaapiimage_priv.h>
+#include <gst/vaapi/gstvaapiencoder_mpeg2_priv.h>
+#include <gst/vaapi/gstvaapiencoder_h264_priv.h>

Never use private definitions.

@@ +67,3 @@
+    g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free);  \
+  } G_STMT_END
+

Use your own locks, not GstVaapiEncoder private definitions.

@@ +588,3 @@
+    free(yuvdata);
+}
+

How to stream Y4M frames into GstVaapiSurface.

Initially:
- Create a GstVaapiSurfacePool, based on information from Y4MImageFileInfo (format, width, height -> gst_video_info_set_format() with format forced to GST_VIDEO_FORMAT_ENCODED).
- Create a GstVaapiImage with specified format, width, height.

In the producer loop, i.e. image reader loop:
- Create a GstVaapiSurfaceProxy from the GstVaapiSurfacePool
- Read a frame from the Y4M file. If returning FALSE, then stop image reader thread
- Upload the GstVaapiImage to the GstVaapiSurface

@@ +742,3 @@
+        g_codec_str = (char*)malloc (5);
+        memset(g_codec_str,0,5);
+        memcpy(g_codec_str,"h264",4);

g_codec_str = g_strdup("h264");
Comment 9 changzhix.wei@intel.com 2014-01-03 11:49:40 UTC
Created attachment 265214 [details] [review]
the patch of simple-encoder

Hi Gwenole:

   I modified the code according to your suggestion, and the file is based on your newest code.

Thanks,
Wei,changzhi
Comment 10 sreerenj 2015-01-27 16:41:46 UTC
Extremely sorry for the long delay ! I will push this by next week, after 0.5.10 release..
Comment 11 Víctor Manuel Jáquez Leal 2015-04-28 08:51:00 UTC
I tried to merge this patch last Friday but it is quite obsolete. It doesn't compile anymore.

I'll try to make it work and learn a bit about the encoding.
Comment 12 Víctor Manuel Jáquez Leal 2015-05-01 14:52:25 UTC
Created attachment 302725 [details] [review]
tests: add simple-encoder program

This patch adds a simple-encoder test program that uses libgstvaapi for video encoding
to elementary (raw) streams. Input stream is raw YUV in the Y4M format. That can be
from a regular file or standard input when the input filename is "-".

Usage: simple-encoder [options]* <source>

Options:
--output|-o     output file name
--codec|-c      codec to use for video encoding
--bitrate|-b    desired bitrate (kbps)

By default, and as an initial patch, the encoded stream shall conform to the
minimally supported profile. That is "Constrained Baseline Profile" for H.264
and "Simple Profile" for MPEG-2. Though, those are the defaults to be generated
by libgstvaapi.
Comment 13 Víctor Manuel Jáquez Leal 2015-05-01 14:54:35 UTC
Comment on attachment 302725 [details] [review]
tests: add simple-encoder program

Oops! This patch was a mistake. Sorry for the noise.
Comment 14 Víctor Manuel Jáquez Leal 2015-05-05 11:30:23 UTC
Created attachment 302920 [details] [review]
tests: add simple-encoder program

This patch adds a simple-encoder test program that uses libgstvaapi for video encoding
to elementary (raw) streams. Input stream is raw YUV in the Y4M format. That can be
from a regular file or standard input when the input filename is "-".

Usage: simple-encoder [options]* <source>

Options:
--output|-o     output file name
--codec|-c      codec to use for video encoding
--bitrate|-b    desired bitrate (kbps)

By default, and as an initial patch, the encoded stream shall conform to the
minimally supported profile. That is "Constrained Baseline Profile" for H.264
and "Simple Profile" for MPEG-2. Though, those are the defaults to be generated
by libgstvaapi.

You can find Y4M sample files here http://samples.mplayerhq.hu/yuv4mpeg2/

Based on changzhix.wei@intel.com's patch.
Comment 15 Gwenole Beauchesne 2015-05-05 13:01:12 UTC
Review of attachment 302920 [details] [review]:

Add:

   Original-patch-by: Changzhi Wei <changzhix.wei@intel.com>
   [list of changes on top of that]
   s-o-b: you

(not exhaustively reviewed yet).

::: tests/simple-encoder.c
@@ +410,3 @@
+
+  while (1) {
+    if (!load_frame (app, image))

Make load_frame() map, load, unmap. In the future, pushing a VA image that is still mapped could fail.
Comment 16 Gwenole Beauchesne 2015-05-05 13:13:59 UTC
Review of attachment 302920 [details] [review]:

+ please stop copying the wrong copyright template header. For some time/reason, I had added an extra " " (space) between the the star and the text. :)
i.e. please keep a single whitespace instead of two.
Comment 17 Gwenole Beauchesne 2015-05-05 14:24:17 UTC
Review of attachment 302920 [details] [review]:

::: tests/Makefile.am
@@ +129,3 @@
+simple_encoder_CFLAGS   = $(TEST_CFLAGS) $(GST_VIDEO_CFLAGS)
+simple_encoder_LDADD    = libutils.la libutils_dec.la $(TEST_LIBS) \
+	$(GST_VIDEO_LIBS)

I don't think libutils_dec to be necessary. However, a libutils_enc.la might be useful to hold e.g. the Y4M file reader.

::: tests/y4mreader.c
@@ +35,3 @@
+  gchar *str;
+
+  memset (header, 0, 80);

Why 80 bytes max all over in here? I don't see that in the specs. Maybe use BUFSIZ?

@@ +89,3 @@
+        guint num = strtol (str, NULL, 0);
+        if (errno)
+          return FALSE;

Same pattern copied all over here, please create a dedicated function to safely parse an int. e.g. static gboolean parse_int(const gchar *str, int *out_value_ptr);

@@ +109,3 @@
+        break;
+      }
+      case 'A': /* sample aspect ration */

ratio.

@@ +208,3 @@
+
+  size_t size = fread (plane, 1, frame_size, file->fp);
+  return size == frame_size;

You will need to split read_frame() into read_plane() and possibly read_line() [inlined?] so that to cope with Y4M image stride != VA image stride.
Comment 18 Víctor Manuel Jáquez Leal 2015-05-05 14:40:47 UTC
(In reply to Gwenole Beauchesne from comment #15)
> Review of attachment 302920 [details] [review] [review]:
> 
> Add:
> 
>    Original-patch-by: Changzhi Wei <changzhix.wei@intel.com>
>    [list of changes on top of that]

I would only write those changes in general, because the refactor took me ~95 commits.
Comment 19 Víctor Manuel Jáquez Leal 2015-05-05 14:47:12 UTC
(In reply to Gwenole Beauchesne from comment #17)
> Review of attachment 302920 [details] [review] [review]:
> ::: tests/y4mreader.c
> @@ +35,3 @@
> +  gchar *str;
> +
> +  memset (header, 0, 80);
> 
> Why 80 bytes max all over in here? I don't see that in the specs. Maybe use
> BUFSIZ?

I copied from here: https://svn.xiph.org/trunk/theora/examples/encoder_example.c
Comment 20 Víctor Manuel Jáquez Leal 2015-05-06 10:16:33 UTC
Created attachment 302966 [details] [review]
tests: add simple-encoder program

This patch adds a simple-encoder test program that uses libgstvaapi for video
encoding to elementary (raw) streams. Input stream is raw YUV in the Y4M
format. That can be from a regular file or standard input when the input
filename is "-".

Usage: simple-encoder [options]* <source>

Options:
--output|-o     output file name
--codec|-c      codec to use for video encoding
--bitrate|-b    desired bitrate (kbps)

By default, and as an initial patch, the encoded stream shall conform to the
minimally supported profile. That is "Constrained Baseline Profile" for H.264
and "Simple Profile" for MPEG-2. Though, those are the defaults to be
generated by libgstvaapi.

You can find Y4M sample files here http://samples.mplayerhq.hu/yuv4mpeg2/

Original-patch-by: Changzhi Wei <changzhix.wei@intel.com>
* general code clean-up
* removed the yuv reader thread
* re-wrote the y4m file parser
* updated used API fixed some wrong usage
* fixed a lot of memory leaks
* added the bitrate setting
* keep fps' numerator and denominator
* simplified the thread control
* removed custom logging and use glib

Signed-off-by: Víctor Manuel Jáquez Leal <victorx.jaquez@intel.com>
Comment 21 Víctor Manuel Jáquez Leal 2015-05-06 10:19:16 UTC
Created attachment 302967 [details] [review]
tests: add simple-encoder program

This patch adds a simple-encoder test program that uses libgstvaapi for video
encoding to elementary (raw) streams. Input stream is raw YUV in the Y4M
format. That can be from a regular file or standard input when the input
filename is "-".

Usage: simple-encoder [options]* <source>

Options:
--output|-o     output file name
--codec|-c      codec to use for video encoding
--bitrate|-b    desired bitrate (kbps)

By default, and as an initial patch, the encoded stream shall conform to the
minimally supported profile. That is "Constrained Baseline Profile" for H.264
and "Simple Profile" for MPEG-2. Though, those are the defaults to be
generated by libgstvaapi.

You can find Y4M sample files here http://samples.mplayerhq.hu/yuv4mpeg2/

Original-patch-by: Changzhi Wei <changzhix.wei@intel.com>
* general code clean-up
* removed the yuv reader thread
* re-wrote the y4m file parser
* updated used API fixed some wrong usage
* fixed a lot of memory leaks
* added the bitrate setting
* keep fps' numerator and denominator
* simplified the thread control
* removed custom logging and use glib

Signed-off-by: Víctor Manuel Jáquez Leal <victorx.jaquez@intel.com>
Comment 22 Víctor Manuel Jáquez Leal 2015-05-08 08:32:27 UTC
Gwenole, do you approve the patch? :)
Comment 23 Víctor Manuel Jáquez Leal 2015-05-12 10:10:02 UTC
Attachment 302967 [details] pushed as be40a1d - tests: add simple-encoder program