All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Add a libv4l plugin for video bitstream parsing
@ 2017-04-28 15:02 Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 1/3] v4l-utils: sync with kernel (parsed MPEG-2 support) Hugues Fruchet
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Hugues Fruchet @ 2017-04-28 15:02 UTC (permalink / raw)
  To: linux-media, Hans Verkuil
  Cc: Benjamin Gaignard, Hugues Fruchet, Jean-Christophe Trotin

Stateless video decoders require explicit codec specific metadata
derived from video bitstream parsing.
This plugin aims to silently convert the user provided video bitstream
to a parsed video bitstream, ie the video bitstream itself + additional
parsing metadata which are given to the driver through the V4L2 extended
control framework.
This plugin can support several codec dependent parser backends, enabling
of the right parser is done by intercepting the pixel format information
negotiated between user and driver (enum_fmt/try_fmt/get_fmt/s_fmt).
This patchset provides a MPEG-2 parser backend using GStreamer
codecparsers library.
It has been tested with STMicroelectronics st-delta kernel driver.

===========
= history =
===========
version 2:
  - rebase linux headers based on st-delta mpeg2 v6 patchset:
    http://www.mail-archive.com/linux-media@vger.kernel.org/msg112067.html

version 1:
  - initial submission


Hugues Fruchet (3):
  v4l-utils: sync with kernel (parsed MPEG-2 support)
  add libv4l-codecparsers plugin for video bitstream parsing
  libv4l-codecparsers: add GStreamer mpeg2 parser

 configure.ac                                      |  23 ++
 include/linux/v4l2-controls.h                     |  93 +++++
 include/linux/videodev2.h                         |   8 +
 lib/Makefile.am                                   |   3 +-
 lib/libv4l-codecparsers/Makefile.am               |  21 +
 lib/libv4l-codecparsers/libv4l-codecparsers.pc.in |  12 +
 lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c   | 375 +++++++++++++++++
 lib/libv4l-codecparsers/libv4l-cparsers.c         | 465 ++++++++++++++++++++++
 lib/libv4l-codecparsers/libv4l-cparsers.h         | 101 +++++
 9 files changed, 1100 insertions(+), 1 deletion(-)
 create mode 100644 lib/libv4l-codecparsers/Makefile.am
 create mode 100644 lib/libv4l-codecparsers/libv4l-codecparsers.pc.in
 create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
 create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers.c
 create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/3] v4l-utils: sync with kernel (parsed MPEG-2 support)
  2017-04-28 15:02 [PATCH v2 0/3] Add a libv4l plugin for video bitstream parsing Hugues Fruchet
@ 2017-04-28 15:02 ` Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 2/3] add libv4l-codecparsers plugin for video bitstream parsing Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser Hugues Fruchet
  2 siblings, 0 replies; 6+ messages in thread
From: Hugues Fruchet @ 2017-04-28 15:02 UTC (permalink / raw)
  To: linux-media, Hans Verkuil
  Cc: Benjamin Gaignard, Hugues Fruchet, Jean-Christophe Trotin

Add "parsed MPEG-2" pixel format & related controls
needed by stateless video decoders.
In order to decode the video bitstream chunk provided
by user on OUTPUT queue, stateless decoders require
also some extra data resulting from this video bitstream
chunk parsing.
Those parsed extra data have to be set by user through
control framework using the dedicated mpeg video extended
controls introduced in this patchset.

Change-Id: I60755685ccb41942574654f64632d1348b689033
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
 include/linux/v4l2-controls.h | 93 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/videodev2.h     |  8 ++++
 2 files changed, 101 insertions(+)

diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h
index 0d2e1e0..d8ad718 100644
--- a/include/linux/v4l2-controls.h
+++ b/include/linux/v4l2-controls.h
@@ -547,6 +547,99 @@ enum v4l2_mpeg_video_mpeg4_profile {
 };
 #define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL		(V4L2_CID_MPEG_BASE+407)
 
+/*
+ * parsed MPEG-2 controls
+ * (needed by stateless video decoders)
+ * Those controls have been defined based on MPEG-2 standard ISO/IEC 13818-2,
+ * and so derive directly from the MPEG-2 video bitstream syntax including
+ * how it is coded inside bitstream (enumeration values for ex.).
+ */
+#define MPEG2_QUANTISER_MATRIX_SIZE	64
+#define V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_HDR		(V4L2_CID_MPEG_BASE+450)
+struct v4l2_mpeg_video_mpeg2_seq_hdr {
+	__u16	width;
+	__u16	height;
+	__u8	aspect_ratio_info;
+	__u8	frame_rate_code;
+	__u16	vbv_buffer_size;
+	__u32	bitrate_value;
+	__u16	constrained_parameters_flag;
+	__u8	load_intra_quantiser_matrix;
+	__u8	load_non_intra_quantiser_matrix;
+	__u8	intra_quantiser_matrix[MPEG2_QUANTISER_MATRIX_SIZE];
+	__u8	non_intra_quantiser_matrix[MPEG2_QUANTISER_MATRIX_SIZE];
+	__u32	par_w;
+	__u32	par_h;
+	__u32	fps_n;
+	__u32	fps_d;
+	__u32	bitrate;
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_EXT		(V4L2_CID_MPEG_BASE+451)
+struct v4l2_mpeg_video_mpeg2_seq_ext {
+	__u8	profile;
+	__u8	level;
+	__u8	progressive;
+	__u8	chroma_format;
+	__u8	horiz_size_ext;
+	__u8	vert_size_ext;
+	__u16	bitrate_ext;
+	__u8	vbv_buffer_size_ext;
+	__u8	low_delay;
+	__u8	fps_n_ext;
+	__u8	fps_d_ext;
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_DISPLAY_EXT	(V4L2_CID_MPEG_BASE+452)
+struct v4l2_mpeg_video_mpeg2_seq_display_ext {
+	__u16	display_horizontal_size;
+	__u16	display_vertical_size;
+	__u8	video_format;
+	__u8	colour_description_flag;
+	__u8	colour_primaries;
+	__u8	transfer_characteristics;
+	__u8	matrix_coefficients;
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_MATRIX_EXT	(V4L2_CID_MPEG_BASE+453)
+struct v4l2_mpeg_video_mpeg2_seq_matrix_ext {
+	__u8	load_intra_quantiser_matrix;
+	__u8	intra_quantiser_matrix[MPEG2_QUANTISER_MATRIX_SIZE];
+	__u8	load_non_intra_quantiser_matrix;
+	__u8	non_intra_quantiser_matrix[MPEG2_QUANTISER_MATRIX_SIZE];
+	__u8	load_chroma_intra_quantiser_matrix;
+	__u8	chroma_intra_quantiser_matrix[MPEG2_QUANTISER_MATRIX_SIZE];
+	__u8	load_chroma_non_intra_quantiser_matrix;
+	__u8	chroma_non_intra_quantiser_matrix[MPEG2_QUANTISER_MATRIX_SIZE];
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR		(V4L2_CID_MPEG_BASE+454)
+struct v4l2_mpeg_video_mpeg2_pic_hdr {
+	__u32	offset;
+	__u16	tsn;
+	__u16	vbv_delay;
+	__u8	pic_type;
+	__u8	full_pel_forward_vector;
+	__u8	full_pel_backward_vector;
+	__u8	f_code[2][2];
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT		(V4L2_CID_MPEG_BASE+455)
+struct v4l2_mpeg_video_mpeg2_pic_ext {
+	__u8	f_code[2][2];
+	__u8	intra_dc_precision;
+	__u8	picture_structure;
+	__u8	top_field_first;
+	__u8	frame_pred_frame_dct;
+	__u8	concealment_motion_vectors;
+	__u8	q_scale_type;
+	__u8	intra_vlc_format;
+	__u8	alternate_scan;
+	__u8	repeat_first_field;
+	__u8	chroma_420_type;
+	__u8	progressive_frame;
+	__u8	composite_display;
+	__u8	v_axis;
+	__u8	field_sequence;
+	__u8	sub_carrier;
+	__u8	burst_amplitude;
+	__u8	sub_carrier_phase;
+};
 /*  Control IDs for VP8 streams
  *  Although VP8 is not part of MPEG we add these controls to the MPEG class
  *  as that class is already handling other video compression standards
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b1e36ee..ec4344c 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -618,7 +618,9 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */
 #define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
 #define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
+#define V4L2_PIX_FMT_MPEG1_PARSED v4l2_fourcc('M', 'G', '1', 'P') /* MPEG1 with parsing metadata given through controls */
 #define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
+#define V4L2_PIX_FMT_MPEG2_PARSED v4l2_fourcc('M', 'G', '2', 'P') /* MPEG2 with parsing metadata given through controls */
 #define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 part 2 ES */
 #define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
 #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
@@ -1597,6 +1599,12 @@ enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_U8	     = 0x0100,
 	V4L2_CTRL_TYPE_U16	     = 0x0101,
 	V4L2_CTRL_TYPE_U32	     = 0x0102,
+	V4L2_CTRL_TYPE_MPEG2_SEQ_HDR  = 0x0109,
+	V4L2_CTRL_TYPE_MPEG2_SEQ_EXT  = 0x010A,
+	V4L2_CTRL_TYPE_MPEG2_SEQ_DISPLAY_EXT  = 0x010B,
+	V4L2_CTRL_TYPE_MPEG2_SEQ_MATRIX_EXT  = 0x010C,
+	V4L2_CTRL_TYPE_MPEG2_PIC_HDR  = 0x010D,
+	V4L2_CTRL_TYPE_MPEG2_PIC_EXT  = 0x010E,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] add libv4l-codecparsers plugin for video bitstream parsing
  2017-04-28 15:02 [PATCH v2 0/3] Add a libv4l plugin for video bitstream parsing Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 1/3] v4l-utils: sync with kernel (parsed MPEG-2 support) Hugues Fruchet
@ 2017-04-28 15:02 ` Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser Hugues Fruchet
  2 siblings, 0 replies; 6+ messages in thread
From: Hugues Fruchet @ 2017-04-28 15:02 UTC (permalink / raw)
  To: linux-media, Hans Verkuil
  Cc: Benjamin Gaignard, Hugues Fruchet, Jean-Christophe Trotin

Stateless video decoders require explicit codec specific
metadata derived from video bitstream parsing.
This plugin aims to silently convert the user provided video
bitstream to a parsed video bitstream, ie the video bitstream itself
+ additional parsing metadata which are given to the driver through the
V4L2 extended control framework.
This plugin supports several codec dependent parser backends.
Enabling of the right parser is done by intercepting the pixel format
information negotiated between user and driver (enum_fmt/try_fmt/get_fmt/s_fmt).

Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
 configure.ac                                      |   2 +
 lib/Makefile.am                                   |   3 +-
 lib/libv4l-codecparsers/Makefile.am               |   9 +
 lib/libv4l-codecparsers/libv4l-codecparsers.pc.in |  12 +
 lib/libv4l-codecparsers/libv4l-cparsers.c         | 461 ++++++++++++++++++++++
 lib/libv4l-codecparsers/libv4l-cparsers.h         | 101 +++++
 6 files changed, 587 insertions(+), 1 deletion(-)
 create mode 100644 lib/libv4l-codecparsers/Makefile.am
 create mode 100644 lib/libv4l-codecparsers/libv4l-codecparsers.pc.in
 create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers.c
 create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers.h

diff --git a/configure.ac b/configure.ac
index dd29eda..9ce7392 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,7 @@ AC_CONFIG_FILES([Makefile
 	lib/libdvbv5/Makefile
 	lib/libv4l2rds/Makefile
 	lib/libv4l-mplane/Makefile
+	lib/libv4l-codecparsers/Makefile
 
 	utils/Makefile
 	utils/libv4l2util/Makefile
@@ -56,6 +57,7 @@ AC_CONFIG_FILES([Makefile
 	lib/libv4lconvert/libv4lconvert.pc
 	lib/libv4l1/libv4l1.pc
 	lib/libv4l2/libv4l2.pc
+	lib/libv4l-codecparsers/libv4l-codecparsers.pc
 	lib/libdvbv5/libdvbv5.pc
 	lib/libv4l2rds/libv4l2rds.pc
 	utils/media-ctl/libmediactl.pc
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a105c95..3aa8564 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3,7 +3,8 @@ SUBDIRS = \
 	libv4l2 \
 	libv4l1 \
 	libv4l2rds \
-	libv4l-mplane
+	libv4l-mplane \
+	libv4l-codecparsers
 
 if WITH_LIBDVBV5
 SUBDIRS += \
diff --git a/lib/libv4l-codecparsers/Makefile.am b/lib/libv4l-codecparsers/Makefile.am
new file mode 100644
index 0000000..a9d6c8b
--- /dev/null
+++ b/lib/libv4l-codecparsers/Makefile.am
@@ -0,0 +1,9 @@
+if WITH_V4L_PLUGINS
+libv4l2plugin_LTLIBRARIES = libv4l-codecparsers.la
+endif
+
+libv4l_codecparsers_la_SOURCES = libv4l-cparsers.c libv4l-cparsers.h
+
+libv4l_codecparsers_la_CPPFLAGS = $(CFLAG_VISIBILITY) -I$(top_srcdir)/lib/libv4l2/ -I$(top_srcdir)/lib/libv4lconvert/
+libv4l_codecparsers_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lpthread
+libv4l_codecparsers_la_LIBADD = ../libv4l2/libv4l2.la
diff --git a/lib/libv4l-codecparsers/libv4l-codecparsers.pc.in b/lib/libv4l-codecparsers/libv4l-codecparsers.pc.in
new file mode 100644
index 0000000..ea367ee
--- /dev/null
+++ b/lib/libv4l-codecparsers/libv4l-codecparsers.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+Name: libv4l-codecparsers
+Description: v4l2 library to parse video bitstream, needed by stateless video decoders
+Version: @PACKAGE_VERSION@
+Requires.private: libv4l-gst
+Libs: -L${libdir} -lv4l2
+Libs.private: -lpthread
+Cflags: -I${includedir}
diff --git a/lib/libv4l-codecparsers/libv4l-cparsers.c b/lib/libv4l-codecparsers/libv4l-cparsers.c
new file mode 100644
index 0000000..af59f50
--- /dev/null
+++ b/lib/libv4l-codecparsers/libv4l-cparsers.c
@@ -0,0 +1,461 @@
+/*
+ * libv4l-cparsers.c
+ *
+ * Copyright (C) STMicroelectronics SA 2017
+ * Authors: Hugues Fruchet <hugues.fruchet@st.com>
+ *          Tifaine Inguere <tifaine.inguere@st.com>
+ *          for STMicroelectronics.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "libv4l2.h"
+#include "libv4l2-priv.h"
+#include "libv4l-plugin.h"
+#include "libv4lsyscall-priv.h"
+
+#include "libv4l-cparsers.h"
+
+#if HAVE_VISIBILITY
+#define PLUGIN_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define PLUGIN_PUBLIC
+#endif
+
+/* available parsers */
+const struct meta_parser *parsers[] = {
+};
+
+static void *plugin_init(int fd)
+{
+	struct cparsers_plugin *cparsers = NULL;
+	struct v4l2_capability cap;
+	int ret;
+	unsigned int i;
+	struct v4l2_fmtdesc fmt;
+	bool found = false;
+
+	/* check if device needs cparsers plugin */
+	memset(&cap, 0, sizeof(cap));
+	ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
+	if (ret)
+		return NULL;
+
+	if (!(cap.capabilities & V4L2_CAP_VIDEO_M2M))
+		return NULL;
+
+	memset(&fmt, 0, sizeof(fmt));
+	fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	while (SYS_IOCTL(fd, VIDIOC_ENUM_FMT, &fmt) >= 0) {
+		for (i = 0; i < (sizeof(parsers) / sizeof(parsers[0])); i++) {
+			if (parsers[i]->parsedformat == fmt.pixelformat) {
+				V4L2_LOG("%s: %s device matches %s parser for conversion %4.4s=>%4.4s(%s)\n",
+					 __func__, cap.driver, parsers[i]->name,
+					 (char *)&parsers[i]->streamformat,
+					 (char *)&fmt.pixelformat,
+					 fmt.description);
+				found = true;
+				break;
+			}
+		}
+		fmt.index++;
+	}
+
+	if (!found)
+		return NULL;
+
+	V4L2_LOG("%s: %s device needs libv4l-codecparsers plugin\n",
+		 __func__, cap.driver);
+
+	/* allocate and initialize private data */
+	cparsers = calloc(1, sizeof(struct cparsers_plugin));
+	if (!cparsers) {
+		V4L2_LOG_ERR("%s: couldn't allocate memory\n", __func__);
+		return NULL;
+	}
+
+	/* store driver name (debug purpose) */
+	memcpy(cparsers->driver_name, cap.driver, sizeof(cparsers->driver_name));
+
+	return cparsers;
+}
+
+static void plugin_close(void *dev_ops_priv)
+{
+	struct cparsers_plugin *cparsers = dev_ops_priv;
+	unsigned int i, j;
+
+	if (!cparsers)
+		return;
+
+	if (!cparsers->aus) {
+		free(cparsers);
+		return;
+	}
+
+	for (i = 0; i < cparsers->nb_of_aus; i++) {
+		struct cparsers_au *au = &cparsers->aus[i];
+
+		/* unmap AU */
+		if (au->addr)
+			SYS_MUNMAP(au->addr, au->size);
+
+		/* free metadata */
+		for (j = 0; j < au->nb_of_metas; j++)
+			if (au->metas_store[j].ptr)
+				free(au->metas_store[j].ptr);
+	}
+
+	free(cparsers->aus);
+	free(cparsers);
+}
+
+static int enum_fmt(struct cparsers_plugin *cparsers, int fd,
+		    unsigned long int cmd, struct v4l2_fmtdesc *fmtdesc)
+{
+	unsigned int i;
+	int ret = 0;
+	__u32 driver_format;
+
+	if (!fmtdesc)
+		return -EINVAL;
+
+	ret = SYS_IOCTL(fd, cmd, fmtdesc);
+	if (ret)
+		return ret;
+
+	if (fmtdesc->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return 0;
+
+	/*
+	 * check if driver enumerate a parsers' supported
+	 * pixel format, in that case override with stream
+	 * format so that conversion is transparent for user
+	 */
+	driver_format = fmtdesc->pixelformat;
+	for (i = 0; i < (sizeof(parsers) / sizeof(parsers[0])); i++) {
+		if (parsers[i]->parsedformat == driver_format) {
+			V4L2_LOG("%s: %s parser available, override format %4.4s with %4.4s\n",
+				 __func__, parsers[i]->name,
+				 (char *)&driver_format,
+				 (char *)&parsers[i]->streamformat);
+			fmtdesc->pixelformat = parsers[i]->streamformat;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int try_fmt(struct cparsers_plugin *cparsers, int fd,
+		   unsigned long int cmd, struct v4l2_format *format)
+{
+	unsigned int i;
+	int ret = 0;
+	__u32 requested_format;
+
+	if (!format)
+		return -EINVAL;
+
+	/*
+	 * check if user request for a parsers' supported
+	 * pixel format, in that case override with parsed
+	 * format supported by driver
+	 */
+	requested_format = format->fmt.pix.pixelformat;
+	if (format->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		for (i = 0; i < (sizeof(parsers) / sizeof(parsers[0])); i++) {
+			if (parsers[i]->streamformat == requested_format) {
+				V4L2_LOG("%s: %s parser available, override format %4.4s with %4.4s\n",
+					 __func__, parsers[i]->name,
+					 (char *)&requested_format,
+					 (char *)&parsers[i]->parsedformat);
+				format->fmt.pix.pixelformat = parsers[i]->parsedformat;
+				break;
+			}
+		}
+
+	ret = SYS_IOCTL(fd, cmd, format);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int g_fmt(struct cparsers_plugin *cparsers, int fd,
+		 unsigned long int cmd, struct v4l2_format *format)
+{
+	unsigned int i;
+	int ret = 0;
+	__u32 driver_format;
+
+	if (!format)
+		return -EINVAL;
+
+	ret = SYS_IOCTL(fd, cmd, format);
+	if (ret)
+		return ret;
+
+	driver_format = format->fmt.pix.pixelformat;
+
+	/*
+	 * check if driver returns a parsers' supported
+	 * pixel format, in that case override with stream
+	 * format so that conversion is transparent for user
+	 */
+	if (format->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		for (i = 0; i < (sizeof(parsers) / sizeof(parsers[0])); i++) {
+			if (parsers[i]->parsedformat == driver_format) {
+				V4L2_LOG("%s: %s parser available, override format %4.4s with %4.4s\n",
+					 __func__, parsers[i]->name,
+					 (char *)&driver_format,
+					 (char *)&parsers[i]->streamformat);
+				format->fmt.pix.pixelformat = parsers[i]->streamformat;
+				break;
+			}
+		}
+
+	return ret;
+}
+
+static int s_fmt(struct cparsers_plugin *cparsers, int fd,
+		 unsigned long int cmd, struct v4l2_format *format)
+{
+	unsigned int i;
+	int ret = 0;
+	__u32 requested_format;
+	bool parser_enabled = false;
+
+	if (!format)
+		return -EINVAL;
+
+	/*
+	 * check if user request for a parsers' supported
+	 * pixel format, in that case override with parsed
+	 * format supported by driver
+	 */
+	requested_format = format->fmt.pix.pixelformat;
+	if (format->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		for (i = 0; i < (sizeof(parsers) / sizeof(parsers[0])); i++) {
+			if (parsers[i]->streamformat == requested_format) {
+				V4L2_LOG("%s: %s parser available, override format %4.4s with %4.4s\n",
+					 __func__, parsers[i]->name,
+					 (char *)&requested_format,
+					 (char *)&parsers[i]->parsedformat);
+				format->fmt.pix.pixelformat = parsers[i]->parsedformat;
+				parser_enabled = true;
+				break;
+			}
+		}
+
+	ret = SYS_IOCTL(fd, cmd, format);
+	if (ret)
+		return ret;
+
+	if (!parser_enabled)
+		return ret;
+
+	/*
+	 * we have now a parser candidate and
+	 * S_FMT is successful on driver side,
+	 * let's selects this parser for this instance
+	 */
+	cparsers->parser = parsers[i];
+	/* override format, so that conversion is transparent for user */
+	format->fmt.pix.pixelformat = requested_format;
+
+	V4L2_LOG("%s: %s parser is now selected for device %s\n",
+		 __func__, cparsers->parser->name, cparsers->driver_name);
+
+	return ret;
+}
+
+static int reqbufs(struct cparsers_plugin *cparsers, int fd,
+		   unsigned long int cmd,
+		   struct v4l2_requestbuffers *requestbuffers)
+{
+	int ret;
+
+	if (!requestbuffers)
+		return -EINVAL;
+
+	ret = SYS_IOCTL(fd, cmd, requestbuffers);
+	if (ret)
+		return ret;
+
+	if (cparsers->parser &&
+	    (requestbuffers->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) &&
+	    (requestbuffers->count > 0)) {
+		/* intercept REQBUFS(OUTPUT) to know the nb of buffers to mmap */
+
+		/* allocates the set of buffer info */
+		cparsers->aus =
+		    calloc(requestbuffers->count,
+			   sizeof(struct cparsers_au));
+
+		cparsers->nb_of_aus = requestbuffers->count;
+	}
+
+	return ret;
+}
+
+static int querybuf(struct cparsers_plugin *cparsers, int fd,
+		    unsigned long int cmd, struct v4l2_buffer *buffer)
+{
+	int ret;
+	const struct meta_parser *parser = cparsers->parser;
+	unsigned int i;
+
+	if (!buffer)
+		return -EINVAL;
+
+	ret = SYS_IOCTL(fd, cmd, buffer);
+	if (ret)
+		return ret;
+
+	if (parser &&
+	    (buffer->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) &&
+	    (buffer->length > 0)) {
+		/* intercept QUERYBUF(OUTPUT) to mmap access unit & allocate metadata */
+
+		struct cparsers_au *au =
+		    &cparsers->aus[buffer->index];
+		void *vaddr;
+
+		/* user stream buffer memory mapping */
+		au->size = buffer->length;
+		vaddr = (void *)SYS_MMAP(NULL, buffer->length,
+					 PROT_READ | PROT_WRITE, MAP_SHARED, fd,
+					 buffer->m.offset);
+		if (vaddr == MAP_FAILED) {
+			V4L2_LOG_ERR("%s: failed to map AU\n", __func__);
+			return -EINVAL;
+		}
+		au->addr = vaddr;
+
+		au->nb_of_metas = parser->nb_of_metas;
+		if (au->nb_of_metas > CPARSERS_MAX_METAS) {
+			V4L2_LOG_ERR("%s: not enough room for metas (%d > %d), please increase CPARSERS_MAX_METAS\n",
+				     __func__,
+				     au->nb_of_metas,
+				     CPARSERS_MAX_METAS);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < au->nb_of_metas; i++) {
+			au->metas_store[i] = parser->metas_store[i];
+			/* allocate the set of metadata */
+			vaddr = calloc(1, au->metas_store[i].size);
+			if (!vaddr) {
+				V4L2_LOG_ERR("%s: couldn't allocate metadata memory plugin\n", __func__);
+				return -ENOMEM;
+			}
+			au->metas_store[i].ptr = vaddr;
+		}
+	}
+
+	return ret;
+}
+
+static int qbuf(struct cparsers_plugin *cparsers, int fd, unsigned long int cmd,
+		struct v4l2_buffer *buffer)
+{
+	struct v4l2_ext_controls ctrls;
+	int ret = 0;
+	unsigned int found = 0;
+	const struct meta_parser *parser = cparsers->parser;
+	unsigned int nb_of_metas = 0;
+	struct v4l2_ext_control metas[CPARSERS_MAX_METAS];
+
+	if (!buffer)
+		return -EINVAL;
+
+	if (parser &&
+	    (buffer->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) &&
+	    (buffer->bytesused > 0) &&
+	    cparsers->aus &&
+	    (buffer->index < cparsers->nb_of_aus)) {
+		struct cparsers_au *au = &cparsers->aus[buffer->index];
+
+		au->bytesused = buffer->bytesused;
+		nb_of_metas = 0;
+		memset(metas, 0, sizeof(metas));
+		found = parser->parse_metas(au, metas, &nb_of_metas);
+		if (!found) {
+			V4L2_LOG_WARN("%s: no header found within %d bytes input stream\n",
+				      __func__, au->bytesused);
+			return 0;
+		}
+
+		/* call CTRL with metas */
+		memset(&ctrls, 0, sizeof(ctrls));
+		ctrls.controls = metas;
+		ctrls.count = nb_of_metas;
+
+		ret = SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
+		if (ret)
+			return ret;
+	}
+
+	/* call QBUF */
+	ret = SYS_IOCTL(fd, cmd, buffer);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int plugin_ioctl(void *dev_ops_priv, int fd,
+			unsigned long int cmd, void *arg)
+{
+	struct cparsers_plugin *cparsers = dev_ops_priv;
+
+	switch (cmd) {
+	case VIDIOC_ENUM_FMT:
+		return enum_fmt(cparsers, fd, cmd, arg);
+	case VIDIOC_TRY_FMT:
+		return try_fmt(cparsers, fd, cmd, arg);
+	case VIDIOC_G_FMT:
+		return g_fmt(cparsers, fd, cmd, arg);
+	case VIDIOC_S_FMT:
+		return s_fmt(cparsers, fd, cmd, arg);
+	case VIDIOC_REQBUFS:
+		return reqbufs(cparsers, fd, cmd, arg);
+	case VIDIOC_QUERYBUF:
+		return querybuf(cparsers, fd, cmd, arg);
+	case VIDIOC_QBUF:
+		return qbuf(cparsers, fd, cmd, arg);
+	default:
+		return SYS_IOCTL(fd, cmd, arg);
+	}
+}
+
+PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
+	.init = &plugin_init,
+	.close = &plugin_close,
+	.ioctl = &plugin_ioctl,
+};
+
diff --git a/lib/libv4l-codecparsers/libv4l-cparsers.h b/lib/libv4l-codecparsers/libv4l-cparsers.h
new file mode 100644
index 0000000..3f0d7dd
--- /dev/null
+++ b/lib/libv4l-codecparsers/libv4l-cparsers.h
@@ -0,0 +1,101 @@
+/*
+ * libv4l-cparsers.h
+ *
+ * Copyright (C) STMicroelectronics SA 2017
+ * Authors: Hugues Fruchet <hugues.fruchet@st.com>
+ *          Tifaine Inguere <tifaine.inguere@st.com>
+ *          for STMicroelectronics.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
+ */
+
+#ifndef LIBV4L_CPARSERS_H
+#define LIBV4L_CPARSERS_H
+
+#include <stdio.h>
+#include <linux/videodev2.h>
+
+#define CPARSERS_MAX_METAS 10
+
+/*
+ * struct cparsers_au - access unit structure, associating
+ * a single compressed video bitstream chunk with its possible
+ * parsing metadata.
+ *
+ * @addr:		virtual address of the access unit data
+ * @size:		allocated size in bytes of the access unit data
+ * @bytesused:		size in bytes of the valid data within the access unit
+ * @metas_store:	set of all possible metadata controls
+ *			that can be encountered in this access unit
+ *			with their control structure allocated
+ *			in "ptr" field.
+ * @nb_of_metas:	number of meta in store
+ */
+struct cparsers_au {
+	void *addr;
+	unsigned int size;
+	unsigned int bytesused;
+	struct v4l2_ext_control metas_store[CPARSERS_MAX_METAS];
+	unsigned int nb_of_metas;
+};
+
+/*
+ * struct meta_parser - parser structure, one per parser instance
+ *
+ * @name:		name of parser
+ * @streamformat:	compressed format of input video stream
+ * @parsedformat:	parsed compressed format output by parser
+ * @metas_store:	set of meta controls supported by this parser
+ *			(control identifier / control structure size)
+ * @nb_of_metas:	number of meta in store
+ */
+struct meta_parser {
+	const char *name;
+	__u32 streamformat;
+	__u32 parsedformat;
+	const struct v4l2_ext_control *metas_store;
+	unsigned int nb_of_metas;
+
+	/*
+	 * parse_metas() - parse the given access unit and output
+	 * the associated set of metadata.
+	 *
+	 * @au:		(in) access unit to parse
+	 * @metas:	(in/out) set of parsed metadata actually
+	 *		encountered after parsing the input access unit.
+	 * @nb_of_metas:(in/out) number of metadata parsed
+	 */
+	unsigned int (*parse_metas)(struct cparsers_au *au,
+				    struct v4l2_ext_control *metas,
+				    unsigned int *nb_of_metas);
+};
+
+/*
+ * struct cparsers_plugin - plugin structure, one per plugin instance
+ *
+ * @driver_name: keep track of driver name which needs parser
+ * @parser: the parser backend wich decodes the metadata from stream
+ * @aus: set of au struct
+ * @nb_of_aus: number of au created by the ioctl command reqbufs
+ */
+struct cparsers_plugin {
+	__u8 driver_name[16];
+	const struct meta_parser *parser;
+	struct cparsers_au *aus;
+	unsigned int nb_of_aus;
+};
+
+#endif /* LIBV4L_CPARSERS_H */
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser
  2017-04-28 15:02 [PATCH v2 0/3] Add a libv4l plugin for video bitstream parsing Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 1/3] v4l-utils: sync with kernel (parsed MPEG-2 support) Hugues Fruchet
  2017-04-28 15:02 ` [PATCH v2 2/3] add libv4l-codecparsers plugin for video bitstream parsing Hugues Fruchet
@ 2017-04-28 15:02 ` Hugues Fruchet
  2017-05-01 17:37   ` Nicolas Dufresne
  2 siblings, 1 reply; 6+ messages in thread
From: Hugues Fruchet @ 2017-04-28 15:02 UTC (permalink / raw)
  To: linux-media, Hans Verkuil
  Cc: Benjamin Gaignard, Hugues Fruchet, Jean-Christophe Trotin

Add the mpeg2 codecparser backend glue which will
call the GStreamer parsing functions.

Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
 configure.ac                                    |  21 ++
 lib/libv4l-codecparsers/Makefile.am             |  14 +-
 lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c | 375 ++++++++++++++++++++++++
 lib/libv4l-codecparsers/libv4l-cparsers.c       |   4 +
 4 files changed, 413 insertions(+), 1 deletion(-)
 create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c

diff --git a/configure.ac b/configure.ac
index 9ce7392..ce43f18 100644
--- a/configure.ac
+++ b/configure.ac
@@ -273,6 +273,25 @@ fi
 
 AC_SUBST([JPEG_LIBS])
 
+# Check for GStreamer codecparsers
+
+gst_codecparsers_pkgconfig=false
+PKG_CHECK_MODULES([GST], [gstreamer-1.0 >= 1.8.0], [gst_pkgconfig=true], [gst_pkgconfig=false])
+if test "x$gst_pkgconfig" = "xfalse"; then
+   AC_MSG_WARN(GStreamer library is not available)
+else
+   PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-1.0 >= 1.8.0], [gst_base_pkgconfig=true], [gst_base_pkgconfig=false])
+   if test "x$gst_base_pkgconfig" = "xfalse"; then
+      AC_MSG_WARN(GStreamer base library is not available)
+   else
+      PKG_CHECK_MODULES(GST_CODEC_PARSERS, [gstreamer-codecparsers-1.0 >= 1.8.0], [gst_codecparsers_pkgconfig=true], [gst_codecparsers_pkgconfig=false])
+      if test "x$gst_codecparsers_pkgconfig" = "xfalse"; then
+         AC_MSG_WARN(GStreamer codecparser library is not available)
+      fi
+   fi
+fi
+AM_CONDITIONAL([HAVE_GST_CODEC_PARSERS], [test x$gst_codecparsers_pkgconfig = xtrue])
+
 # Check for pthread
 
 AS_IF([test x$enable_shared != xno],
@@ -477,6 +496,7 @@ AM_COND_IF([WITH_V4L2_CTL_LIBV4L], [USE_V4L2_CTL="yes"], [USE_V4L2_CTL="no"])
 AM_COND_IF([WITH_V4L2_CTL_STREAM_TO], [USE_V4L2_CTL="yes"], [USE_V4L2_CTL="no"])
 AM_COND_IF([WITH_V4L2_COMPLIANCE_LIBV4L], [USE_V4L2_COMPLIANCE="yes"], [USE_V4L2_COMPLIANCE="no"])
 AS_IF([test "x$alsa_pkgconfig" = "xtrue"], [USE_ALSA="yes"], [USE_ALSA="no"])
+AS_IF([test "x$gst_codecparsers_pkgconfig" = "xtrue"], [USE_GST_CODECPARSERS="yes"], [USE_GST_CODECPARSERS="no"])
 
 AC_OUTPUT
 
@@ -497,6 +517,7 @@ compile time options summary
     pthread             : $have_pthread
     QT version          : $QT_VERSION
     ALSA support        : $USE_ALSA
+    GST codecparsers    : $USE_GST_CODECPARSERS
 
     build dynamic libs  : $enable_shared
     build static libs   : $enable_static
diff --git a/lib/libv4l-codecparsers/Makefile.am b/lib/libv4l-codecparsers/Makefile.am
index a9d6c8b..61f4730 100644
--- a/lib/libv4l-codecparsers/Makefile.am
+++ b/lib/libv4l-codecparsers/Makefile.am
@@ -1,9 +1,21 @@
 if WITH_V4L_PLUGINS
+if HAVE_GST_CODEC_PARSERS
+
 libv4l2plugin_LTLIBRARIES = libv4l-codecparsers.la
-endif
 
 libv4l_codecparsers_la_SOURCES = libv4l-cparsers.c libv4l-cparsers.h
 
 libv4l_codecparsers_la_CPPFLAGS = $(CFLAG_VISIBILITY) -I$(top_srcdir)/lib/libv4l2/ -I$(top_srcdir)/lib/libv4lconvert/
 libv4l_codecparsers_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lpthread
 libv4l_codecparsers_la_LIBADD = ../libv4l2/libv4l2.la
+
+# GStreamer codecparsers library
+libv4l_codecparsers_la_CFLAGS = $(GST_CFLAGS) -DGST_USE_UNSTABLE_API
+libv4l_codecparsers_la_LDFLAGS += $(GST_LIB_LDFLAGS)
+libv4l_codecparsers_la_LIBADD += $(GLIB_LIBS) $(GST_LIBS) $(GST_BASE_LIBS) $(GST_CODEC_PARSERS_LIBS) $(NULL)
+
+# MPEG-2 parser back-end
+libv4l_codecparsers_la_SOURCES += libv4l-cparsers-mpeg2.c
+
+endif
+endif
diff --git a/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c b/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
new file mode 100644
index 0000000..3456b73
--- /dev/null
+++ b/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
@@ -0,0 +1,375 @@
+/*
+ * libv4l-cparsers-mpeg2.c
+ *
+ * Copyright (C) STMicroelectronics SA 2017
+ * Authors: Hugues Fruchet <hugues.fruchet@st.com>
+ *          Tifaine Inguere <tifaine.inguere@st.com>
+ *          for STMicroelectronics.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "libv4l2.h"
+#include "libv4l2-priv.h"
+#include "libv4l-cparsers.h"
+
+#include <gst/codecparsers/gstmpegvideoparser.h>
+#include <gst/base/gstbitreader.h>
+
+/*
+ * parsing metadata ids and their associated control ids.
+ * keep in sync both enum and array, this is used to index metas[<meta id>]
+ */
+enum mpeg2_meta_id {
+	SEQ_HDR,
+	SEQ_EXT,
+	SEQ_DISPLAY_EXT,
+	SEQ_MATRIX_EXT,
+	PIC_HDR,
+	PIC_HDR1,/* 2nd field decoding of interlaced stream */
+	PIC_EXT,
+	PIC_EXT1,/* 2nd field decoding of interlaced stream */
+};
+
+static const struct v4l2_ext_control mpeg2_metas_store[] = {
+	{
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_HDR,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_hdr),
+	},
+	{
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_EXT,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_ext),
+	},
+	{
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_DISPLAY_EXT,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_display_ext),
+	},
+	{
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_MATRIX_EXT,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_matrix_ext),
+	},
+	{
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_hdr),
+	},
+	{/* 2nd field decoding of interlaced stream */
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_hdr),
+	},
+	{
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_ext),
+	},
+	{/* 2nd field decoding of interlaced stream */
+	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT,
+	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_ext),
+	},
+};
+
+guint8 get_extension_code(const GstMpegVideoPacket *packet)
+{
+	GstBitReader br;
+	unsigned char extension_code;
+
+	gst_bit_reader_init(&br, &packet->data[packet->offset], packet->size);
+	if (!gst_bit_reader_get_bits_uint8(&br, &extension_code, 4)) {
+		V4L2_LOG_ERR("failed to read extension code");
+		return GST_MPEG_VIDEO_PACKET_NONE;
+	}
+
+	return extension_code;
+}
+
+unsigned int mpeg2_parse_metas(struct cparsers_au *au,
+			       struct v4l2_ext_control *metas,
+			       unsigned int *nb_of_metas)
+{
+	unsigned char extension_code;
+	bool startcode_found = false;
+	bool meta_found = false;
+	GstMpegVideoPacket packet_data;
+	unsigned int slice_index = 0;
+	GstMpegVideoSequenceHdr gst_seq_hdr;
+	GstMpegVideoSequenceExt gst_seq_ext;
+	GstMpegVideoSequenceDisplayExt gst_seq_display_ext;
+	GstMpegVideoQuantMatrixExt gst_seq_matrix_ext;
+	GstMpegVideoPictureHdr gst_pic_hdr;
+	GstMpegVideoPictureExt gst_pic_ext;
+	struct v4l2_mpeg_video_mpeg2_seq_hdr *seq_hdr;
+	struct v4l2_mpeg_video_mpeg2_seq_ext *seq_ext;
+	struct v4l2_mpeg_video_mpeg2_seq_display_ext *seq_display_ext;
+	struct v4l2_mpeg_video_mpeg2_seq_matrix_ext *seq_matrix_ext;
+	struct v4l2_mpeg_video_mpeg2_pic_hdr *pic_hdrs[2];
+	struct v4l2_mpeg_video_mpeg2_pic_ext *pic_exts[2];
+
+	if ((!au->addr) || (!au->bytesused) || (!au->metas_store) || (!metas)) {
+		V4L2_LOG_ERR("%s: invalid input: au->addr=%p, au->bytesused=%d, au->metas_store=%p, metas=%p\n",
+			     __func__, au->addr, au->bytesused, au->metas_store, metas);
+		return 0;
+	}
+
+	seq_hdr = au->metas_store[SEQ_HDR].ptr;
+	seq_ext = au->metas_store[SEQ_EXT].ptr;
+	seq_display_ext = au->metas_store[SEQ_DISPLAY_EXT].ptr;
+	seq_matrix_ext = au->metas_store[SEQ_MATRIX_EXT].ptr;
+	pic_hdrs[0] = au->metas_store[PIC_HDR].ptr;
+	pic_hdrs[1] = au->metas_store[PIC_HDR + 1].ptr;
+	pic_exts[0] = au->metas_store[PIC_EXT].ptr;
+	pic_exts[1] = au->metas_store[PIC_EXT + 1].ptr;
+
+	memset(&packet_data, 0, sizeof(packet_data));
+
+	while (((packet_data.offset + 4) < au->bytesused)) {
+		V4L2_LOG("%s: parsing input from offset=%d\n", __func__,
+			 packet_data.offset);
+		startcode_found = gst_mpeg_video_parse(&packet_data, au->addr, au->bytesused, packet_data.offset);
+		if (!startcode_found) {
+			V4L2_LOG("%s: parsing is over\n", __func__);
+			break;
+		}
+		/*
+		 * gst_mpeg_video_parse compute packet size by searching for next
+		 * startcode, but if next startcode is not found (end of access unit),
+		 * packet size is set to -1. We fix this here and set packet size
+		 * to remaining size in this case.
+		 */
+		if (packet_data.size < 0)
+			packet_data.size = au->bytesused - packet_data.offset;
+
+		V4L2_LOG("%s: found startcode 0x%02x @offset=%u, size=%d\n",
+			 __func__, packet_data.type, packet_data.offset - 4, packet_data.size);
+
+		switch (packet_data.type) {
+		case GST_MPEG_VIDEO_PACKET_PICTURE:
+			if (gst_mpeg_video_packet_parse_picture_header
+			    (&packet_data, &gst_pic_hdr)) {
+				struct v4l2_mpeg_video_mpeg2_pic_hdr *pic_hdr = pic_hdrs[slice_index];
+
+				metas[(*nb_of_metas)++] = au->metas_store[PIC_HDR + slice_index];
+
+				memset(pic_hdr, 0, sizeof(*pic_hdr));
+				pic_hdr->tsn = gst_pic_hdr.tsn;
+				pic_hdr->pic_type = gst_pic_hdr.pic_type;
+				pic_hdr->full_pel_forward_vector = gst_pic_hdr.full_pel_forward_vector;
+				pic_hdr->full_pel_backward_vector = gst_pic_hdr.full_pel_backward_vector;
+				memcpy(&pic_hdr->f_code, &gst_pic_hdr.f_code, sizeof(pic_hdr->f_code));
+
+				V4L2_LOG("%s: PICTURE HEADER\n", __func__);
+				meta_found = true;
+			}
+			break;
+
+		case GST_MPEG_VIDEO_PACKET_SLICE_MIN:
+			/* New slice encountered */
+			if (slice_index > 1) {
+				V4L2_LOG_ERR("%s: more than 2 slices detected @offset=%d, ignoring this slice...\n",
+					     __func__, packet_data.offset);
+				break;
+			}
+			/* store its offset, including startcode */
+			pic_hdrs[slice_index]->offset = packet_data.offset - 4;
+			slice_index++;
+
+			V4L2_LOG("%s: START OF SLICE @ offset=%d\n", __func__, packet_data.offset);
+			meta_found = true;
+			goto done;
+
+			break;
+
+		case GST_MPEG_VIDEO_PACKET_USER_DATA:
+			/* not implemented : do nothing */
+			V4L2_LOG("%s: USER DATA, not implemented\n", __func__);
+			break;
+
+		case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+			if (gst_mpeg_video_packet_parse_sequence_header
+			    (&packet_data, &gst_seq_hdr)) {
+				metas[(*nb_of_metas)++] = au->metas_store[SEQ_HDR];
+
+				memset(seq_hdr, 0, sizeof(*seq_hdr));
+				seq_hdr->width = gst_seq_hdr.width;
+				seq_hdr->height = gst_seq_hdr.height;
+				seq_hdr->load_intra_quantiser_matrix = 1;
+				memcpy(&seq_hdr->intra_quantiser_matrix,
+				       &gst_seq_hdr.intra_quantizer_matrix,
+				       sizeof(seq_hdr->intra_quantiser_matrix));
+				seq_hdr->load_non_intra_quantiser_matrix = 1;
+				memcpy(&seq_hdr->non_intra_quantiser_matrix,
+				       &gst_seq_hdr.non_intra_quantizer_matrix,
+				       sizeof(seq_hdr->non_intra_quantiser_matrix));
+
+				V4L2_LOG("%s: SEQUENCE HEADER\n", __func__);
+				meta_found = true;
+			}
+			break;
+
+		case GST_MPEG_VIDEO_PACKET_EXTENSION:
+			extension_code = get_extension_code(&packet_data);
+			V4L2_LOG("%s: extension code=0x%02x  \n", __func__, extension_code);
+
+			switch (extension_code) {
+			case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
+				if (gst_mpeg_video_packet_parse_sequence_extension
+				    (&packet_data, &gst_seq_ext)) {
+					metas[(*nb_of_metas)++] = au->metas_store[SEQ_EXT];
+
+					memset(seq_ext, 0, sizeof(*seq_ext));
+					seq_ext->profile = gst_seq_ext.profile;
+					seq_ext->level = gst_seq_ext.level;
+					seq_ext->progressive = gst_seq_ext.progressive;
+					seq_ext->chroma_format = gst_seq_ext.chroma_format;
+					seq_ext->horiz_size_ext = gst_seq_ext.horiz_size_ext;
+					seq_ext->vert_size_ext = gst_seq_ext.vert_size_ext;
+
+					V4L2_LOG("%s: SEQUENCE EXTENSION\n", __func__);
+					meta_found = true;
+				}
+				break;
+
+			case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
+				if (gst_mpeg_video_packet_parse_sequence_display_extension
+				    (&packet_data, &gst_seq_display_ext)) {
+					metas[(*nb_of_metas)++] = au->metas_store[SEQ_DISPLAY_EXT];
+
+					memset(seq_display_ext, 0, sizeof(*seq_display_ext));
+					seq_display_ext->video_format = gst_seq_display_ext.video_format;
+					seq_display_ext->colour_description_flag = gst_seq_display_ext.colour_description_flag;
+					seq_display_ext->colour_primaries = gst_seq_display_ext.colour_primaries;
+					seq_display_ext->transfer_characteristics = gst_seq_display_ext.transfer_characteristics;
+					seq_display_ext->matrix_coefficients = gst_seq_display_ext.matrix_coefficients;
+					seq_display_ext->display_horizontal_size = gst_seq_display_ext.display_horizontal_size;
+					seq_display_ext->display_vertical_size = gst_seq_display_ext.display_vertical_size;
+
+					V4L2_LOG("%s: SEQUENCE DISPLAY EXTENSION\n", __func__);
+					meta_found = true;
+				}
+				break;
+
+			case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
+				if (gst_mpeg_video_packet_parse_quant_matrix_extension
+				    (&packet_data, &gst_seq_matrix_ext)) {
+					metas[(*nb_of_metas)++] = au->metas_store[SEQ_DISPLAY_EXT];
+
+					memset(seq_matrix_ext, 0, sizeof(*seq_matrix_ext));
+					seq_matrix_ext->load_intra_quantiser_matrix =
+						gst_seq_matrix_ext.load_intra_quantiser_matrix;
+					memcpy(&seq_matrix_ext->intra_quantiser_matrix,
+					       &gst_seq_matrix_ext.intra_quantiser_matrix,
+					       sizeof(seq_matrix_ext->intra_quantiser_matrix));
+					seq_matrix_ext->load_non_intra_quantiser_matrix =
+						gst_seq_matrix_ext.load_non_intra_quantiser_matrix;
+					memcpy(&seq_matrix_ext->non_intra_quantiser_matrix,
+					       &gst_seq_matrix_ext.non_intra_quantiser_matrix,
+					       sizeof(seq_matrix_ext->non_intra_quantiser_matrix));
+					seq_matrix_ext->load_chroma_intra_quantiser_matrix =
+						gst_seq_matrix_ext.load_chroma_intra_quantiser_matrix;
+					memcpy(&seq_matrix_ext->chroma_intra_quantiser_matrix,
+					       &gst_seq_matrix_ext.chroma_intra_quantiser_matrix,
+					       sizeof(seq_matrix_ext->chroma_intra_quantiser_matrix));
+					seq_matrix_ext->load_chroma_non_intra_quantiser_matrix =
+						gst_seq_matrix_ext.load_chroma_non_intra_quantiser_matrix;
+					memcpy(&seq_matrix_ext->chroma_non_intra_quantiser_matrix,
+					       &gst_seq_matrix_ext.chroma_non_intra_quantiser_matrix,
+					       sizeof(seq_matrix_ext->chroma_non_intra_quantiser_matrix));
+
+					V4L2_LOG("%s: SEQUENCE MATRIX EXTENSION\n", __func__);
+					meta_found = true;
+				}
+				break;
+
+			case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
+				/* not implemented : do nothing */
+				V4L2_LOG("%s: SEQUENCE SCALABLE EXTENSION, not implemented\n", __func__);
+				break;
+
+			case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
+				if (gst_mpeg_video_packet_parse_picture_extension
+				    (&packet_data, &gst_pic_ext)) {
+					struct v4l2_mpeg_video_mpeg2_pic_ext *pic_ext = pic_exts[slice_index];
+
+					metas[(*nb_of_metas)++] = au->metas_store[PIC_EXT + slice_index];
+
+					memset(pic_ext, 0, sizeof(*pic_ext));
+					memcpy(&pic_ext->f_code, &gst_pic_ext.f_code, sizeof(pic_ext->f_code));
+					pic_ext->intra_dc_precision = gst_pic_ext.intra_dc_precision;
+					pic_ext->picture_structure = gst_pic_ext.picture_structure;
+					pic_ext->top_field_first = gst_pic_ext.top_field_first;
+					pic_ext->frame_pred_frame_dct = gst_pic_ext.frame_pred_frame_dct;
+					pic_ext->concealment_motion_vectors = gst_pic_ext.concealment_motion_vectors;
+					pic_ext->q_scale_type = gst_pic_ext.q_scale_type;
+					pic_ext->intra_vlc_format = gst_pic_ext.intra_vlc_format;
+					pic_ext->alternate_scan = gst_pic_ext.alternate_scan;
+					pic_ext->repeat_first_field = gst_pic_ext.repeat_first_field;
+					pic_ext->chroma_420_type = gst_pic_ext.chroma_420_type;
+					pic_ext->progressive_frame = gst_pic_ext.progressive_frame;
+					pic_ext->composite_display = gst_pic_ext.composite_display;
+					pic_ext->v_axis = gst_pic_ext.v_axis;
+					pic_ext->field_sequence = gst_pic_ext.field_sequence;
+					pic_ext->sub_carrier = gst_pic_ext.sub_carrier;
+					pic_ext->burst_amplitude = gst_pic_ext.burst_amplitude;
+					pic_ext->sub_carrier_phase = gst_pic_ext.sub_carrier_phase;
+
+					V4L2_LOG("%s: PICTURE EXTENSION, top_field_first=%d\n",
+						 __func__, pic_exts[slice_index]->top_field_first);
+					meta_found = true;
+				}
+				break;
+
+			default:
+				break;
+			}
+			break;
+
+		case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
+			V4L2_LOG("%s: END OF PACKET SEQUENCE\n", __func__);
+			break;
+
+		case GST_MPEG_VIDEO_PACKET_GOP:
+			V4L2_LOG("%s: GOP\n", __func__);
+			break;
+
+		default:
+			V4L2_LOG("%s: unknown/unsupported header %02x\n",
+				 __func__, packet_data.type);
+			break;
+		}
+	}
+
+done:
+	return meta_found;
+}
+
+const struct meta_parser mpeg2parse = {
+	.name = "mpeg2",
+	.streamformat = V4L2_PIX_FMT_MPEG2,
+	.parsedformat = V4L2_PIX_FMT_MPEG2_PARSED,
+	.nb_of_metas = sizeof(mpeg2_metas_store) / sizeof(mpeg2_metas_store[0]),
+	.metas_store = mpeg2_metas_store,
+	.parse_metas = mpeg2_parse_metas,
+};
+
+const struct meta_parser mpeg1parse = {
+	.name = "mpeg1",
+	.streamformat = V4L2_PIX_FMT_MPEG1,
+	.parsedformat = V4L2_PIX_FMT_MPEG1_PARSED,
+	.nb_of_metas = sizeof(mpeg2_metas_store) / sizeof(mpeg2_metas_store[0]),
+	.metas_store = mpeg2_metas_store,
+	.parse_metas = mpeg2_parse_metas,
+};
diff --git a/lib/libv4l-codecparsers/libv4l-cparsers.c b/lib/libv4l-codecparsers/libv4l-cparsers.c
index af59f50..4e8ae31 100644
--- a/lib/libv4l-codecparsers/libv4l-cparsers.c
+++ b/lib/libv4l-codecparsers/libv4l-cparsers.c
@@ -46,7 +46,11 @@
 #endif
 
 /* available parsers */
+extern const struct meta_parser mpeg1parse;
+extern const struct meta_parser mpeg2parse;
 const struct meta_parser *parsers[] = {
+	&mpeg1parse,
+	&mpeg2parse,
 };
 
 static void *plugin_init(int fd)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser
  2017-04-28 15:02 ` [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser Hugues Fruchet
@ 2017-05-01 17:37   ` Nicolas Dufresne
  2017-05-03  9:13     ` Hugues FRUCHET
  0 siblings, 1 reply; 6+ messages in thread
From: Nicolas Dufresne @ 2017-05-01 17:37 UTC (permalink / raw)
  To: Hugues Fruchet, linux-media, Hans Verkuil
  Cc: Benjamin Gaignard, Jean-Christophe Trotin

[-- Attachment #1: Type: text/plain, Size: 20927 bytes --]

Le vendredi 28 avril 2017 à 17:02 +0200, Hugues Fruchet a écrit :
> Add the mpeg2 codecparser backend glue which will
> call the GStreamer parsing functions.
> 
> Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
> ---
>  configure.ac                                    |  21 ++
>  lib/libv4l-codecparsers/Makefile.am             |  14 +-
>  lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c | 375
> ++++++++++++++++++++++++
>  lib/libv4l-codecparsers/libv4l-cparsers.c       |   4 +
>  4 files changed, 413 insertions(+), 1 deletion(-)
>  create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
> 
> diff --git a/configure.ac b/configure.ac
> index 9ce7392..ce43f18 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -273,6 +273,25 @@ fi
>  
>  AC_SUBST([JPEG_LIBS])
>  
> +# Check for GStreamer codecparsers
> +
> +gst_codecparsers_pkgconfig=false
> +PKG_CHECK_MODULES([GST], [gstreamer-1.0 >= 1.8.0],
> [gst_pkgconfig=true], [gst_pkgconfig=false])
> +if test "x$gst_pkgconfig" = "xfalse"; then
> +   AC_MSG_WARN(GStreamer library is not available)
> +else
> +   PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-1.0 >= 1.8.0],
> [gst_base_pkgconfig=true], [gst_base_pkgconfig=false])
> +   if test "x$gst_base_pkgconfig" = "xfalse"; then
> +      AC_MSG_WARN(GStreamer base library is not available)
> +   else
> +      PKG_CHECK_MODULES(GST_CODEC_PARSERS, [gstreamer-codecparsers-
> 1.0 >= 1.8.0], [gst_codecparsers_pkgconfig=true], 

You should only check for the codecparser library. The rest are
dependencies which will be pulled automatically by pkg-config. If for
some reason you needed multiple libs, that don't depend on each others,
notice the S in PKG_CHECK_MODULES. You can do a single invocation.

> [gst_codecparsers_pkgconfig=false])
> +      if test "x$gst_codecparsers_pkgconfig" = "xfalse"; then
> +         AC_MSG_WARN(GStreamer codecparser library is not available)
> +      fi
> +   fi
> +fi
> +AM_CONDITIONAL([HAVE_GST_CODEC_PARSERS], [test
> x$gst_codecparsers_pkgconfig = xtrue])
> +
>  # Check for pthread
>  
>  AS_IF([test x$enable_shared != xno],
> @@ -477,6 +496,7 @@ AM_COND_IF([WITH_V4L2_CTL_LIBV4L],
> [USE_V4L2_CTL="yes"], [USE_V4L2_CTL="no"])
>  AM_COND_IF([WITH_V4L2_CTL_STREAM_TO], [USE_V4L2_CTL="yes"],
> [USE_V4L2_CTL="no"])
>  AM_COND_IF([WITH_V4L2_COMPLIANCE_LIBV4L],
> [USE_V4L2_COMPLIANCE="yes"], [USE_V4L2_COMPLIANCE="no"])
>  AS_IF([test "x$alsa_pkgconfig" = "xtrue"], [USE_ALSA="yes"],
> [USE_ALSA="no"])
> +AS_IF([test "x$gst_codecparsers_pkgconfig" = "xtrue"],
> [USE_GST_CODECPARSERS="yes"], [USE_GST_CODECPARSERS="no"])
>  
>  AC_OUTPUT
>  
> @@ -497,6 +517,7 @@ compile time options summary
>      pthread             : $have_pthread
>      QT version          : $QT_VERSION
>      ALSA support        : $USE_ALSA
> +    GST codecparsers    : $USE_GST_CODECPARSERS
>  
>      build dynamic libs  : $enable_shared
>      build static libs   : $enable_static
> diff --git a/lib/libv4l-codecparsers/Makefile.am b/lib/libv4l-
> codecparsers/Makefile.am
> index a9d6c8b..61f4730 100644
> --- a/lib/libv4l-codecparsers/Makefile.am
> +++ b/lib/libv4l-codecparsers/Makefile.am
> @@ -1,9 +1,21 @@
>  if WITH_V4L_PLUGINS
> +if HAVE_GST_CODEC_PARSERS
> +
>  libv4l2plugin_LTLIBRARIES = libv4l-codecparsers.la
> -endif
>  
>  libv4l_codecparsers_la_SOURCES = libv4l-cparsers.c libv4l-cparsers.h
>  
>  libv4l_codecparsers_la_CPPFLAGS = $(CFLAG_VISIBILITY)
> -I$(top_srcdir)/lib/libv4l2/ -I$(top_srcdir)/lib/libv4lconvert/
>  libv4l_codecparsers_la_LDFLAGS = -avoid-version -module -shared
> -export-dynamic -lpthread
>  libv4l_codecparsers_la_LIBADD = ../libv4l2/libv4l2.la
> +
> +# GStreamer codecparsers library
> +libv4l_codecparsers_la_CFLAGS = $(GST_CFLAGS) -DGST_USE_UNSTABLE_API
> +libv4l_codecparsers_la_LDFLAGS += $(GST_LIB_LDFLAGS)
> +libv4l_codecparsers_la_LIBADD += $(GLIB_LIBS) $(GST_LIBS)
> $(GST_BASE_LIBS) $(GST_CODEC_PARSERS_LIBS) $(NULL)
> +
> +# MPEG-2 parser back-end
> +libv4l_codecparsers_la_SOURCES += libv4l-cparsers-mpeg2.c
> +
> +endif
> +endif
> diff --git a/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
> b/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
> new file mode 100644
> index 0000000..3456b73
> --- /dev/null
> +++ b/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
> @@ -0,0 +1,375 @@
> +/*
> + * libv4l-cparsers-mpeg2.c
> + *
> + * Copyright (C) STMicroelectronics SA 2017
> + * Authors: Hugues Fruchet <hugues.fruchet@st.com>
> + *          Tifaine Inguere <tifaine.inguere@st.com>
> + *          for STMicroelectronics.
> + *
> + * This program 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 program 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 program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston,
> MA  02110-1335  USA
> + */
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdbool.h>
> +
> +#include "libv4l2.h"
> +#include "libv4l2-priv.h"
> +#include "libv4l-cparsers.h"
> +
> +#include <gst/codecparsers/gstmpegvideoparser.h>
> +#include <gst/base/gstbitreader.h>
> +
> +/*
> + * parsing metadata ids and their associated control ids.
> + * keep in sync both enum and array, this is used to index
> metas[<meta id>]
> + */
> +enum mpeg2_meta_id {
> +	SEQ_HDR,
> +	SEQ_EXT,
> +	SEQ_DISPLAY_EXT,
> +	SEQ_MATRIX_EXT,
> +	PIC_HDR,
> +	PIC_HDR1,/* 2nd field decoding of interlaced stream */
> +	PIC_EXT,
> +	PIC_EXT1,/* 2nd field decoding of interlaced stream */
> +};
> +
> +static const struct v4l2_ext_control mpeg2_metas_store[] = {
> +	{
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_HDR,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_hdr),
> +	},
> +	{
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_EXT,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_ext),
> +	},
> +	{
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_DISPLAY_EXT,
> +	.size = sizeof(struct
> v4l2_mpeg_video_mpeg2_seq_display_ext),
> +	},
> +	{
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_MATRIX_EXT,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_matrix_ext),
> +	},
> +	{
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_hdr),
> +	},
> +	{/* 2nd field decoding of interlaced stream */
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_hdr),
> +	},
> +	{
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_ext),
> +	},
> +	{/* 2nd field decoding of interlaced stream */
> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT,
> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_ext),
> +	},
> +};
> +
> +guint8 get_extension_code(const GstMpegVideoPacket *packet)
> +{
> +	GstBitReader br;
> +	unsigned char extension_code;
> +
> +	gst_bit_reader_init(&br, &packet->data[packet->offset],
> packet->size);
> +	if (!gst_bit_reader_get_bits_uint8(&br, &extension_code, 4))
> {
> +		V4L2_LOG_ERR("failed to read extension code");
> +		return GST_MPEG_VIDEO_PACKET_NONE;
> +	}
> +
> +	return extension_code;
> +}
> +
> +unsigned int mpeg2_parse_metas(struct cparsers_au *au,
> +			       struct v4l2_ext_control *metas,
> +			       unsigned int *nb_of_metas)
> +{
> +	unsigned char extension_code;
> +	bool startcode_found = false;
> +	bool meta_found = false;
> +	GstMpegVideoPacket packet_data;
> +	unsigned int slice_index = 0;
> +	GstMpegVideoSequenceHdr gst_seq_hdr;
> +	GstMpegVideoSequenceExt gst_seq_ext;
> +	GstMpegVideoSequenceDisplayExt gst_seq_display_ext;
> +	GstMpegVideoQuantMatrixExt gst_seq_matrix_ext;
> +	GstMpegVideoPictureHdr gst_pic_hdr;
> +	GstMpegVideoPictureExt gst_pic_ext;
> +	struct v4l2_mpeg_video_mpeg2_seq_hdr *seq_hdr;
> +	struct v4l2_mpeg_video_mpeg2_seq_ext *seq_ext;
> +	struct v4l2_mpeg_video_mpeg2_seq_display_ext
> *seq_display_ext;
> +	struct v4l2_mpeg_video_mpeg2_seq_matrix_ext *seq_matrix_ext;
> +	struct v4l2_mpeg_video_mpeg2_pic_hdr *pic_hdrs[2];
> +	struct v4l2_mpeg_video_mpeg2_pic_ext *pic_exts[2];
> +
> +	if ((!au->addr) || (!au->bytesused) || (!au->metas_store) ||
> (!metas)) {
> +		V4L2_LOG_ERR("%s: invalid input: au->addr=%p, au-
> >bytesused=%d, au->metas_store=%p, metas=%p\n",
> +			     __func__, au->addr, au->bytesused, au-
> >metas_store, metas);
> +		return 0;
> +	}
> +
> +	seq_hdr = au->metas_store[SEQ_HDR].ptr;
> +	seq_ext = au->metas_store[SEQ_EXT].ptr;
> +	seq_display_ext = au->metas_store[SEQ_DISPLAY_EXT].ptr;
> +	seq_matrix_ext = au->metas_store[SEQ_MATRIX_EXT].ptr;
> +	pic_hdrs[0] = au->metas_store[PIC_HDR].ptr;
> +	pic_hdrs[1] = au->metas_store[PIC_HDR + 1].ptr;
> +	pic_exts[0] = au->metas_store[PIC_EXT].ptr;
> +	pic_exts[1] = au->metas_store[PIC_EXT + 1].ptr;
> +
> +	memset(&packet_data, 0, sizeof(packet_data));
> +
> +	while (((packet_data.offset + 4) < au->bytesused)) {
> +		V4L2_LOG("%s: parsing input from offset=%d\n",
> __func__,
> +			 packet_data.offset);
> +		startcode_found = gst_mpeg_video_parse(&packet_data,
> au->addr, au->bytesused, packet_data.offset);
> +		if (!startcode_found) {
> +			V4L2_LOG("%s: parsing is over\n", __func__);
> +			break;
> +		}
> +		/*
> +		 * gst_mpeg_video_parse compute packet size by
> searching for next
> +		 * startcode, but if next startcode is not found
> (end of access unit),
> +		 * packet size is set to -1. We fix this here and
> set packet size
> +		 * to remaining size in this case.
> +		 */
> +		if (packet_data.size < 0)
> +			packet_data.size = au->bytesused -
> packet_data.offset;
> +
> +		V4L2_LOG("%s: found startcode 0x%02x @offset=%u,
> size=%d\n",
> +			 __func__, packet_data.type,
> packet_data.offset - 4, packet_data.size);
> +
> +		switch (packet_data.type) {
> +		case GST_MPEG_VIDEO_PACKET_PICTURE:
> +			if
> (gst_mpeg_video_packet_parse_picture_header
> +			    (&packet_data, &gst_pic_hdr)) {
> +				struct v4l2_mpeg_video_mpeg2_pic_hdr
> *pic_hdr = pic_hdrs[slice_index];
> +
> +				metas[(*nb_of_metas)++] = au-
> >metas_store[PIC_HDR + slice_index];
> +
> +				memset(pic_hdr, 0,
> sizeof(*pic_hdr));
> +				pic_hdr->tsn = gst_pic_hdr.tsn;
> +				pic_hdr->pic_type =
> gst_pic_hdr.pic_type;
> +				pic_hdr->full_pel_forward_vector =
> gst_pic_hdr.full_pel_forward_vector;
> +				pic_hdr->full_pel_backward_vector =
> gst_pic_hdr.full_pel_backward_vector;
> +				memcpy(&pic_hdr->f_code,
> &gst_pic_hdr.f_code, sizeof(pic_hdr->f_code));
> +
> +				V4L2_LOG("%s: PICTURE HEADER\n",
> __func__);
> +				meta_found = true;
> +			}
> +			break;
> +
> +		case GST_MPEG_VIDEO_PACKET_SLICE_MIN:
> +			/* New slice encountered */
> +			if (slice_index > 1) {
> +				V4L2_LOG_ERR("%s: more than 2 slices
> detected @offset=%d, ignoring this slice...\n",
> +					     __func__,
> packet_data.offset);
> +				break;
> +			}
> +			/* store its offset, including startcode */
> +			pic_hdrs[slice_index]->offset =
> packet_data.offset - 4;
> +			slice_index++;
> +
> +			V4L2_LOG("%s: START OF SLICE @ offset=%d\n",
> __func__, packet_data.offset);
> +			meta_found = true;
> +			goto done;
> +
> +			break;
> +
> +		case GST_MPEG_VIDEO_PACKET_USER_DATA:
> +			/* not implemented : do nothing */
> +			V4L2_LOG("%s: USER DATA, not implemented\n",
> __func__);
> +			break;
> +
> +		case GST_MPEG_VIDEO_PACKET_SEQUENCE:
> +			if
> (gst_mpeg_video_packet_parse_sequence_header
> +			    (&packet_data, &gst_seq_hdr)) {
> +				metas[(*nb_of_metas)++] = au-
> >metas_store[SEQ_HDR];
> +
> +				memset(seq_hdr, 0,
> sizeof(*seq_hdr));
> +				seq_hdr->width = gst_seq_hdr.width;
> +				seq_hdr->height =
> gst_seq_hdr.height;
> +				seq_hdr->load_intra_quantiser_matrix 
> = 1;
> +				memcpy(&seq_hdr-
> >intra_quantiser_matrix,
> +				       &gst_seq_hdr.intra_quantizer_
> matrix,
> +				       sizeof(seq_hdr-
> >intra_quantiser_matrix));
> +				seq_hdr-
> >load_non_intra_quantiser_matrix = 1;
> +				memcpy(&seq_hdr-
> >non_intra_quantiser_matrix,
> +				       &gst_seq_hdr.non_intra_quanti
> zer_matrix,
> +				       sizeof(seq_hdr-
> >non_intra_quantiser_matrix));
> +
> +				V4L2_LOG("%s: SEQUENCE HEADER\n",
> __func__);
> +				meta_found = true;
> +			}
> +			break;
> +
> +		case GST_MPEG_VIDEO_PACKET_EXTENSION:
> +			extension_code =
> get_extension_code(&packet_data);
> +			V4L2_LOG("%s: extension code=0x%02x  \n",
> __func__, extension_code);
> +
> +			switch (extension_code) {
> +			case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
> +				if
> (gst_mpeg_video_packet_parse_sequence_extension
> +				    (&packet_data, &gst_seq_ext)) {
> +					metas[(*nb_of_metas)++] =
> au->metas_store[SEQ_EXT];
> +
> +					memset(seq_ext, 0,
> sizeof(*seq_ext));
> +					seq_ext->profile =
> gst_seq_ext.profile;
> +					seq_ext->level =
> gst_seq_ext.level;
> +					seq_ext->progressive =
> gst_seq_ext.progressive;
> +					seq_ext->chroma_format =
> gst_seq_ext.chroma_format;
> +					seq_ext->horiz_size_ext =
> gst_seq_ext.horiz_size_ext;
> +					seq_ext->vert_size_ext =
> gst_seq_ext.vert_size_ext;
> +
> +					V4L2_LOG("%s: SEQUENCE
> EXTENSION\n", __func__);
> +					meta_found = true;
> +				}
> +				break;
> +
> +			case
> GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
> +				if
> (gst_mpeg_video_packet_parse_sequence_display_extension
> +				    (&packet_data,
> &gst_seq_display_ext)) {
> +					metas[(*nb_of_metas)++] =
> au->metas_store[SEQ_DISPLAY_EXT];
> +
> +					memset(seq_display_ext, 0,
> sizeof(*seq_display_ext));
> +					seq_display_ext-
> >video_format = gst_seq_display_ext.video_format;
> +					seq_display_ext-
> >colour_description_flag =
> gst_seq_display_ext.colour_description_flag;
> +					seq_display_ext-
> >colour_primaries = gst_seq_display_ext.colour_primaries;
> +					seq_display_ext-
> >transfer_characteristics =
> gst_seq_display_ext.transfer_characteristics;
> +					seq_display_ext-
> >matrix_coefficients = gst_seq_display_ext.matrix_coefficients;
> +					seq_display_ext-
> >display_horizontal_size =
> gst_seq_display_ext.display_horizontal_size;
> +					seq_display_ext-
> >display_vertical_size = gst_seq_display_ext.display_vertical_size;
> +
> +					V4L2_LOG("%s: SEQUENCE
> DISPLAY EXTENSION\n", __func__);
> +					meta_found = true;
> +				}
> +				break;
> +
> +			case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
> +				if
> (gst_mpeg_video_packet_parse_quant_matrix_extension
> +				    (&packet_data,
> &gst_seq_matrix_ext)) {
> +					metas[(*nb_of_metas)++] =
> au->metas_store[SEQ_DISPLAY_EXT];
> +
> +					memset(seq_matrix_ext, 0,
> sizeof(*seq_matrix_ext));
> +					seq_matrix_ext-
> >load_intra_quantiser_matrix =
> +						gst_seq_matrix_ext.l
> oad_intra_quantiser_matrix;
> +					memcpy(&seq_matrix_ext-
> >intra_quantiser_matrix,
> +					       &gst_seq_matrix_ext.i
> ntra_quantiser_matrix,
> +					       sizeof(seq_matrix_ext
> ->intra_quantiser_matrix));
> +					seq_matrix_ext-
> >load_non_intra_quantiser_matrix =
> +						gst_seq_matrix_ext.l
> oad_non_intra_quantiser_matrix;
> +					memcpy(&seq_matrix_ext-
> >non_intra_quantiser_matrix,
> +					       &gst_seq_matrix_ext.n
> on_intra_quantiser_matrix,
> +					       sizeof(seq_matrix_ext
> ->non_intra_quantiser_matrix));
> +					seq_matrix_ext-
> >load_chroma_intra_quantiser_matrix =
> +						gst_seq_matrix_ext.l
> oad_chroma_intra_quantiser_matrix;
> +					memcpy(&seq_matrix_ext-
> >chroma_intra_quantiser_matrix,
> +					       &gst_seq_matrix_ext.c
> hroma_intra_quantiser_matrix,
> +					       sizeof(seq_matrix_ext
> ->chroma_intra_quantiser_matrix));
> +					seq_matrix_ext-
> >load_chroma_non_intra_quantiser_matrix =
> +						gst_seq_matrix_ext.l
> oad_chroma_non_intra_quantiser_matrix;
> +					memcpy(&seq_matrix_ext-
> >chroma_non_intra_quantiser_matrix,
> +					       &gst_seq_matrix_ext.c
> hroma_non_intra_quantiser_matrix,
> +					       sizeof(seq_matrix_ext
> ->chroma_non_intra_quantiser_matrix));
> +
> +					V4L2_LOG("%s: SEQUENCE
> MATRIX EXTENSION\n", __func__);
> +					meta_found = true;
> +				}
> +				break;
> +
> +			case
> GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
> +				/* not implemented : do nothing */
> +				V4L2_LOG("%s: SEQUENCE SCALABLE
> EXTENSION, not implemented\n", __func__);
> +				break;
> +
> +			case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
> +				if
> (gst_mpeg_video_packet_parse_picture_extension
> +				    (&packet_data, &gst_pic_ext)) {
> +					struct
> v4l2_mpeg_video_mpeg2_pic_ext *pic_ext = pic_exts[slice_index];
> +
> +					metas[(*nb_of_metas)++] =
> au->metas_store[PIC_EXT + slice_index];
> +
> +					memset(pic_ext, 0,
> sizeof(*pic_ext));
> +					memcpy(&pic_ext->f_code,
> &gst_pic_ext.f_code, sizeof(pic_ext->f_code));
> +					pic_ext->intra_dc_precision
> = gst_pic_ext.intra_dc_precision;
> +					pic_ext->picture_structure =
> gst_pic_ext.picture_structure;
> +					pic_ext->top_field_first =
> gst_pic_ext.top_field_first;
> +					pic_ext-
> >frame_pred_frame_dct = gst_pic_ext.frame_pred_frame_dct;
> +					pic_ext-
> >concealment_motion_vectors = gst_pic_ext.concealment_motion_vectors;
> +					pic_ext->q_scale_type =
> gst_pic_ext.q_scale_type;
> +					pic_ext->intra_vlc_format =
> gst_pic_ext.intra_vlc_format;
> +					pic_ext->alternate_scan =
> gst_pic_ext.alternate_scan;
> +					pic_ext->repeat_first_field
> = gst_pic_ext.repeat_first_field;
> +					pic_ext->chroma_420_type =
> gst_pic_ext.chroma_420_type;
> +					pic_ext->progressive_frame =
> gst_pic_ext.progressive_frame;
> +					pic_ext->composite_display =
> gst_pic_ext.composite_display;
> +					pic_ext->v_axis =
> gst_pic_ext.v_axis;
> +					pic_ext->field_sequence =
> gst_pic_ext.field_sequence;
> +					pic_ext->sub_carrier =
> gst_pic_ext.sub_carrier;
> +					pic_ext->burst_amplitude =
> gst_pic_ext.burst_amplitude;
> +					pic_ext->sub_carrier_phase =
> gst_pic_ext.sub_carrier_phase;
> +
> +					V4L2_LOG("%s: PICTURE
> EXTENSION, top_field_first=%d\n",
> +						 __func__,
> pic_exts[slice_index]->top_field_first);
> +					meta_found = true;
> +				}
> +				break;
> +
> +			default:
> +				break;
> +			}
> +			break;
> +
> +		case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
> +			V4L2_LOG("%s: END OF PACKET SEQUENCE\n",
> __func__);
> +			break;
> +
> +		case GST_MPEG_VIDEO_PACKET_GOP:
> +			V4L2_LOG("%s: GOP\n", __func__);
> +			break;
> +
> +		default:
> +			V4L2_LOG("%s: unknown/unsupported header
> %02x\n",
> +				 __func__, packet_data.type);
> +			break;
> +		}
> +	}
> +
> +done:
> +	return meta_found;
> +}
> +
> +const struct meta_parser mpeg2parse = {
> +	.name = "mpeg2",
> +	.streamformat = V4L2_PIX_FMT_MPEG2,
> +	.parsedformat = V4L2_PIX_FMT_MPEG2_PARSED,
> +	.nb_of_metas = sizeof(mpeg2_metas_store) /
> sizeof(mpeg2_metas_store[0]),
> +	.metas_store = mpeg2_metas_store,
> +	.parse_metas = mpeg2_parse_metas,
> +};
> +
> +const struct meta_parser mpeg1parse = {
> +	.name = "mpeg1",
> +	.streamformat = V4L2_PIX_FMT_MPEG1,
> +	.parsedformat = V4L2_PIX_FMT_MPEG1_PARSED,
> +	.nb_of_metas = sizeof(mpeg2_metas_store) /
> sizeof(mpeg2_metas_store[0]),
> +	.metas_store = mpeg2_metas_store,
> +	.parse_metas = mpeg2_parse_metas,
> +};
> diff --git a/lib/libv4l-codecparsers/libv4l-cparsers.c b/lib/libv4l-
> codecparsers/libv4l-cparsers.c
> index af59f50..4e8ae31 100644
> --- a/lib/libv4l-codecparsers/libv4l-cparsers.c
> +++ b/lib/libv4l-codecparsers/libv4l-cparsers.c
> @@ -46,7 +46,11 @@
>  #endif
>  
>  /* available parsers */
> +extern const struct meta_parser mpeg1parse;
> +extern const struct meta_parser mpeg2parse;
>  const struct meta_parser *parsers[] = {
> +	&mpeg1parse,
> +	&mpeg2parse,
>  };
>  
>  static void *plugin_init(int fd)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser
  2017-05-01 17:37   ` Nicolas Dufresne
@ 2017-05-03  9:13     ` Hugues FRUCHET
  0 siblings, 0 replies; 6+ messages in thread
From: Hugues FRUCHET @ 2017-05-03  9:13 UTC (permalink / raw)
  To: Nicolas Dufresne, linux-media, Hans Verkuil
  Cc: Benjamin Gaignard, Jean Christophe TROTIN

Thanks Nicolas,
I will update configure.ac accordingly.
BR,
Hugues.

On 05/01/2017 07:37 PM, Nicolas Dufresne wrote:
> Le vendredi 28 avril 2017 à 17:02 +0200, Hugues Fruchet a écrit :
>> Add the mpeg2 codecparser backend glue which will
>> call the GStreamer parsing functions.
>>
>> Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
>> ---
>>  configure.ac                                    |  21 ++
>>  lib/libv4l-codecparsers/Makefile.am             |  14 +-
>>  lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c | 375
>> ++++++++++++++++++++++++
>>  lib/libv4l-codecparsers/libv4l-cparsers.c       |   4 +
>>  4 files changed, 413 insertions(+), 1 deletion(-)
>>  create mode 100644 lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
>>
>> diff --git a/configure.ac b/configure.ac
>> index 9ce7392..ce43f18 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -273,6 +273,25 @@ fi
>>
>>  AC_SUBST([JPEG_LIBS])
>>
>> +# Check for GStreamer codecparsers
>> +
>> +gst_codecparsers_pkgconfig=false
>> +PKG_CHECK_MODULES([GST], [gstreamer-1.0 >= 1.8.0],
>> [gst_pkgconfig=true], [gst_pkgconfig=false])
>> +if test "x$gst_pkgconfig" = "xfalse"; then
>> +   AC_MSG_WARN(GStreamer library is not available)
>> +else
>> +   PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-1.0 >= 1.8.0],
>> [gst_base_pkgconfig=true], [gst_base_pkgconfig=false])
>> +   if test "x$gst_base_pkgconfig" = "xfalse"; then
>> +      AC_MSG_WARN(GStreamer base library is not available)
>> +   else
>> +      PKG_CHECK_MODULES(GST_CODEC_PARSERS, [gstreamer-codecparsers-
>> 1.0 >= 1.8.0], [gst_codecparsers_pkgconfig=true],
>
> You should only check for the codecparser library. The rest are
> dependencies which will be pulled automatically by pkg-config. If for
> some reason you needed multiple libs, that don't depend on each others,
> notice the S in PKG_CHECK_MODULES. You can do a single invocation.
>
>> [gst_codecparsers_pkgconfig=false])
>> +      if test "x$gst_codecparsers_pkgconfig" = "xfalse"; then
>> +         AC_MSG_WARN(GStreamer codecparser library is not available)
>> +      fi
>> +   fi
>> +fi
>> +AM_CONDITIONAL([HAVE_GST_CODEC_PARSERS], [test
>> x$gst_codecparsers_pkgconfig = xtrue])
>> +
>>  # Check for pthread
>>
>>  AS_IF([test x$enable_shared != xno],
>> @@ -477,6 +496,7 @@ AM_COND_IF([WITH_V4L2_CTL_LIBV4L],
>> [USE_V4L2_CTL="yes"], [USE_V4L2_CTL="no"])
>>  AM_COND_IF([WITH_V4L2_CTL_STREAM_TO], [USE_V4L2_CTL="yes"],
>> [USE_V4L2_CTL="no"])
>>  AM_COND_IF([WITH_V4L2_COMPLIANCE_LIBV4L],
>> [USE_V4L2_COMPLIANCE="yes"], [USE_V4L2_COMPLIANCE="no"])
>>  AS_IF([test "x$alsa_pkgconfig" = "xtrue"], [USE_ALSA="yes"],
>> [USE_ALSA="no"])
>> +AS_IF([test "x$gst_codecparsers_pkgconfig" = "xtrue"],
>> [USE_GST_CODECPARSERS="yes"], [USE_GST_CODECPARSERS="no"])
>>
>>  AC_OUTPUT
>>
>> @@ -497,6 +517,7 @@ compile time options summary
>>      pthread             : $have_pthread
>>      QT version          : $QT_VERSION
>>      ALSA support        : $USE_ALSA
>> +    GST codecparsers    : $USE_GST_CODECPARSERS
>>
>>      build dynamic libs  : $enable_shared
>>      build static libs   : $enable_static
>> diff --git a/lib/libv4l-codecparsers/Makefile.am b/lib/libv4l-
>> codecparsers/Makefile.am
>> index a9d6c8b..61f4730 100644
>> --- a/lib/libv4l-codecparsers/Makefile.am
>> +++ b/lib/libv4l-codecparsers/Makefile.am
>> @@ -1,9 +1,21 @@
>>  if WITH_V4L_PLUGINS
>> +if HAVE_GST_CODEC_PARSERS
>> +
>>  libv4l2plugin_LTLIBRARIES = libv4l-codecparsers.la
>> -endif
>>
>>  libv4l_codecparsers_la_SOURCES = libv4l-cparsers.c libv4l-cparsers.h
>>
>>  libv4l_codecparsers_la_CPPFLAGS = $(CFLAG_VISIBILITY)
>> -I$(top_srcdir)/lib/libv4l2/ -I$(top_srcdir)/lib/libv4lconvert/
>>  libv4l_codecparsers_la_LDFLAGS = -avoid-version -module -shared
>> -export-dynamic -lpthread
>>  libv4l_codecparsers_la_LIBADD = ../libv4l2/libv4l2.la
>> +
>> +# GStreamer codecparsers library
>> +libv4l_codecparsers_la_CFLAGS = $(GST_CFLAGS) -DGST_USE_UNSTABLE_API
>> +libv4l_codecparsers_la_LDFLAGS += $(GST_LIB_LDFLAGS)
>> +libv4l_codecparsers_la_LIBADD += $(GLIB_LIBS) $(GST_LIBS)
>> $(GST_BASE_LIBS) $(GST_CODEC_PARSERS_LIBS) $(NULL)
>> +
>> +# MPEG-2 parser back-end
>> +libv4l_codecparsers_la_SOURCES += libv4l-cparsers-mpeg2.c
>> +
>> +endif
>> +endif
>> diff --git a/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
>> b/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
>> new file mode 100644
>> index 0000000..3456b73
>> --- /dev/null
>> +++ b/lib/libv4l-codecparsers/libv4l-cparsers-mpeg2.c
>> @@ -0,0 +1,375 @@
>> +/*
>> + * libv4l-cparsers-mpeg2.c
>> + *
>> + * Copyright (C) STMicroelectronics SA 2017
>> + * Authors: Hugues Fruchet <hugues.fruchet@st.com>
>> + *          Tifaine Inguere <tifaine.inguere@st.com>
>> + *          for STMicroelectronics.
>> + *
>> + * This program 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 program 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 program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston,
>> MA  02110-1335  USA
>> + */
>> +
>> +#include <errno.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <stdbool.h>
>> +
>> +#include "libv4l2.h"
>> +#include "libv4l2-priv.h"
>> +#include "libv4l-cparsers.h"
>> +
>> +#include <gst/codecparsers/gstmpegvideoparser.h>
>> +#include <gst/base/gstbitreader.h>
>> +
>> +/*
>> + * parsing metadata ids and their associated control ids.
>> + * keep in sync both enum and array, this is used to index
>> metas[<meta id>]
>> + */
>> +enum mpeg2_meta_id {
>> +	SEQ_HDR,
>> +	SEQ_EXT,
>> +	SEQ_DISPLAY_EXT,
>> +	SEQ_MATRIX_EXT,
>> +	PIC_HDR,
>> +	PIC_HDR1,/* 2nd field decoding of interlaced stream */
>> +	PIC_EXT,
>> +	PIC_EXT1,/* 2nd field decoding of interlaced stream */
>> +};
>> +
>> +static const struct v4l2_ext_control mpeg2_metas_store[] = {
>> +	{
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_HDR,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_hdr),
>> +	},
>> +	{
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_EXT,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_ext),
>> +	},
>> +	{
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_DISPLAY_EXT,
>> +	.size = sizeof(struct
>> v4l2_mpeg_video_mpeg2_seq_display_ext),
>> +	},
>> +	{
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQ_MATRIX_EXT,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_seq_matrix_ext),
>> +	},
>> +	{
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_hdr),
>> +	},
>> +	{/* 2nd field decoding of interlaced stream */
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_HDR,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_hdr),
>> +	},
>> +	{
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_ext),
>> +	},
>> +	{/* 2nd field decoding of interlaced stream */
>> +	.id = V4L2_CID_MPEG_VIDEO_MPEG2_PIC_EXT,
>> +	.size = sizeof(struct v4l2_mpeg_video_mpeg2_pic_ext),
>> +	},
>> +};
>> +
>> +guint8 get_extension_code(const GstMpegVideoPacket *packet)
>> +{
>> +	GstBitReader br;
>> +	unsigned char extension_code;
>> +
>> +	gst_bit_reader_init(&br, &packet->data[packet->offset],
>> packet->size);
>> +	if (!gst_bit_reader_get_bits_uint8(&br, &extension_code, 4))
>> {
>> +		V4L2_LOG_ERR("failed to read extension code");
>> +		return GST_MPEG_VIDEO_PACKET_NONE;
>> +	}
>> +
>> +	return extension_code;
>> +}
>> +
>> +unsigned int mpeg2_parse_metas(struct cparsers_au *au,
>> +			       struct v4l2_ext_control *metas,
>> +			       unsigned int *nb_of_metas)
>> +{
>> +	unsigned char extension_code;
>> +	bool startcode_found = false;
>> +	bool meta_found = false;
>> +	GstMpegVideoPacket packet_data;
>> +	unsigned int slice_index = 0;
>> +	GstMpegVideoSequenceHdr gst_seq_hdr;
>> +	GstMpegVideoSequenceExt gst_seq_ext;
>> +	GstMpegVideoSequenceDisplayExt gst_seq_display_ext;
>> +	GstMpegVideoQuantMatrixExt gst_seq_matrix_ext;
>> +	GstMpegVideoPictureHdr gst_pic_hdr;
>> +	GstMpegVideoPictureExt gst_pic_ext;
>> +	struct v4l2_mpeg_video_mpeg2_seq_hdr *seq_hdr;
>> +	struct v4l2_mpeg_video_mpeg2_seq_ext *seq_ext;
>> +	struct v4l2_mpeg_video_mpeg2_seq_display_ext
>> *seq_display_ext;
>> +	struct v4l2_mpeg_video_mpeg2_seq_matrix_ext *seq_matrix_ext;
>> +	struct v4l2_mpeg_video_mpeg2_pic_hdr *pic_hdrs[2];
>> +	struct v4l2_mpeg_video_mpeg2_pic_ext *pic_exts[2];
>> +
>> +	if ((!au->addr) || (!au->bytesused) || (!au->metas_store) ||
>> (!metas)) {
>> +		V4L2_LOG_ERR("%s: invalid input: au->addr=%p, au-
>>> bytesused=%d, au->metas_store=%p, metas=%p\n",
>> +			     __func__, au->addr, au->bytesused, au-
>>> metas_store, metas);
>> +		return 0;
>> +	}
>> +
>> +	seq_hdr = au->metas_store[SEQ_HDR].ptr;
>> +	seq_ext = au->metas_store[SEQ_EXT].ptr;
>> +	seq_display_ext = au->metas_store[SEQ_DISPLAY_EXT].ptr;
>> +	seq_matrix_ext = au->metas_store[SEQ_MATRIX_EXT].ptr;
>> +	pic_hdrs[0] = au->metas_store[PIC_HDR].ptr;
>> +	pic_hdrs[1] = au->metas_store[PIC_HDR + 1].ptr;
>> +	pic_exts[0] = au->metas_store[PIC_EXT].ptr;
>> +	pic_exts[1] = au->metas_store[PIC_EXT + 1].ptr;
>> +
>> +	memset(&packet_data, 0, sizeof(packet_data));
>> +
>> +	while (((packet_data.offset + 4) < au->bytesused)) {
>> +		V4L2_LOG("%s: parsing input from offset=%d\n",
>> __func__,
>> +			 packet_data.offset);
>> +		startcode_found = gst_mpeg_video_parse(&packet_data,
>> au->addr, au->bytesused, packet_data.offset);
>> +		if (!startcode_found) {
>> +			V4L2_LOG("%s: parsing is over\n", __func__);
>> +			break;
>> +		}
>> +		/*
>> +		 * gst_mpeg_video_parse compute packet size by
>> searching for next
>> +		 * startcode, but if next startcode is not found
>> (end of access unit),
>> +		 * packet size is set to -1. We fix this here and
>> set packet size
>> +		 * to remaining size in this case.
>> +		 */
>> +		if (packet_data.size < 0)
>> +			packet_data.size = au->bytesused -
>> packet_data.offset;
>> +
>> +		V4L2_LOG("%s: found startcode 0x%02x @offset=%u,
>> size=%d\n",
>> +			 __func__, packet_data.type,
>> packet_data.offset - 4, packet_data.size);
>> +
>> +		switch (packet_data.type) {
>> +		case GST_MPEG_VIDEO_PACKET_PICTURE:
>> +			if
>> (gst_mpeg_video_packet_parse_picture_header
>> +			    (&packet_data, &gst_pic_hdr)) {
>> +				struct v4l2_mpeg_video_mpeg2_pic_hdr
>> *pic_hdr = pic_hdrs[slice_index];
>> +
>> +				metas[(*nb_of_metas)++] = au-
>>> metas_store[PIC_HDR + slice_index];
>> +
>> +				memset(pic_hdr, 0,
>> sizeof(*pic_hdr));
>> +				pic_hdr->tsn = gst_pic_hdr.tsn;
>> +				pic_hdr->pic_type =
>> gst_pic_hdr.pic_type;
>> +				pic_hdr->full_pel_forward_vector =
>> gst_pic_hdr.full_pel_forward_vector;
>> +				pic_hdr->full_pel_backward_vector =
>> gst_pic_hdr.full_pel_backward_vector;
>> +				memcpy(&pic_hdr->f_code,
>> &gst_pic_hdr.f_code, sizeof(pic_hdr->f_code));
>> +
>> +				V4L2_LOG("%s: PICTURE HEADER\n",
>> __func__);
>> +				meta_found = true;
>> +			}
>> +			break;
>> +
>> +		case GST_MPEG_VIDEO_PACKET_SLICE_MIN:
>> +			/* New slice encountered */
>> +			if (slice_index > 1) {
>> +				V4L2_LOG_ERR("%s: more than 2 slices
>> detected @offset=%d, ignoring this slice...\n",
>> +					     __func__,
>> packet_data.offset);
>> +				break;
>> +			}
>> +			/* store its offset, including startcode */
>> +			pic_hdrs[slice_index]->offset =
>> packet_data.offset - 4;
>> +			slice_index++;
>> +
>> +			V4L2_LOG("%s: START OF SLICE @ offset=%d\n",
>> __func__, packet_data.offset);
>> +			meta_found = true;
>> +			goto done;
>> +
>> +			break;
>> +
>> +		case GST_MPEG_VIDEO_PACKET_USER_DATA:
>> +			/* not implemented : do nothing */
>> +			V4L2_LOG("%s: USER DATA, not implemented\n",
>> __func__);
>> +			break;
>> +
>> +		case GST_MPEG_VIDEO_PACKET_SEQUENCE:
>> +			if
>> (gst_mpeg_video_packet_parse_sequence_header
>> +			    (&packet_data, &gst_seq_hdr)) {
>> +				metas[(*nb_of_metas)++] = au-
>>> metas_store[SEQ_HDR];
>> +
>> +				memset(seq_hdr, 0,
>> sizeof(*seq_hdr));
>> +				seq_hdr->width = gst_seq_hdr.width;
>> +				seq_hdr->height =
>> gst_seq_hdr.height;
>> +				seq_hdr->load_intra_quantiser_matrix
>> = 1;
>> +				memcpy(&seq_hdr-
>>> intra_quantiser_matrix,
>> +				       &gst_seq_hdr.intra_quantizer_
>> matrix,
>> +				       sizeof(seq_hdr-
>>> intra_quantiser_matrix));
>> +				seq_hdr-
>>> load_non_intra_quantiser_matrix = 1;
>> +				memcpy(&seq_hdr-
>>> non_intra_quantiser_matrix,
>> +				       &gst_seq_hdr.non_intra_quanti
>> zer_matrix,
>> +				       sizeof(seq_hdr-
>>> non_intra_quantiser_matrix));
>> +
>> +				V4L2_LOG("%s: SEQUENCE HEADER\n",
>> __func__);
>> +				meta_found = true;
>> +			}
>> +			break;
>> +
>> +		case GST_MPEG_VIDEO_PACKET_EXTENSION:
>> +			extension_code =
>> get_extension_code(&packet_data);
>> +			V4L2_LOG("%s: extension code=0x%02x  \n",
>> __func__, extension_code);
>> +
>> +			switch (extension_code) {
>> +			case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
>> +				if
>> (gst_mpeg_video_packet_parse_sequence_extension
>> +				    (&packet_data, &gst_seq_ext)) {
>> +					metas[(*nb_of_metas)++] =
>> au->metas_store[SEQ_EXT];
>> +
>> +					memset(seq_ext, 0,
>> sizeof(*seq_ext));
>> +					seq_ext->profile =
>> gst_seq_ext.profile;
>> +					seq_ext->level =
>> gst_seq_ext.level;
>> +					seq_ext->progressive =
>> gst_seq_ext.progressive;
>> +					seq_ext->chroma_format =
>> gst_seq_ext.chroma_format;
>> +					seq_ext->horiz_size_ext =
>> gst_seq_ext.horiz_size_ext;
>> +					seq_ext->vert_size_ext =
>> gst_seq_ext.vert_size_ext;
>> +
>> +					V4L2_LOG("%s: SEQUENCE
>> EXTENSION\n", __func__);
>> +					meta_found = true;
>> +				}
>> +				break;
>> +
>> +			case
>> GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
>> +				if
>> (gst_mpeg_video_packet_parse_sequence_display_extension
>> +				    (&packet_data,
>> &gst_seq_display_ext)) {
>> +					metas[(*nb_of_metas)++] =
>> au->metas_store[SEQ_DISPLAY_EXT];
>> +
>> +					memset(seq_display_ext, 0,
>> sizeof(*seq_display_ext));
>> +					seq_display_ext-
>>> video_format = gst_seq_display_ext.video_format;
>> +					seq_display_ext-
>>> colour_description_flag =
>> gst_seq_display_ext.colour_description_flag;
>> +					seq_display_ext-
>>> colour_primaries = gst_seq_display_ext.colour_primaries;
>> +					seq_display_ext-
>>> transfer_characteristics =
>> gst_seq_display_ext.transfer_characteristics;
>> +					seq_display_ext-
>>> matrix_coefficients = gst_seq_display_ext.matrix_coefficients;
>> +					seq_display_ext-
>>> display_horizontal_size =
>> gst_seq_display_ext.display_horizontal_size;
>> +					seq_display_ext-
>>> display_vertical_size = gst_seq_display_ext.display_vertical_size;
>> +
>> +					V4L2_LOG("%s: SEQUENCE
>> DISPLAY EXTENSION\n", __func__);
>> +					meta_found = true;
>> +				}
>> +				break;
>> +
>> +			case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
>> +				if
>> (gst_mpeg_video_packet_parse_quant_matrix_extension
>> +				    (&packet_data,
>> &gst_seq_matrix_ext)) {
>> +					metas[(*nb_of_metas)++] =
>> au->metas_store[SEQ_DISPLAY_EXT];
>> +
>> +					memset(seq_matrix_ext, 0,
>> sizeof(*seq_matrix_ext));
>> +					seq_matrix_ext-
>>> load_intra_quantiser_matrix =
>> +						gst_seq_matrix_ext.l
>> oad_intra_quantiser_matrix;
>> +					memcpy(&seq_matrix_ext-
>>> intra_quantiser_matrix,
>> +					       &gst_seq_matrix_ext.i
>> ntra_quantiser_matrix,
>> +					       sizeof(seq_matrix_ext
>> ->intra_quantiser_matrix));
>> +					seq_matrix_ext-
>>> load_non_intra_quantiser_matrix =
>> +						gst_seq_matrix_ext.l
>> oad_non_intra_quantiser_matrix;
>> +					memcpy(&seq_matrix_ext-
>>> non_intra_quantiser_matrix,
>> +					       &gst_seq_matrix_ext.n
>> on_intra_quantiser_matrix,
>> +					       sizeof(seq_matrix_ext
>> ->non_intra_quantiser_matrix));
>> +					seq_matrix_ext-
>>> load_chroma_intra_quantiser_matrix =
>> +						gst_seq_matrix_ext.l
>> oad_chroma_intra_quantiser_matrix;
>> +					memcpy(&seq_matrix_ext-
>>> chroma_intra_quantiser_matrix,
>> +					       &gst_seq_matrix_ext.c
>> hroma_intra_quantiser_matrix,
>> +					       sizeof(seq_matrix_ext
>> ->chroma_intra_quantiser_matrix));
>> +					seq_matrix_ext-
>>> load_chroma_non_intra_quantiser_matrix =
>> +						gst_seq_matrix_ext.l
>> oad_chroma_non_intra_quantiser_matrix;
>> +					memcpy(&seq_matrix_ext-
>>> chroma_non_intra_quantiser_matrix,
>> +					       &gst_seq_matrix_ext.c
>> hroma_non_intra_quantiser_matrix,
>> +					       sizeof(seq_matrix_ext
>> ->chroma_non_intra_quantiser_matrix));
>> +
>> +					V4L2_LOG("%s: SEQUENCE
>> MATRIX EXTENSION\n", __func__);
>> +					meta_found = true;
>> +				}
>> +				break;
>> +
>> +			case
>> GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
>> +				/* not implemented : do nothing */
>> +				V4L2_LOG("%s: SEQUENCE SCALABLE
>> EXTENSION, not implemented\n", __func__);
>> +				break;
>> +
>> +			case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
>> +				if
>> (gst_mpeg_video_packet_parse_picture_extension
>> +				    (&packet_data, &gst_pic_ext)) {
>> +					struct
>> v4l2_mpeg_video_mpeg2_pic_ext *pic_ext = pic_exts[slice_index];
>> +
>> +					metas[(*nb_of_metas)++] =
>> au->metas_store[PIC_EXT + slice_index];
>> +
>> +					memset(pic_ext, 0,
>> sizeof(*pic_ext));
>> +					memcpy(&pic_ext->f_code,
>> &gst_pic_ext.f_code, sizeof(pic_ext->f_code));
>> +					pic_ext->intra_dc_precision
>> = gst_pic_ext.intra_dc_precision;
>> +					pic_ext->picture_structure =
>> gst_pic_ext.picture_structure;
>> +					pic_ext->top_field_first =
>> gst_pic_ext.top_field_first;
>> +					pic_ext-
>>> frame_pred_frame_dct = gst_pic_ext.frame_pred_frame_dct;
>> +					pic_ext-
>>> concealment_motion_vectors = gst_pic_ext.concealment_motion_vectors;
>> +					pic_ext->q_scale_type =
>> gst_pic_ext.q_scale_type;
>> +					pic_ext->intra_vlc_format =
>> gst_pic_ext.intra_vlc_format;
>> +					pic_ext->alternate_scan =
>> gst_pic_ext.alternate_scan;
>> +					pic_ext->repeat_first_field
>> = gst_pic_ext.repeat_first_field;
>> +					pic_ext->chroma_420_type =
>> gst_pic_ext.chroma_420_type;
>> +					pic_ext->progressive_frame =
>> gst_pic_ext.progressive_frame;
>> +					pic_ext->composite_display =
>> gst_pic_ext.composite_display;
>> +					pic_ext->v_axis =
>> gst_pic_ext.v_axis;
>> +					pic_ext->field_sequence =
>> gst_pic_ext.field_sequence;
>> +					pic_ext->sub_carrier =
>> gst_pic_ext.sub_carrier;
>> +					pic_ext->burst_amplitude =
>> gst_pic_ext.burst_amplitude;
>> +					pic_ext->sub_carrier_phase =
>> gst_pic_ext.sub_carrier_phase;
>> +
>> +					V4L2_LOG("%s: PICTURE
>> EXTENSION, top_field_first=%d\n",
>> +						 __func__,
>> pic_exts[slice_index]->top_field_first);
>> +					meta_found = true;
>> +				}
>> +				break;
>> +
>> +			default:
>> +				break;
>> +			}
>> +			break;
>> +
>> +		case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
>> +			V4L2_LOG("%s: END OF PACKET SEQUENCE\n",
>> __func__);
>> +			break;
>> +
>> +		case GST_MPEG_VIDEO_PACKET_GOP:
>> +			V4L2_LOG("%s: GOP\n", __func__);
>> +			break;
>> +
>> +		default:
>> +			V4L2_LOG("%s: unknown/unsupported header
>> %02x\n",
>> +				 __func__, packet_data.type);
>> +			break;
>> +		}
>> +	}
>> +
>> +done:
>> +	return meta_found;
>> +}
>> +
>> +const struct meta_parser mpeg2parse = {
>> +	.name = "mpeg2",
>> +	.streamformat = V4L2_PIX_FMT_MPEG2,
>> +	.parsedformat = V4L2_PIX_FMT_MPEG2_PARSED,
>> +	.nb_of_metas = sizeof(mpeg2_metas_store) /
>> sizeof(mpeg2_metas_store[0]),
>> +	.metas_store = mpeg2_metas_store,
>> +	.parse_metas = mpeg2_parse_metas,
>> +};
>> +
>> +const struct meta_parser mpeg1parse = {
>> +	.name = "mpeg1",
>> +	.streamformat = V4L2_PIX_FMT_MPEG1,
>> +	.parsedformat = V4L2_PIX_FMT_MPEG1_PARSED,
>> +	.nb_of_metas = sizeof(mpeg2_metas_store) /
>> sizeof(mpeg2_metas_store[0]),
>> +	.metas_store = mpeg2_metas_store,
>> +	.parse_metas = mpeg2_parse_metas,
>> +};
>> diff --git a/lib/libv4l-codecparsers/libv4l-cparsers.c b/lib/libv4l-
>> codecparsers/libv4l-cparsers.c
>> index af59f50..4e8ae31 100644
>> --- a/lib/libv4l-codecparsers/libv4l-cparsers.c
>> +++ b/lib/libv4l-codecparsers/libv4l-cparsers.c
>> @@ -46,7 +46,11 @@
>>  #endif
>>
>>  /* available parsers */
>> +extern const struct meta_parser mpeg1parse;
>> +extern const struct meta_parser mpeg2parse;
>>  const struct meta_parser *parsers[] = {
>> +	&mpeg1parse,
>> +	&mpeg2parse,
>>  };
>>
>>  static void *plugin_init(int fd)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-05-03  9:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-28 15:02 [PATCH v2 0/3] Add a libv4l plugin for video bitstream parsing Hugues Fruchet
2017-04-28 15:02 ` [PATCH v2 1/3] v4l-utils: sync with kernel (parsed MPEG-2 support) Hugues Fruchet
2017-04-28 15:02 ` [PATCH v2 2/3] add libv4l-codecparsers plugin for video bitstream parsing Hugues Fruchet
2017-04-28 15:02 ` [PATCH v2 3/3] libv4l-codecparsers: add GStreamer mpeg2 parser Hugues Fruchet
2017-05-01 17:37   ` Nicolas Dufresne
2017-05-03  9:13     ` Hugues FRUCHET

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.