linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] v4l-utils: dvb: add streaming support
@ 2025-06-05 10:58 Hans Verkuil
  2025-06-05 10:58 ` [PATCH 1/9] dvbv5: streaming support using videobuf2 for DVR and auto-scan Hans Verkuil
                   ` (8 more replies)
  0 siblings, 9 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab

This series picks up where Satendra left it back in 2017.

The original patch added support for streaming I/O in dvbv5-zap and
dvbv5-scan, but it was incomplete, especially for dvbv5-scan.

The patches on top fix a number of issues, mainly relating to
dvbv5-scan, allowing that utility to also use the streaming I/O if
the -R option was specified. Various bugs were addressed and
finally a test was added to test-media.

This was used to test the kernel patches that drop the
wait_prepare/finish callbacks:

https://patchwork.linuxtv.org/project/linux-media/list/?series=15715

The media CI test of the kernel patches + these v4l-utils patches
is here:

https://gitlab.freedesktop.org/linux-media/users/hverkuil/-/pipelines/1443147

Regards,

	Hans

Hans Verkuil (8):
  dvbv5: use proper dvb_v5 namespace
  dvb-vb2: add dvb_v5_stream_alloc/free
  libdvbv5: prepare for vb2 stream context
  dvbv5-scan: add -R streaming option
  libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible
  libdvbv5/dvb-scan: always requeue after dvb_parse_section
  libdvbv5/dvb-scan: flush any pending bufs after dvb_dmx_stop
  test-media: add initial vidtv streaming test

Satendra Singh Thakur (1):
  dvbv5: streaming support using videobuf2 for DVR and auto-scan

 contrib/test/test-media        |  50 +++++
 lib/include/libdvbv5/dvb-dev.h |   8 +
 lib/include/libdvbv5/dvb-fe.h  |   5 +
 lib/include/libdvbv5/dvb-vb2.h | 161 +++++++++++++++
 lib/libdvbv5/dvb-fe-priv.h     |   2 +-
 lib/libdvbv5/dvb-scan.c        | 112 +++++++++--
 lib/libdvbv5/dvb-v5-std.c      |   7 +
 lib/libdvbv5/dvb-vb2.c         | 349 +++++++++++++++++++++++++++++++++
 lib/libdvbv5/meson.build       |   2 +
 utils/dvb/dvbv5-scan.c         |  13 ++
 utils/dvb/dvbv5-zap.c          |  30 ++-
 11 files changed, 718 insertions(+), 21 deletions(-)
 create mode 100644 lib/include/libdvbv5/dvb-vb2.h
 create mode 100644 lib/libdvbv5/dvb-vb2.c

-- 
2.47.2


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

* [PATCH 1/9] dvbv5: streaming support using videobuf2 for DVR and auto-scan
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 2/9] dvbv5: use proper dvb_v5 namespace Hans Verkuil
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media
  Cc: Mauro Carvalho Chehab, Junghak Sung, Geunyoung Kim, Seung-Woo Kim,
	Inki Dae, Satendra Singh Thakur, Hans Verkuil

From: Satendra Singh Thakur <satendra.t@samsung.com>

Ported an older patch (details given below) to latest v4l-utils:
 commit 6049ea8bd64f (Statically linking libdvbv5 must
 include -ludev) v4l-utils
 -Added videobuf2 code for auto-scan
-Enhanced queueing logic
--Enqueue all bufs in the begining, dequeue one buf
--Consume it, enqueue it again and so on..
-Added a common dvb-vb2 lib for following streaming APIs.
--initializatioin, deinitialization: unmap and dequeue
--enqueue buf, dequeue buf
--export buf, stream_to_file
--xioctl for repeated ioctl calling
-Added comments to functions
-This code could not be tested so far

Original patch:
https://patchwork.linuxtv.org/patch/31612/

Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Satendra Singh Thakur <satendra.t@samsung.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/include/libdvbv5/dvb-dev.h |   8 +
 lib/include/libdvbv5/dvb-vb2.h | 147 +++++++++++++++
 lib/libdvbv5/dvb-scan.c        | 100 ++++++++--
 lib/libdvbv5/dvb-vb2.c         | 325 +++++++++++++++++++++++++++++++++
 lib/libdvbv5/meson.build       |   2 +
 utils/dvb/dvbv5-zap.c          |  30 ++-
 6 files changed, 599 insertions(+), 13 deletions(-)
 create mode 100644 lib/include/libdvbv5/dvb-vb2.h
 create mode 100644 lib/libdvbv5/dvb-vb2.c

diff --git a/lib/include/libdvbv5/dvb-dev.h b/lib/include/libdvbv5/dvb-dev.h
index 6b4d7483..3fdf7a09 100644
--- a/lib/include/libdvbv5/dvb-dev.h
+++ b/lib/include/libdvbv5/dvb-dev.h
@@ -308,6 +308,14 @@ struct dvb_open_descriptor *dvb_dev_open(struct dvb_device *dvb,
  * closed.
  */
 void dvb_dev_close(struct dvb_open_descriptor *open_dev);
+/**
+ * @brief Gets open file descriptor of a dvb device
+ * @ingroup dvb_device
+ *
+ * @param open_dev	Points to the struct dvb_open_descriptor
+ * @return Retuns fd on success, -1 otherwise.
+ */
+int dvb_dev_get_fd(struct dvb_open_descriptor *open_dev);
 
 /**
  * @brief returns fd from a local device
diff --git a/lib/include/libdvbv5/dvb-vb2.h b/lib/include/libdvbv5/dvb-vb2.h
new file mode 100644
index 00000000..e66b9efe
--- /dev/null
+++ b/lib/include/libdvbv5/dvb-vb2.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2017-2018 - Mauro Carvalho Chehab
+ * Copyright (c) 2017-2018 - Junghak Sung <jh1009.sung@samsung.com>
+ * Copyright (c) 2017-2018 - Satendra Singh Thakur <satendra.t@samsung.com>
+ *
+ * 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 version 2.1 of the License.
+ *
+ * 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, Fifth Floor, Boston, MA 02110-1301 USA
+ * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+#ifndef _LIBVB2_H
+#define _LIBVB2_H
+
+#include <stdint.h>
+#include <linux/dvb/dmx.h>
+
+/**
+ * @file dvb-vb2.h
+ * @ingroup frontend_scan
+ * @brief Provides interfaces to videobuf2 streaming for DVB.
+ * @copyright GNU Lesser General Public License version 2.1 (LGPLv2.1)
+ * @author Satendra Singh Thakur
+ *
+ * @par Bug Report
+ * Please submit bug reports and patches to linux-media@vger.kernel.org
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define memzero(x) memset(&(x), 0, sizeof(x))
+
+/**Max count of the buffers*/
+#define MAX_STREAM_BUF_CNT	10
+
+/**
+ * struct stream_ctx - Streaming context
+ *
+ * @param in_fd		File descriptor of streaming device
+ * @param out_fd	File descriptor of output file
+ * @param buf_cnt	Count of the buffers to be queued/dequeued
+ * @param buf_size	Size of one such buffer
+ * @param buf		Pointer to array of buffers
+ * @param buf_flags	Array of boolean flags corresponding to buffers
+ * @param exp_fd	Array of file descriptors of exported buffers
+ * @param error		Error flag
+ */
+struct stream_ctx {
+	int in_fd;
+	int out_fd;
+	int buf_cnt;
+	int buf_size;
+	unsigned char *buf[MAX_STREAM_BUF_CNT];
+	int buf_flag[MAX_STREAM_BUF_CNT];
+	int exp_fd[MAX_STREAM_BUF_CNT];
+	int error;
+};
+/**
+ * stream_qbuf - Enqueues a buffer specified by index n
+ *
+ * @param sc		Context for streaming management
+ *			Pointer to &struct stream_ctx
+ * @param idx		Index of the buffer
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_qbuf(struct stream_ctx *sc, int idx);
+
+/**
+ * sream_dqbuf - Dequeues a buffer specified by buf argument
+ *
+ * @param sc		Context for streaming management
+ *			Pointer to &struct stream_ctx
+ * @param buf		Pointer to &struct dmx_buffer
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_dqbuf(struct stream_ctx *sc, struct dmx_buffer *buf);
+/**
+ * sream_expbuf - Exports a buffer specified by buf argument
+ *
+ * @param sc		Context for streaming management
+ *			Pointer to &struct stream_ctx
+ * @param idx		Index of the buffer
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_expbuf(struct stream_ctx *sc, int idx);
+/**
+ * stream_init - Requests number of buffers from memory
+ * Gets pointer to the buffers from driver, mmaps those buffers
+ * and stores them in an array
+ * Also, optionally exports those buffers
+ *
+ * @param sc		Context for streaming management
+ * @param in_fd		File descriptor of the streaming device
+ * @param buf_size	Size of the buffer
+ * @param buf_cnt	Number of buffers
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_init(struct stream_ctx *sc, int in_fd, int buf_size, int buf_cnt);
+
+/**
+ * @struct dvb_table_filter
+ * @brief De-initiazes streaming
+ * @ingroup frontend_scan
+ *
+ * @param sc		Pointer to &struct stream_ctx
+ */
+void stream_deinit(struct stream_ctx *sc);
+/**
+ * stream_to_file - Implements enqueue and dequeue logic
+ * First enqueues all the available buffers then dequeues
+ * one buffer, again enqueues it and so on.
+ *
+ * @param in_fd		File descriptor of the streaming device
+ * @param out_fd	File descriptor of output file
+ * @param timeout	Timeout in seconds
+ * @param dbg_level	Debug flag
+ * @param exit_flag	Flag to exit
+ *
+ * @return void
+ */
+void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
+			int *exit_flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/libdvbv5/dvb-scan.c b/lib/libdvbv5/dvb-scan.c
index fcf2eba7..053ee137 100644
--- a/lib/libdvbv5/dvb-scan.c
+++ b/lib/libdvbv5/dvb-scan.c
@@ -72,6 +72,28 @@
 
 # define N_(string) string
 
+#define PERROR(x...)                                                    \
+	do {                                                            \
+		fprintf(stderr, "ERROR: ");                             \
+		fprintf(stderr, x);                                     \
+		fprintf(stderr, " (%s)\n", strerror(errno));		\
+	} while (0)
+
+
+/**Videobuf2 streaming
+ * Comment VB2 macro to disable the streaming code
+ */
+#define VB2
+
+#ifdef VB2
+#include <sys/mman.h>
+#include <libdvbv5/dvb-vb2.h>
+#define STREAM_BUF_CNT (4)
+#define STREAM_BUF_SIZ (DVB_MAX_PAYLOAD_PACKET_SIZE)
+
+struct stream_ctx sc = {0,};
+#endif
+
 static int dvb_poll(struct dvb_v5_fe_parms_priv *parms, int fd, unsigned int seconds)
 {
 	fd_set set;
@@ -331,7 +353,8 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 	if (parms->p.verbose)
 		dvb_log(_("%s: waiting for table ID 0x%02x, program ID 0x%02x"),
 			__func__, sect->tid, sect->pid);
-
+#ifdef VB2
+#else
 	buf = calloc(DVB_MAX_PAYLOAD_PACKET_SIZE, 1);
 	if (!buf) {
 		dvb_logerr(_("%s: out of memory"), __func__);
@@ -339,7 +362,7 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 		dvb_table_filter_free(sect);
 		return -1;
 	}
-
+#endif
 
 	do {
 		int available;
@@ -359,7 +382,23 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 			ret = -1;
 			break;
 		}
+#ifdef VB2
+		struct dmx_buffer b;
+		memset(&b, 0, sizeof(b));
+
+		ret = stream_dqbuf(&sc, &b);
+		if (ret < 0) {
+			sc.error = 1;
+			break;
+		}
+		else {
+			sc.buf_flag[b.index] = 0;
+			buf = sc.buf[b.index];
+			buf_length = b.bytesused;
+		}
+#else
 		buf_length = read(dmx_fd, buf, DVB_MAX_PAYLOAD_PACKET_SIZE);
+#endif
 
 		if (!buf_length) {
 			dvb_logerr(_("%s: buf returned an empty buffer"), __func__);
@@ -380,8 +419,24 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 		}
 
 		ret = dvb_parse_section(parms, sect, buf, buf_length);
+#ifdef VB2
+		/**enqueue the buffer again*/
+		if (!ret) {
+			if (stream_qbuf(&sc, b.index) < 0) {
+				sc.error = 1;
+				break;
+			}
+			else
+				sc.buf_flag[b.index] = 1;
+		}
+
+#endif
 	} while (!ret);
+
+#ifdef VB2
+#else
 	free(buf);
+#endif
 	dvb_dmx_stop(dmx_fd);
 	dvb_table_filter_free(sect);
 
@@ -459,9 +514,22 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 
 	struct dvb_v5_descriptors *dvb_scan_handler;
 
+#ifdef VB2
+	rc = stream_init(&sc, dmx_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
+	if (rc < 0) {
+		PERROR("stream_init failed: error %d, %s\n",
+				errno, strerror(errno));
+		/** We dont know what failed during stream_init
+		 * reqbufs, mmap or  qbuf. We will call stream_deinit
+		 * to delete the mapping which might have been created
+		 */
+		goto ret_null;
+	}
+#endif
+
 	dvb_scan_handler = dvb_scan_alloc_handler_table(delivery_system);
 	if (!dvb_scan_handler)
-		return NULL;
+		goto ret_null;
 
 	if (!timeout_multiply)
 		timeout_multiply = 1;
@@ -515,11 +583,11 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 			      (void **)&dvb_scan_handler->pat,
 			      pat_pmt_time * timeout_multiply);
 	if (parms->p.abort)
-		return dvb_scan_handler;
+		goto ret_handler;
 	if (rc < 0) {
 		dvb_logerr(_("error while waiting for PAT table"));
 		dvb_scan_free_handler_table(dvb_scan_handler);
-		return NULL;
+		goto ret_null;
 	}
 	if (parms->p.verbose)
 		dvb_table_pat_print(&parms->p, dvb_scan_handler->pat);
@@ -531,7 +599,7 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 				      (void **)&dvb_scan_handler->vct,
 				      vct_time * timeout_multiply);
 		if (parms->p.abort)
-			return dvb_scan_handler;
+			goto ret_handler;
 		if (rc < 0)
 			dvb_logerr(_("error while waiting for VCT table"));
 		else if (parms->p.verbose)
@@ -561,7 +629,7 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 				      pat_pmt_time * timeout_multiply);
 		if (parms->p.abort) {
 			dvb_scan_handler->num_program = num_pmt + 1;
-			return dvb_scan_handler;
+			goto ret_handler;
 		}
 		if (rc < 0) {
 			dvb_logerr(_("error while reading the PMT table for service 0x%04x"),
@@ -582,7 +650,7 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 			      (void **)&dvb_scan_handler->nit,
 			      nit_time * timeout_multiply);
 	if (parms->p.abort)
-		return dvb_scan_handler;
+		goto ret_handler;
 	if (rc < 0)
 		dvb_logerr(_("error while reading the NIT table"));
 	else if (parms->p.verbose)
@@ -595,7 +663,7 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 				(void **)&dvb_scan_handler->sdt,
 				sdt_time * timeout_multiply);
 		if (parms->p.abort)
-			return dvb_scan_handler;
+			goto ret_handler;
 		if (rc < 0)
 			dvb_logerr(_("error while reading the SDT table"));
 		else if (parms->p.verbose)
@@ -611,7 +679,7 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 				      (void **)&dvb_scan_handler->nit,
 				      nit_time * timeout_multiply);
 		if (parms->p.abort)
-			return dvb_scan_handler;
+			goto ret_handler;
 		if (rc < 0)
 			dvb_logerr(_("error while reading the NIT table"));
 		else if (parms->p.verbose)
@@ -622,13 +690,23 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 				(void **)&dvb_scan_handler->sdt,
 				sdt_time * timeout_multiply);
 		if (parms->p.abort)
-			return dvb_scan_handler;
+			goto ret_handler;
 		if (rc < 0)
 			dvb_logerr(_("error while reading the SDT table"));
 		else if (parms->p.verbose)
 			dvb_table_sdt_print(&parms->p, dvb_scan_handler->sdt);
 	}
 
+ret_null:
+#ifdef VB2
+	stream_deinit(&sc);
+#endif
+	return NULL;
+
+ret_handler:
+#ifdef VB2
+	stream_deinit(&sc);
+#endif
 	return dvb_scan_handler;
 }
 
diff --git a/lib/libdvbv5/dvb-vb2.c b/lib/libdvbv5/dvb-vb2.c
new file mode 100644
index 00000000..9617d1b1
--- /dev/null
+++ b/lib/libdvbv5/dvb-vb2.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2017-2018 - Mauro Carvalho Chehab
+ * Copyright (c) 2017-2018 - Junghak Sung <jh1009.sung@samsung.com>
+ * Copyright (c) 2017-2018 - Satendra Singh Thakur <satendra.t@samsung.com>
+ *
+ * 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 version 2.1 of the License.
+ *
+ * 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, Fifth Floor, Boston, MA 02110-1301 USA
+ * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+/******************************************************************************
+ * Implements videobuf2 streaming APIs for DVB
+ *****************************************************************************/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <sys/mman.h>
+#include <libdvbv5/dvb-vb2.h>
+
+#define PERROR(x...)                                                    \
+	do {                                                            \
+		fprintf(stderr, "ERROR: ");                             \
+		fprintf(stderr, x);                                     \
+		fprintf(stderr, " (%s)\n", strerror(errno));		\
+	} while (0)
+
+/**These 2 params are for DVR*/
+#define STREAM_BUF_CNT (10)
+#define STREAM_BUF_SIZ (188*1024)
+/*Sleep time for retry, in case ioctl fails*/
+#define SLEEP_US	1000
+
+static inline int xioctl(int fd, unsigned long int cmd, void *arg)
+{
+	int ret;
+	struct timespec stime, etime;
+	long long etimell = 0, stimell = 0;
+	clock_gettime(CLOCK_MONOTONIC, &stime);
+	do {
+		ret = ioctl(fd, cmd, arg);
+		if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
+			clock_gettime(CLOCK_MONOTONIC, &etime);
+			etimell = (long long) etime.tv_sec * 1000000000 +
+					etime.tv_nsec;
+			stimell = (long long) (stime.tv_sec + 1 /*1 sec wait*/)
+					* 1000000000 + stime.tv_nsec;
+			if (etimell > stimell)
+				break;
+			/*wait for some time to prevent cpu hogging*/
+			usleep(SLEEP_US);
+			continue;
+		}
+		else
+			break;
+	} while (1);
+
+        return ret;
+}
+
+
+/**
+ * stream_qbuf - Enqueues a buffer specified by index
+ *
+ * @param sc		Context for streaming management
+ *			Pointer to &struct stream_ctx
+ * @param idx		Index of the buffer
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_qbuf(struct stream_ctx *sc, int idx)
+{
+	struct dmx_buffer buf;
+	int ret;
+
+	memzero(buf);
+	buf.index = idx;
+
+	ret = xioctl(sc->in_fd, DMX_QBUF, &buf);
+	if (ret < 0) {
+		PERROR("DMX_QBUF failed: error=%d", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * stream_dqbuf - Dequeues a buffer specified by index
+ *
+ * @param sc		Context for streaming management
+ *			Pointer to &struct stream_ctx
+ * @param buf		Pointer to &struct dmx_buffer
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_dqbuf(struct stream_ctx *sc, struct dmx_buffer *buf)
+{
+	int ret;
+
+	ret = xioctl(sc->in_fd, DMX_DQBUF, buf);
+	if (ret < 0) {
+		PERROR("DMX_DQBUF failed: error=%d", ret);
+		return ret;
+	}
+
+	return ret;
+}
+/**
+ * sream_expbuf - Exports a buffer specified by buf argument
+ *
+ * @param sc		Context for streaming management
+ *			Pointer to &struct stream_ctx
+ * @param idx		Buffer index
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_expbuf(struct stream_ctx *sc, int idx)
+{
+	int ret;
+	struct dmx_exportbuffer exp;
+	memzero(exp);
+	exp.index = idx;
+	ret = ioctl(sc->in_fd, DMX_EXPBUF, &exp);
+	if (ret) {
+		PERROR("DMX_EXPBUF failed: buf=%d error=%d", idx, ret);
+		return ret;
+	}
+	sc->exp_fd[idx] = exp.fd;
+	fprintf(stderr, "Export buffer %d (fd=%d)\n",
+			idx, sc->exp_fd[idx]);
+	return ret;
+}
+/**
+ * stream_init - Requests number of buffers from memory
+ * Gets pointer to the buffers from driver, mmaps those buffers
+ * and stores them in an array
+ * Also, optionally exports those buffers
+ *
+ * @param sc		Context for streaming management
+ * @param in_fd		File descriptor of the streaming device
+ * @param buf_size	Size of the buffer
+ * @param buf_cnt	Count of the buffers
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+int stream_init(struct stream_ctx *sc, int in_fd, int buf_size, int buf_cnt)
+{
+	struct dmx_requestbuffers req;
+	struct dmx_buffer buf;
+	int ret;
+	int i;
+
+	memset(sc, 0, sizeof(struct stream_ctx));
+	sc->in_fd = in_fd;
+	sc->buf_size = buf_size;
+	sc->buf_cnt = buf_cnt;
+
+	memzero(req);
+	req.count = sc->buf_cnt;
+	req.size = sc->buf_size;
+
+	ret = xioctl(in_fd, DMX_REQBUFS, &req);
+	if (ret) {
+		PERROR("DMX_REQBUFS failed: error=%d", ret);
+		return ret;
+	}
+
+	if (sc->buf_cnt != req.count) {
+		PERROR("buf_cnt %d -> %d changed !!!", sc->buf_cnt, req.count);
+		sc->buf_cnt = req.count;
+	}
+
+	for (i = 0; i < sc->buf_cnt; i++) {
+		memzero(buf);
+		buf.index = i;
+
+		ret = xioctl(in_fd, DMX_QUERYBUF, &buf);
+		if (ret) {
+			PERROR("DMX_QUERYBUF failed: buf=%d error=%d", i, ret);
+			return ret;
+		}
+
+		sc->buf[i] = mmap(NULL, buf.length,
+					PROT_READ | PROT_WRITE, MAP_SHARED,
+					in_fd, buf.offset);
+
+		if (sc->buf[i] == MAP_FAILED) {
+			PERROR("Failed to MMAP buffer %d", i);
+			return -1;
+		}
+		/**enqueue the buffers*/
+		ret = stream_qbuf(sc, i);
+		if (ret) {
+			PERROR("stream_qbuf failed: buf=%d error=%d", i, ret);
+			return ret;
+		}
+
+		sc->buf_flag[i] = 1;
+	}
+
+	return 0;
+}
+
+/**
+ * stream_deinit - Dequeues and unmaps the buffers
+ *
+ * @param sc - Context for streaming management
+ *
+ * @return At return, it returns a negative value if error or
+ * zero on success.
+ */
+void stream_deinit(struct stream_ctx *sc)
+{
+	struct dmx_buffer buf;
+	int ret;
+	int i;
+
+	for (i = 0; i < sc->buf_cnt; i++) {
+		memzero(buf);
+		buf.index = i;
+
+		if (sc->buf_flag[i]) {
+			ret = stream_dqbuf(sc, &buf);
+			if (ret) {
+				PERROR("stream_dqbuf failed: buf=%d error=%d",
+					 i, ret);
+			}
+		}
+		ret = munmap(sc->buf[i], sc->buf_size);
+		if (ret) {
+			PERROR("munmap failed: buf=%d error=%d", i, ret);
+		}
+
+	}
+
+	return;
+}
+
+/**
+ * stream_to_file - Implements enqueue and dequeue logic
+ * First enqueues all the available buffers then dequeues
+ * one buffer, again enqueues it and so on.
+ *
+ * @param in_fd		File descriptor of the streaming device
+ * @param out_fd	File descriptor of output file
+ * @param timeout	Timeout in seconds
+ * @param dbg_level	Debug flag
+ * @param exit_flag	Flag to exit
+ *
+ * @return void
+ */
+void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
+			int *exit_flag)
+{
+	struct stream_ctx sc;
+	int ret;
+	long long int rc = 0LL;
+
+	ret = stream_init(&sc, in_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
+	if (ret < 0) {
+		PERROR("[%s] Failed to setup buffers!!!", __func__);
+		sc.error = 1;
+		return;
+	}
+	fprintf(stderr, "start streaming!!!\n");
+	sc.out_fd = out_fd;
+
+	while (!*exit_flag  && !sc.error) {
+		/* dequeue the buffer */
+		struct dmx_buffer b;
+
+		memzero(b);
+		ret = stream_dqbuf(&sc, &b);
+		if (ret < 0) {
+			sc.error = 1;
+			break;
+		}
+		else {
+			sc.buf_flag[b.index] = 0;
+			ret = write(sc.out_fd, sc.buf[b.index],
+					b.bytesused);
+			if (ret < 0) {
+				PERROR("Write failed err=%d", ret);
+				break;
+			} else
+				rc += b.bytesused;
+		}
+
+		/* enqueue the buffer */
+		ret = stream_qbuf(&sc, b.index);
+		if (ret < 0)
+			sc.error = 1;
+		else
+			sc.buf_flag[b.index] = 1;
+	}
+	if (dbg_level < 2) {
+		fprintf(stderr, "copied %lld bytes (%lld Kbytes/sec)\n", rc,
+			rc / (1024 * timeout));
+	}
+	stream_deinit(&sc);
+}
diff --git a/lib/libdvbv5/meson.build b/lib/libdvbv5/meson.build
index 8f5929fc..eedb1ead 100644
--- a/lib/libdvbv5/meson.build
+++ b/lib/libdvbv5/meson.build
@@ -40,6 +40,7 @@ libdvbv5_sources = files(
     'dvb-legacy-channel-format.c',
     'dvb-log.c',
     'dvb-sat.c',
+    'dvb-vb2.c',
     'dvb-scan.c',
     'dvb-v5-std.c',
     'dvb-v5.c',
@@ -105,6 +106,7 @@ libdvbv5_api = files(
     '../include/libdvbv5/dvb-frontend.h',
     '../include/libdvbv5/dvb-log.h',
     '../include/libdvbv5/dvb-sat.h',
+    '../include/libdvbv5/dvb-vb2.h',
     '../include/libdvbv5/dvb-scan.h',
     '../include/libdvbv5/dvb-v5-std.h',
     '../include/libdvbv5/eit.h',
diff --git a/utils/dvb/dvbv5-zap.c b/utils/dvb/dvbv5-zap.c
index 5f84e101..7ff1d3d1 100644
--- a/utils/dvb/dvbv5-zap.c
+++ b/utils/dvb/dvbv5-zap.c
@@ -47,6 +47,7 @@
 #include <signal.h>
 #include <argp.h>
 #include <sys/time.h>
+#include <sys/mman.h>
 #include <time.h>
 
 #ifdef ENABLE_NLS
@@ -68,6 +69,7 @@
 #include "libdvbv5/dvb-scan.h"
 #include "libdvbv5/header.h"
 #include "libdvbv5/countries.h"
+#include "libdvbv5/dvb-vb2.h"
 
 #define CHANNEL_FILE	"channels.conf"
 #define PROGRAM_NAME	"dvbv5-zap"
@@ -93,6 +95,7 @@ struct arguments {
 	unsigned n_apid, n_vpid, extra_pids, all_pids;
 	enum dvb_file_formats input_format, output_format;
 	unsigned traffic_monitor, low_traffic, non_human, port;
+	unsigned int streaming;
 	char *search, *server;
 	const char *cc;
 
@@ -116,6 +119,7 @@ static const struct argp_option options[] = {
 	{"pat",		'p', NULL,			0, N_("add pat and pmt to TS recording (implies -r)"), 0},
 	{"all-pids",	'P', NULL,			0, N_("don't filter any pids. Instead, outputs all of them"), 0 },
 	{"record",	'r', NULL,			0, N_("set up /dev/dvb/adapterX/dvr0 for TS recording"), 0},
+	{"streaming",	'R', NULL,			0, N_("uses streaming I/O for TS recording"), 0},
 	{"silence",	's', NULL,			0, N_("increases silence (can be used more than once)"), 0},
 	{"sat_number",	'S', N_("satellite_number"),	0, N_("satellite number. If not specified, disable DISEqC"), 0},
 	{"timeout",	't', N_("seconds"),		0, N_("timeout for zapping and for recording"), 0},
@@ -636,6 +640,10 @@ static error_t parse_opt(int k, char *optarg, struct argp_state *state)
 	case 'r':
 		args->dvr = 1;
 		break;
+	case 'R':
+		args->dvr = 1;
+		args->streaming = 1;
+		break;
 	case 'p':
 		args->rec_psi = 1;
 		break;
@@ -1382,14 +1390,32 @@ int main(int argc, char **argv)
 			get_show_stats(stderr, &args, parms, 0);
 
 		if (file_fd >= 0) {
-			dvr_fd = dvb_dev_open(dvb, args.dvr_dev, O_RDONLY);
+			int flag, fd;
+
+			if (args.streaming)
+				flag = O_RDWR;
+			else
+				flag = O_RDONLY;
+
+			dvr_fd = dvb_dev_open(dvb, args.dvr_dev, flag);
 			if (!dvr_fd) {
 				ERROR("failed opening '%s'", args.dvr_dev);
 				goto err;
 			}
 			if (!timeout_flag)
 				fprintf(stderr, _("Record to file '%s' started\n"), args.filename);
-			copy_to_file(dvr_fd, file_fd, args.timeout, args.silent);
+			if (args.streaming) {
+				fd = dvb_dev_get_fd(dvr_fd);
+				if (fd < 0) {
+					ERROR("Invalid fd for '%s'",
+						args.dvr_dev);
+					goto err;
+				}
+				stream_to_file(fd, file_fd, args.timeout,
+						args.silent, &timeout_flag);
+			} else
+				copy_to_file(dvr_fd, file_fd, args.timeout,
+						args.silent);
 		} else if (args.server && args.port) {
 			struct stat st;
 			if (stat(args.dvr_pipe, &st) == -1) {
-- 
2.47.2


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

* [PATCH 2/9] dvbv5: use proper dvb_v5 namespace
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
  2025-06-05 10:58 ` [PATCH 1/9] dvbv5: streaming support using videobuf2 for DVR and auto-scan Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 3/9] dvb-vb2: add dvb_v5_stream_alloc/free Hans Verkuil
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

The use of just 'stream_' as prefix is not unique enough. Use
dvb_v5_stream_ instead.

Also add some newlines to make the code easier to read.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/include/libdvbv5/dvb-vb2.h | 56 +++++++++++++++++-----------------
 lib/libdvbv5/dvb-scan.c        | 16 +++++-----
 lib/libdvbv5/dvb-vb2.c         | 50 +++++++++++++++---------------
 utils/dvb/dvbv5-zap.c          |  4 +--
 4 files changed, 64 insertions(+), 62 deletions(-)

diff --git a/lib/include/libdvbv5/dvb-vb2.h b/lib/include/libdvbv5/dvb-vb2.h
index e66b9efe..26b73fbf 100644
--- a/lib/include/libdvbv5/dvb-vb2.h
+++ b/lib/include/libdvbv5/dvb-vb2.h
@@ -39,13 +39,11 @@
 extern "C" {
 #endif
 
-#define memzero(x) memset(&(x), 0, sizeof(x))
-
-/**Max count of the buffers*/
-#define MAX_STREAM_BUF_CNT	10
+/** Max count of the buffers */
+#define DVB_V5_MAX_STREAM_BUF_CNT	10
 
 /**
- * struct stream_ctx - Streaming context
+ * struct dvb_v5_stream_ctx - Streaming context
  *
  * @param in_fd		File descriptor of streaming device
  * @param out_fd	File descriptor of output file
@@ -56,52 +54,55 @@ extern "C" {
  * @param exp_fd	Array of file descriptors of exported buffers
  * @param error		Error flag
  */
-struct stream_ctx {
+struct dvb_v5_stream_ctx {
 	int in_fd;
 	int out_fd;
 	int buf_cnt;
 	int buf_size;
-	unsigned char *buf[MAX_STREAM_BUF_CNT];
-	int buf_flag[MAX_STREAM_BUF_CNT];
-	int exp_fd[MAX_STREAM_BUF_CNT];
+	unsigned char *buf[DVB_V5_MAX_STREAM_BUF_CNT];
+	int buf_flag[DVB_V5_MAX_STREAM_BUF_CNT];
+	int exp_fd[DVB_V5_MAX_STREAM_BUF_CNT];
 	int error;
 };
+
 /**
- * stream_qbuf - Enqueues a buffer specified by index n
+ * dvb_v5_stream_qbuf - Enqueues a buffer specified by index n
  *
  * @param sc		Context for streaming management
- *			Pointer to &struct stream_ctx
+ *			Pointer to &struct dvb_v5_stream_ctx
  * @param idx		Index of the buffer
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_qbuf(struct stream_ctx *sc, int idx);
+int dvb_v5_stream_qbuf(struct dvb_v5_stream_ctx *sc, int idx);
 
 /**
- * sream_dqbuf - Dequeues a buffer specified by buf argument
+ * dvb_v5_stream_dqbuf - Dequeues a buffer specified by buf argument
  *
  * @param sc		Context for streaming management
- *			Pointer to &struct stream_ctx
+ *			Pointer to &struct dvb_v5_stream_ctx
  * @param buf		Pointer to &struct dmx_buffer
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_dqbuf(struct stream_ctx *sc, struct dmx_buffer *buf);
+int dvb_v5_stream_dqbuf(struct dvb_v5_stream_ctx *sc, struct dmx_buffer *buf);
+
 /**
- * sream_expbuf - Exports a buffer specified by buf argument
+ * dvb_v5_stream_expbuf - Exports a buffer specified by buf argument
  *
  * @param sc		Context for streaming management
- *			Pointer to &struct stream_ctx
+ *			Pointer to &struct dvb_v5_stream_ctx
  * @param idx		Index of the buffer
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_expbuf(struct stream_ctx *sc, int idx);
+int dvb_v5_stream_expbuf(struct dvb_v5_stream_ctx *sc, int idx);
+
 /**
- * stream_init - Requests number of buffers from memory
+ * dvb_v5_stream_init - Requests number of buffers from memory
  * Gets pointer to the buffers from driver, mmaps those buffers
  * and stores them in an array
  * Also, optionally exports those buffers
@@ -114,18 +115,17 @@ int stream_expbuf(struct stream_ctx *sc, int idx);
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_init(struct stream_ctx *sc, int in_fd, int buf_size, int buf_cnt);
+int dvb_v5_stream_init(struct dvb_v5_stream_ctx *sc, int in_fd, int buf_size, int buf_cnt);
 
 /**
- * @struct dvb_table_filter
- * @brief De-initiazes streaming
- * @ingroup frontend_scan
+ * dvb_v5_stream_deinit - Dequeues and unmaps the buffers
  *
- * @param sc		Pointer to &struct stream_ctx
+ * @param sc		Pointer to &struct dvb_v5_stream_ctx
  */
-void stream_deinit(struct stream_ctx *sc);
+void dvb_v5_stream_deinit(struct dvb_v5_stream_ctx *sc);
+
 /**
- * stream_to_file - Implements enqueue and dequeue logic
+ * dvb_v5_stream_to_file - Implements enqueue and dequeue logic
  * First enqueues all the available buffers then dequeues
  * one buffer, again enqueues it and so on.
  *
@@ -137,8 +137,8 @@ void stream_deinit(struct stream_ctx *sc);
  *
  * @return void
  */
-void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
-			int *exit_flag);
+void dvb_v5_stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
+			   int *exit_flag);
 
 #ifdef __cplusplus
 }
diff --git a/lib/libdvbv5/dvb-scan.c b/lib/libdvbv5/dvb-scan.c
index 053ee137..353802a5 100644
--- a/lib/libdvbv5/dvb-scan.c
+++ b/lib/libdvbv5/dvb-scan.c
@@ -91,7 +91,7 @@
 #define STREAM_BUF_CNT (4)
 #define STREAM_BUF_SIZ (DVB_MAX_PAYLOAD_PACKET_SIZE)
 
-struct stream_ctx sc = {0,};
+struct dvb_v5_stream_ctx sc = {0,};
 #endif
 
 static int dvb_poll(struct dvb_v5_fe_parms_priv *parms, int fd, unsigned int seconds)
@@ -386,7 +386,7 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 		struct dmx_buffer b;
 		memset(&b, 0, sizeof(b));
 
-		ret = stream_dqbuf(&sc, &b);
+		ret = dvb_v5_stream_dqbuf(&sc, &b);
 		if (ret < 0) {
 			sc.error = 1;
 			break;
@@ -422,7 +422,7 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 #ifdef VB2
 		/**enqueue the buffer again*/
 		if (!ret) {
-			if (stream_qbuf(&sc, b.index) < 0) {
+			if (dvb_v5_stream_qbuf(&sc, b.index) < 0) {
 				sc.error = 1;
 				break;
 			}
@@ -515,12 +515,12 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 	struct dvb_v5_descriptors *dvb_scan_handler;
 
 #ifdef VB2
-	rc = stream_init(&sc, dmx_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
+	rc = dvb_v5_stream_init(&sc, dmx_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
 	if (rc < 0) {
 		PERROR("stream_init failed: error %d, %s\n",
 				errno, strerror(errno));
-		/** We dont know what failed during stream_init
-		 * reqbufs, mmap or  qbuf. We will call stream_deinit
+		/** We don't know what failed during dvb_v5_stream_init
+		 * reqbufs, mmap or  qbuf. We will call dvb_v5_stream_deinit
 		 * to delete the mapping which might have been created
 		 */
 		goto ret_null;
@@ -699,13 +699,13 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 
 ret_null:
 #ifdef VB2
-	stream_deinit(&sc);
+	dvb_v5_stream_deinit(&sc);
 #endif
 	return NULL;
 
 ret_handler:
 #ifdef VB2
-	stream_deinit(&sc);
+	dvb_v5_stream_deinit(&sc);
 #endif
 	return dvb_scan_handler;
 }
diff --git a/lib/libdvbv5/dvb-vb2.c b/lib/libdvbv5/dvb-vb2.c
index 9617d1b1..8678a767 100644
--- a/lib/libdvbv5/dvb-vb2.c
+++ b/lib/libdvbv5/dvb-vb2.c
@@ -50,6 +50,8 @@
 /*Sleep time for retry, in case ioctl fails*/
 #define SLEEP_US	1000
 
+#define memzero(x) memset(&(x), 0, sizeof(x))
+
 static inline int xioctl(int fd, unsigned long int cmd, void *arg)
 {
 	int ret;
@@ -79,16 +81,16 @@ static inline int xioctl(int fd, unsigned long int cmd, void *arg)
 
 
 /**
- * stream_qbuf - Enqueues a buffer specified by index
+ * dvb_v5_stream_qbuf - Enqueues a buffer specified by index
  *
  * @param sc		Context for streaming management
- *			Pointer to &struct stream_ctx
+ *			Pointer to &struct dvb_v5_stream_ctx
  * @param idx		Index of the buffer
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_qbuf(struct stream_ctx *sc, int idx)
+int dvb_v5_stream_qbuf(struct dvb_v5_stream_ctx *sc, int idx)
 {
 	struct dmx_buffer buf;
 	int ret;
@@ -106,16 +108,16 @@ int stream_qbuf(struct stream_ctx *sc, int idx)
 }
 
 /**
- * stream_dqbuf - Dequeues a buffer specified by index
+ * dvb_v5_stream_dqbuf - Dequeues a buffer specified by index
  *
  * @param sc		Context for streaming management
- *			Pointer to &struct stream_ctx
+ *			Pointer to &struct dvb_v5_stream_ctx
  * @param buf		Pointer to &struct dmx_buffer
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_dqbuf(struct stream_ctx *sc, struct dmx_buffer *buf)
+int dvb_v5_stream_dqbuf(struct dvb_v5_stream_ctx *sc, struct dmx_buffer *buf)
 {
 	int ret;
 
@@ -128,16 +130,16 @@ int stream_dqbuf(struct stream_ctx *sc, struct dmx_buffer *buf)
 	return ret;
 }
 /**
- * sream_expbuf - Exports a buffer specified by buf argument
+ * dvb_v5_stream_expbuf - Exports a buffer specified by buf argument
  *
  * @param sc		Context for streaming management
- *			Pointer to &struct stream_ctx
+ *			Pointer to &struct dvb_v5_stream_ctx
  * @param idx		Buffer index
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_expbuf(struct stream_ctx *sc, int idx)
+int dvb_v5_stream_expbuf(struct dvb_v5_stream_ctx *sc, int idx)
 {
 	int ret;
 	struct dmx_exportbuffer exp;
@@ -154,7 +156,7 @@ int stream_expbuf(struct stream_ctx *sc, int idx)
 	return ret;
 }
 /**
- * stream_init - Requests number of buffers from memory
+ * dvb_v5_stream_init - Requests number of buffers from memory
  * Gets pointer to the buffers from driver, mmaps those buffers
  * and stores them in an array
  * Also, optionally exports those buffers
@@ -167,14 +169,14 @@ int stream_expbuf(struct stream_ctx *sc, int idx)
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-int stream_init(struct stream_ctx *sc, int in_fd, int buf_size, int buf_cnt)
+int dvb_v5_stream_init(struct dvb_v5_stream_ctx *sc, int in_fd, int buf_size, int buf_cnt)
 {
 	struct dmx_requestbuffers req;
 	struct dmx_buffer buf;
 	int ret;
 	int i;
 
-	memset(sc, 0, sizeof(struct stream_ctx));
+	memset(sc, 0, sizeof(struct dvb_v5_stream_ctx));
 	sc->in_fd = in_fd;
 	sc->buf_size = buf_size;
 	sc->buf_cnt = buf_cnt;
@@ -213,7 +215,7 @@ int stream_init(struct stream_ctx *sc, int in_fd, int buf_size, int buf_cnt)
 			return -1;
 		}
 		/**enqueue the buffers*/
-		ret = stream_qbuf(sc, i);
+		ret = dvb_v5_stream_qbuf(sc, i);
 		if (ret) {
 			PERROR("stream_qbuf failed: buf=%d error=%d", i, ret);
 			return ret;
@@ -226,14 +228,14 @@ int stream_init(struct stream_ctx *sc, int in_fd, int buf_size, int buf_cnt)
 }
 
 /**
- * stream_deinit - Dequeues and unmaps the buffers
+ * dvb_v5_stream_deinit - Dequeues and unmaps the buffers
  *
  * @param sc - Context for streaming management
  *
  * @return At return, it returns a negative value if error or
  * zero on success.
  */
-void stream_deinit(struct stream_ctx *sc)
+void dvb_v5_stream_deinit(struct dvb_v5_stream_ctx *sc)
 {
 	struct dmx_buffer buf;
 	int ret;
@@ -244,7 +246,7 @@ void stream_deinit(struct stream_ctx *sc)
 		buf.index = i;
 
 		if (sc->buf_flag[i]) {
-			ret = stream_dqbuf(sc, &buf);
+			ret = dvb_v5_stream_dqbuf(sc, &buf);
 			if (ret) {
 				PERROR("stream_dqbuf failed: buf=%d error=%d",
 					 i, ret);
@@ -261,7 +263,7 @@ void stream_deinit(struct stream_ctx *sc)
 }
 
 /**
- * stream_to_file - Implements enqueue and dequeue logic
+ * dvb_v5_stream_to_file - Implements enqueue and dequeue logic
  * First enqueues all the available buffers then dequeues
  * one buffer, again enqueues it and so on.
  *
@@ -273,14 +275,14 @@ void stream_deinit(struct stream_ctx *sc)
  *
  * @return void
  */
-void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
-			int *exit_flag)
+void dvb_v5_stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
+			   int *exit_flag)
 {
-	struct stream_ctx sc;
+	struct dvb_v5_stream_ctx sc;
 	int ret;
 	long long int rc = 0LL;
 
-	ret = stream_init(&sc, in_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
+	ret = dvb_v5_stream_init(&sc, in_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
 	if (ret < 0) {
 		PERROR("[%s] Failed to setup buffers!!!", __func__);
 		sc.error = 1;
@@ -294,7 +296,7 @@ void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
 		struct dmx_buffer b;
 
 		memzero(b);
-		ret = stream_dqbuf(&sc, &b);
+		ret = dvb_v5_stream_dqbuf(&sc, &b);
 		if (ret < 0) {
 			sc.error = 1;
 			break;
@@ -311,7 +313,7 @@ void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
 		}
 
 		/* enqueue the buffer */
-		ret = stream_qbuf(&sc, b.index);
+		ret = dvb_v5_stream_qbuf(&sc, b.index);
 		if (ret < 0)
 			sc.error = 1;
 		else
@@ -321,5 +323,5 @@ void stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
 		fprintf(stderr, "copied %lld bytes (%lld Kbytes/sec)\n", rc,
 			rc / (1024 * timeout));
 	}
-	stream_deinit(&sc);
+	dvb_v5_stream_deinit(&sc);
 }
diff --git a/utils/dvb/dvbv5-zap.c b/utils/dvb/dvbv5-zap.c
index 7ff1d3d1..aca751af 100644
--- a/utils/dvb/dvbv5-zap.c
+++ b/utils/dvb/dvbv5-zap.c
@@ -1411,8 +1411,8 @@ int main(int argc, char **argv)
 						args.dvr_dev);
 					goto err;
 				}
-				stream_to_file(fd, file_fd, args.timeout,
-						args.silent, &timeout_flag);
+				dvb_v5_stream_to_file(fd, file_fd, args.timeout,
+						      args.silent, &timeout_flag);
 			} else
 				copy_to_file(dvr_fd, file_fd, args.timeout,
 						args.silent);
-- 
2.47.2


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

* [PATCH 3/9] dvb-vb2: add dvb_v5_stream_alloc/free
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
  2025-06-05 10:58 ` [PATCH 1/9] dvbv5: streaming support using videobuf2 for DVR and auto-scan Hans Verkuil
  2025-06-05 10:58 ` [PATCH 2/9] dvbv5: use proper dvb_v5 namespace Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 4/9] libdvbv5: prepare for vb2 stream context Hans Verkuil
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

Add new functions to allocate/free a stream context.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/include/libdvbv5/dvb-vb2.h | 14 +++++++++
 lib/libdvbv5/dvb-vb2.c         | 57 ++++++++++++++++++++++++----------
 2 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/lib/include/libdvbv5/dvb-vb2.h b/lib/include/libdvbv5/dvb-vb2.h
index 26b73fbf..cef046e8 100644
--- a/lib/include/libdvbv5/dvb-vb2.h
+++ b/lib/include/libdvbv5/dvb-vb2.h
@@ -101,6 +101,13 @@ int dvb_v5_stream_dqbuf(struct dvb_v5_stream_ctx *sc, struct dmx_buffer *buf);
  */
 int dvb_v5_stream_expbuf(struct dvb_v5_stream_ctx *sc, int idx);
 
+/**
+ * dvb_v5_stream_alloc - Allocate stream context
+ *
+ * @return a stream context or NULL.
+ */
+struct dvb_v5_stream_ctx *dvb_v5_stream_alloc(void);
+
 /**
  * dvb_v5_stream_init - Requests number of buffers from memory
  * Gets pointer to the buffers from driver, mmaps those buffers
@@ -124,6 +131,13 @@ int dvb_v5_stream_init(struct dvb_v5_stream_ctx *sc, int in_fd, int buf_size, in
  */
 void dvb_v5_stream_deinit(struct dvb_v5_stream_ctx *sc);
 
+/**
+ * dvb_v5_stream_free - Free stream context
+ *
+ * @param sc - Context for streaming management
+ */
+void dvb_v5_stream_free(struct dvb_v5_stream_ctx *sc);
+
 /**
  * dvb_v5_stream_to_file - Implements enqueue and dequeue logic
  * First enqueues all the available buffers then dequeues
diff --git a/lib/libdvbv5/dvb-vb2.c b/lib/libdvbv5/dvb-vb2.c
index 8678a767..56a35f81 100644
--- a/lib/libdvbv5/dvb-vb2.c
+++ b/lib/libdvbv5/dvb-vb2.c
@@ -155,6 +155,17 @@ int dvb_v5_stream_expbuf(struct dvb_v5_stream_ctx *sc, int idx)
 			idx, sc->exp_fd[idx]);
 	return ret;
 }
+
+/**
+ * dvb_v5_stream_alloc - Allocate stream context
+ *
+ * @return a stream context or NULL.
+ */
+struct dvb_v5_stream_ctx *dvb_v5_stream_alloc(void)
+{
+	return calloc(1, sizeof(struct dvb_v5_stream_ctx));
+}
+
 /**
  * dvb_v5_stream_init - Requests number of buffers from memory
  * Gets pointer to the buffers from driver, mmaps those buffers
@@ -262,6 +273,16 @@ void dvb_v5_stream_deinit(struct dvb_v5_stream_ctx *sc)
 	return;
 }
 
+/**
+ * dvb_v5_stream_free - Free stream context
+ *
+ * @param sc - Context for streaming management
+ */
+void dvb_v5_stream_free(struct dvb_v5_stream_ctx *sc)
+{
+	free(sc);
+}
+
 /**
  * dvb_v5_stream_to_file - Implements enqueue and dequeue logic
  * First enqueues all the available buffers then dequeues
@@ -278,33 +299,36 @@ void dvb_v5_stream_deinit(struct dvb_v5_stream_ctx *sc)
 void dvb_v5_stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
 			   int *exit_flag)
 {
-	struct dvb_v5_stream_ctx sc;
-	int ret;
+	struct dvb_v5_stream_ctx *sc = dvb_v5_stream_alloc();
 	long long int rc = 0LL;
+	int ret;
 
-	ret = dvb_v5_stream_init(&sc, in_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
+	if (!sc) {
+		PERROR("[%s] Failed to allocate stream context", __func__);
+		return;
+	}
+	ret = dvb_v5_stream_init(sc, in_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
 	if (ret < 0) {
-		PERROR("[%s] Failed to setup buffers!!!", __func__);
-		sc.error = 1;
+		PERROR("[%s] Failed to initialize stream context", __func__);
+		dvb_v5_stream_free(sc);
 		return;
 	}
 	fprintf(stderr, "start streaming!!!\n");
-	sc.out_fd = out_fd;
+	sc->out_fd = out_fd;
 
-	while (!*exit_flag  && !sc.error) {
+	while (!*exit_flag  && !sc->error) {
 		/* dequeue the buffer */
 		struct dmx_buffer b;
 
 		memzero(b);
-		ret = dvb_v5_stream_dqbuf(&sc, &b);
+		ret = dvb_v5_stream_dqbuf(sc, &b);
 		if (ret < 0) {
-			sc.error = 1;
+			sc->error = 1;
 			break;
 		}
 		else {
-			sc.buf_flag[b.index] = 0;
-			ret = write(sc.out_fd, sc.buf[b.index],
-					b.bytesused);
+			sc->buf_flag[b.index] = 0;
+			ret = write(sc->out_fd, sc->buf[b.index], b.bytesused);
 			if (ret < 0) {
 				PERROR("Write failed err=%d", ret);
 				break;
@@ -313,15 +337,16 @@ void dvb_v5_stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
 		}
 
 		/* enqueue the buffer */
-		ret = dvb_v5_stream_qbuf(&sc, b.index);
+		ret = dvb_v5_stream_qbuf(sc, b.index);
 		if (ret < 0)
-			sc.error = 1;
+			sc->error = 1;
 		else
-			sc.buf_flag[b.index] = 1;
+			sc->buf_flag[b.index] = 1;
 	}
 	if (dbg_level < 2) {
 		fprintf(stderr, "copied %lld bytes (%lld Kbytes/sec)\n", rc,
 			rc / (1024 * timeout));
 	}
-	dvb_v5_stream_deinit(&sc);
+	dvb_v5_stream_deinit(sc);
+	dvb_v5_stream_free(sc);
 }
-- 
2.47.2


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

* [PATCH 4/9] libdvbv5: prepare for vb2 stream context
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
                   ` (2 preceding siblings ...)
  2025-06-05 10:58 ` [PATCH 3/9] dvb-vb2: add dvb_v5_stream_alloc/free Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 5/9] dvbv5-scan: add -R streaming option Hans Verkuil
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

Prepare the libdvbv5 code to support vb2 streaming I/O.

This removes the #ifdef VB2 and instead checks for the presence of
the stream context.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/include/libdvbv5/dvb-fe.h |   5 ++
 lib/libdvbv5/dvb-fe-priv.h    |   2 +-
 lib/libdvbv5/dvb-scan.c       | 127 ++++++++++++++++------------------
 lib/libdvbv5/dvb-vb2.c        |   3 -
 4 files changed, 65 insertions(+), 72 deletions(-)

diff --git a/lib/include/libdvbv5/dvb-fe.h b/lib/include/libdvbv5/dvb-fe.h
index ed283f29..44bf18a1 100644
--- a/lib/include/libdvbv5/dvb-fe.h
+++ b/lib/include/libdvbv5/dvb-fe.h
@@ -83,6 +83,8 @@
 
 #endif
 
+struct dvb_v5_stream_ctx;
+
 /**
  * @struct dvb_v5_fe_parms
  * @ingroup frontend
@@ -105,6 +107,7 @@
  * @param lnb			LNBf description (RW)
  * @param sat_number		Number of the satellite (used by DISEqC setup) (RW)
  * @param freq_bpf		SCR/Unicable band-pass filter frequency to use, in kHz
+ * @param stream_ctx		VB2 stream context
  * @param verbose		Verbosity level of the library (RW)
  * @param dvb_logfunc		Function used to write log messages (RO)
  * @param default_charset	Name of the charset used by the DVB standard (RW)
@@ -138,6 +141,8 @@ struct dvb_v5_fe_parms {
 	unsigned			freq_bpf;
 	unsigned			diseqc_wait;
 
+	struct dvb_v5_stream_ctx	*stream_ctx;
+
 	/* Function to write DVB logs */
 	unsigned			verbose;
 	dvb_logfunc                     logfunc;
diff --git a/lib/libdvbv5/dvb-fe-priv.h b/lib/libdvbv5/dvb-fe-priv.h
index 239c48f8..895631ed 100644
--- a/lib/libdvbv5/dvb-fe-priv.h
+++ b/lib/libdvbv5/dvb-fe-priv.h
@@ -57,7 +57,7 @@ struct dvb_v5_stats {
 struct dvb_device_priv;
 
 struct dvb_v5_fe_parms_priv {
-	/* dvbv_v4_fe_parms should be the first element on this struct */
+	/* dvbv_v5_fe_parms should be the first element on this struct */
 	struct dvb_v5_fe_parms		p;
 
 	struct dvb_device_priv		*dvb;
diff --git a/lib/libdvbv5/dvb-scan.c b/lib/libdvbv5/dvb-scan.c
index 353802a5..3f52d140 100644
--- a/lib/libdvbv5/dvb-scan.c
+++ b/lib/libdvbv5/dvb-scan.c
@@ -34,6 +34,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/mman.h>
 #include <stdlib.h>
 #include <sys/time.h>
 
@@ -46,6 +47,7 @@
 #include <libdvbv5/dvb-scan.h>
 #include <libdvbv5/dvb-log.h>
 #include <libdvbv5/dvb-demux.h>
+#include <libdvbv5/dvb-vb2.h>
 #include <libdvbv5/descriptors.h>
 #include <libdvbv5/header.h>
 #include <libdvbv5/pat.h>
@@ -79,21 +81,9 @@
 		fprintf(stderr, " (%s)\n", strerror(errno));		\
 	} while (0)
 
-
-/**Videobuf2 streaming
- * Comment VB2 macro to disable the streaming code
- */
-#define VB2
-
-#ifdef VB2
-#include <sys/mman.h>
-#include <libdvbv5/dvb-vb2.h>
 #define STREAM_BUF_CNT (4)
 #define STREAM_BUF_SIZ (DVB_MAX_PAYLOAD_PACKET_SIZE)
 
-struct dvb_v5_stream_ctx sc = {0,};
-#endif
-
 static int dvb_poll(struct dvb_v5_fe_parms_priv *parms, int fd, unsigned int seconds)
 {
 	fd_set set;
@@ -353,21 +343,22 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 	if (parms->p.verbose)
 		dvb_log(_("%s: waiting for table ID 0x%02x, program ID 0x%02x"),
 			__func__, sect->tid, sect->pid);
-#ifdef VB2
-#else
-	buf = calloc(DVB_MAX_PAYLOAD_PACKET_SIZE, 1);
-	if (!buf) {
-		dvb_logerr(_("%s: out of memory"), __func__);
-		dvb_dmx_stop(dmx_fd);
-		dvb_table_filter_free(sect);
-		return -1;
+
+	if (!parms->p.stream_ctx) {
+		buf = calloc(DVB_MAX_PAYLOAD_PACKET_SIZE, 1);
+		if (!buf) {
+			dvb_logerr(_("%s: out of memory"), __func__);
+			dvb_dmx_stop(dmx_fd);
+			dvb_table_filter_free(sect);
+			return -1;
+		}
 	}
-#endif
 
 	do {
 		int available;
 		uint32_t crc;
 		ssize_t buf_length = 0;
+		struct dmx_buffer b;
 
 		do {
 			available = dvb_poll(parms, dmx_fd, timeout);
@@ -382,23 +373,23 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 			ret = -1;
 			break;
 		}
-#ifdef VB2
-		struct dmx_buffer b;
-		memset(&b, 0, sizeof(b));
 
-		ret = dvb_v5_stream_dqbuf(&sc, &b);
-		if (ret < 0) {
-			sc.error = 1;
-			break;
+		if (parms->p.stream_ctx) {
+			memset(&b, 0, sizeof(b));
+
+			ret = dvb_v5_stream_dqbuf(parms->p.stream_ctx, &b);
+			if (ret < 0) {
+				parms->p.stream_ctx->error = 1;
+				break;
+			}
+			else {
+				parms->p.stream_ctx->buf_flag[b.index] = 0;
+				buf = parms->p.stream_ctx->buf[b.index];
+				buf_length = b.bytesused;
+			}
+		} else {
+			buf_length = read(dmx_fd, buf, DVB_MAX_PAYLOAD_PACKET_SIZE);
 		}
-		else {
-			sc.buf_flag[b.index] = 0;
-			buf = sc.buf[b.index];
-			buf_length = b.bytesused;
-		}
-#else
-		buf_length = read(dmx_fd, buf, DVB_MAX_PAYLOAD_PACKET_SIZE);
-#endif
 
 		if (!buf_length) {
 			dvb_logerr(_("%s: buf returned an empty buffer"), __func__);
@@ -419,24 +410,23 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 		}
 
 		ret = dvb_parse_section(parms, sect, buf, buf_length);
-#ifdef VB2
-		/**enqueue the buffer again*/
-		if (!ret) {
-			if (dvb_v5_stream_qbuf(&sc, b.index) < 0) {
-				sc.error = 1;
-				break;
-			}
-			else
-				sc.buf_flag[b.index] = 1;
-		}
 
-#endif
+		if (parms->p.stream_ctx) {
+			/**enqueue the buffer again*/
+			if (!ret) {
+				if (dvb_v5_stream_qbuf(parms->p.stream_ctx, b.index) < 0) {
+					parms->p.stream_ctx->error = 1;
+					break;
+				} else {
+					parms->p.stream_ctx->buf_flag[b.index] = 1;
+				}
+			}
+		}
 	} while (!ret);
 
-#ifdef VB2
-#else
-	free(buf);
-#endif
+	if (!parms->p.stream_ctx) {
+		free(buf);
+	}
 	dvb_dmx_stop(dmx_fd);
 	dvb_table_filter_free(sect);
 
@@ -514,18 +504,18 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 
 	struct dvb_v5_descriptors *dvb_scan_handler;
 
-#ifdef VB2
-	rc = dvb_v5_stream_init(&sc, dmx_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
-	if (rc < 0) {
-		PERROR("stream_init failed: error %d, %s\n",
-				errno, strerror(errno));
-		/** We don't know what failed during dvb_v5_stream_init
-		 * reqbufs, mmap or  qbuf. We will call dvb_v5_stream_deinit
-		 * to delete the mapping which might have been created
-		 */
-		goto ret_null;
+	if (parms->p.stream_ctx) {
+		rc = dvb_v5_stream_init(parms->p.stream_ctx, dmx_fd, STREAM_BUF_SIZ, STREAM_BUF_CNT);
+		if (rc < 0) {
+			PERROR("stream_init failed: error %d, %s\n",
+			       errno, strerror(errno));
+			/** We don't know what failed during dvb_v5_stream_init
+			 * reqbufs, mmap or  qbuf. We will call dvb_v5_stream_deinit
+			 * to delete the mapping which might have been created
+			 */
+			goto ret_null;
+		}
 	}
-#endif
 
 	dvb_scan_handler = dvb_scan_alloc_handler_table(delivery_system);
 	if (!dvb_scan_handler)
@@ -696,17 +686,18 @@ struct dvb_v5_descriptors *dvb_get_ts_tables(struct dvb_v5_fe_parms *__p,
 		else if (parms->p.verbose)
 			dvb_table_sdt_print(&parms->p, dvb_scan_handler->sdt);
 	}
+	return dvb_scan_handler;
 
 ret_null:
-#ifdef VB2
-	dvb_v5_stream_deinit(&sc);
-#endif
+	if (parms->p.stream_ctx) {
+		dvb_v5_stream_deinit(parms->p.stream_ctx);
+	}
 	return NULL;
 
 ret_handler:
-#ifdef VB2
-	dvb_v5_stream_deinit(&sc);
-#endif
+	if (parms->p.stream_ctx) {
+		dvb_v5_stream_deinit(parms->p.stream_ctx);
+	}
 	return dvb_scan_handler;
 }
 
diff --git a/lib/libdvbv5/dvb-vb2.c b/lib/libdvbv5/dvb-vb2.c
index 56a35f81..60e53287 100644
--- a/lib/libdvbv5/dvb-vb2.c
+++ b/lib/libdvbv5/dvb-vb2.c
@@ -269,8 +269,6 @@ void dvb_v5_stream_deinit(struct dvb_v5_stream_ctx *sc)
 		}
 
 	}
-
-	return;
 }
 
 /**
@@ -313,7 +311,6 @@ void dvb_v5_stream_to_file(int in_fd, int out_fd, int timeout, int dbg_level,
 		dvb_v5_stream_free(sc);
 		return;
 	}
-	fprintf(stderr, "start streaming!!!\n");
 	sc->out_fd = out_fd;
 
 	while (!*exit_flag  && !sc->error) {
-- 
2.47.2


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

* [PATCH 5/9] dvbv5-scan: add -R streaming option
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
                   ` (3 preceding siblings ...)
  2025-06-05 10:58 ` [PATCH 4/9] libdvbv5: prepare for vb2 stream context Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible Hans Verkuil
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

Add the --streaming/-R option to enable streaming I/O.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 utils/dvb/dvbv5-scan.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/utils/dvb/dvbv5-scan.c b/utils/dvb/dvbv5-scan.c
index c84c90fd..b4ff8fc3 100644
--- a/utils/dvb/dvbv5-scan.c
+++ b/utils/dvb/dvbv5-scan.c
@@ -48,6 +48,7 @@
 #include "libdvbv5/dvb-dev.h"
 #include "libdvbv5/dvb-v5-std.h"
 #include "libdvbv5/dvb-scan.h"
+#include "libdvbv5/dvb-vb2.h"
 #include "libdvbv5/countries.h"
 
 #define PROGRAM_NAME	"dvbv5-scan"
@@ -80,6 +81,7 @@ static const struct argp_option options[] = {
 	{"wait",	'W',	N_("time"),		0, N_("adds additional wait time for DISEqC command completion"), 0},
 	{"nit",		'N',	NULL,			0, N_("use data from NIT table on the output file"), 0},
 	{"get_frontend",'G',	NULL,			0, N_("use data from get_frontend on the output file"), 0},
+	{"streaming",	'R',	NULL,			0, N_("uses streaming I/O"), 0},
 	{"verbose",	'v',	NULL,			0, N_("be (very) verbose"), 0},
 	{"output",	'o',	N_("file"),		0, N_("output filename (default: ") DEFAULT_OUTPUT ")", 0},
 	{"file-freqs-only", 'F', NULL,			0, N_("don't use the other frequencies discovered during scan"), 0},
@@ -95,6 +97,7 @@ static const struct argp_option options[] = {
 };
 
 static int verbose = 0;
+static int streaming = 0;
 #define CHANNEL_FILE "channels.conf"
 
 #define ERROR(x...)                                                     \
@@ -394,6 +397,9 @@ static error_t parse_opt(int k, char *optarg, struct argp_state *state)
 	case 'p':
 		args->other_nit++;
 		break;
+	case 'R':
+		streaming++;
+		break;
 	case 'v':
 		verbose++;
 		break;
@@ -521,6 +527,9 @@ int main(int argc, char **argv)
 	dvb_dev_set_log(dvb, verbose, NULL);
 	dvb_dev_find(dvb, NULL, NULL);
 	parms = dvb->fe_parms;
+	if (streaming) {
+		parms->stream_ctx = dvb_v5_stream_alloc();
+	}
 
 	dvb_dev = dvb_dev_seek_by_adapter(dvb, args.adapter_dmx, args.demux, DVB_DEVICE_DEMUX);
 	if (!dvb_dev) {
@@ -559,6 +568,10 @@ int main(int argc, char **argv)
 
 	err = run_scan(&args, dvb);
 
+	if (streaming) {
+		dvb_v5_stream_free(parms->stream_ctx);
+		parms->stream_ctx = NULL;
+	}
 	dvb_dev_free(dvb);
 
 	return err;
-- 
2.47.2


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

* [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
                   ` (4 preceding siblings ...)
  2025-06-05 10:58 ` [PATCH 5/9] dvbv5-scan: add -R streaming option Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 12:18   ` Mauro Carvalho Chehab
  2025-06-05 10:58 ` [PATCH 7/9] libdvbv5/dvb-scan: always requeue after dvb_parse_section Hans Verkuil
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

Several systems support DTV_BANDWIDTH_HZ, add it.

This fixes a dvbv5-scan error message about missing support for
DTV_BANDWIDTH_HZ.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/libdvbv5/dvb-v5-std.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/libdvbv5/dvb-v5-std.c b/lib/libdvbv5/dvb-v5-std.c
index c0a14175..74e2e4fe 100644
--- a/lib/libdvbv5/dvb-v5-std.c
+++ b/lib/libdvbv5/dvb-v5-std.c
@@ -81,6 +81,7 @@ const unsigned int sys_isdbt_props[] = {
 const unsigned int sys_atsc_props[] = {
 	DTV_FREQUENCY,
 	DTV_MODULATION,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
@@ -111,12 +112,14 @@ const unsigned int sys_dvbc_annex_ac_props[] = {
 	DTV_INVERSION,
 	DTV_SYMBOL_RATE,
 	DTV_INNER_FEC,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
 const unsigned int sys_dvbc_annex_b_props[] = {
 	DTV_FREQUENCY,
 	DTV_MODULATION,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
@@ -126,6 +129,7 @@ const unsigned int sys_dvbs_props[] = {
 	DTV_SYMBOL_RATE,
 	DTV_INNER_FEC,
 	DTV_POLARIZATION,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
@@ -139,6 +143,7 @@ const unsigned int sys_dvbs2_props[] = {
 	DTV_ROLLOFF,
 	DTV_POLARIZATION,
 	DTV_STREAM_ID,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
@@ -149,12 +154,14 @@ const unsigned int sys_turbo_props[] = {
 	DTV_INNER_FEC,
 	DTV_MODULATION,
 	DTV_POLARIZATION,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
 const unsigned int sys_isdbs_props[] = {
 	DTV_FREQUENCY,
 	DTV_STREAM_ID,
+	DTV_BANDWIDTH_HZ,
 	0
 };
 
-- 
2.47.2


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

* [PATCH 7/9] libdvbv5/dvb-scan: always requeue after dvb_parse_section
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
                   ` (5 preceding siblings ...)
  2025-06-05 10:58 ` [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 8/9] libdvbv5/dvb-scan: flush any pending bufs after dvb_dmx_stop Hans Verkuil
  2025-06-05 10:58 ` [PATCH 9/9] test-media: add initial vidtv streaming test Hans Verkuil
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

Even if dvb_parse_section returns non-zero, you still need to requeue the buffer.
Otherwise it will effectively be lost.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/libdvbv5/dvb-scan.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/lib/libdvbv5/dvb-scan.c b/lib/libdvbv5/dvb-scan.c
index 3f52d140..afe3a4f0 100644
--- a/lib/libdvbv5/dvb-scan.c
+++ b/lib/libdvbv5/dvb-scan.c
@@ -412,14 +412,12 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 		ret = dvb_parse_section(parms, sect, buf, buf_length);
 
 		if (parms->p.stream_ctx) {
-			/**enqueue the buffer again*/
-			if (!ret) {
-				if (dvb_v5_stream_qbuf(parms->p.stream_ctx, b.index) < 0) {
-					parms->p.stream_ctx->error = 1;
-					break;
-				} else {
-					parms->p.stream_ctx->buf_flag[b.index] = 1;
-				}
+			/* enqueue the buffer again */
+			if (dvb_v5_stream_qbuf(parms->p.stream_ctx, b.index) < 0) {
+				parms->p.stream_ctx->error = 1;
+				break;
+			} else {
+				parms->p.stream_ctx->buf_flag[b.index] = 1;
 			}
 		}
 	} while (!ret);
-- 
2.47.2


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

* [PATCH 8/9] libdvbv5/dvb-scan: flush any pending bufs after dvb_dmx_stop
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
                   ` (6 preceding siblings ...)
  2025-06-05 10:58 ` [PATCH 7/9] libdvbv5/dvb-scan: always requeue after dvb_parse_section Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  2025-06-05 10:58 ` [PATCH 9/9] test-media: add initial vidtv streaming test Hans Verkuil
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

After dvb_dmx_stop() is called, and we are using streaming I/O, then
flush any pending buffers. If we don't do that, then those buffers
will be dequeued next time we enter dvb_read_sections.

If you are not using streaming I/O, then this isn't needed since
the kernel will clear all pending data from the read() buffer when
DMX_STOP is called. But for streaming I/O those buffers are already
queued up for the application.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 lib/libdvbv5/dvb-scan.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/libdvbv5/dvb-scan.c b/lib/libdvbv5/dvb-scan.c
index afe3a4f0..f07b1306 100644
--- a/lib/libdvbv5/dvb-scan.c
+++ b/lib/libdvbv5/dvb-scan.c
@@ -427,6 +427,15 @@ int dvb_read_sections(struct dvb_v5_fe_parms *__p, int dmx_fd,
 	}
 	dvb_dmx_stop(dmx_fd);
 	dvb_table_filter_free(sect);
+	if (parms->p.stream_ctx) {
+		/* Flush pending buffers */
+		while (dvb_poll(parms, dmx_fd, 0) > 0) {
+			struct dmx_buffer b;
+			if (dvb_v5_stream_dqbuf(parms->p.stream_ctx, &b) >= 0) {
+				dvb_v5_stream_qbuf(parms->p.stream_ctx, b.index);
+			}
+		}
+	}
 
 	if (ret > 0)
 		ret = 0;
-- 
2.47.2


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

* [PATCH 9/9] test-media: add initial vidtv streaming test
  2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
                   ` (7 preceding siblings ...)
  2025-06-05 10:58 ` [PATCH 8/9] libdvbv5/dvb-scan: flush any pending bufs after dvb_dmx_stop Hans Verkuil
@ 2025-06-05 10:58 ` Hans Verkuil
  8 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 10:58 UTC (permalink / raw)
  To: linux-media; +Cc: Mauro Carvalho Chehab, Hans Verkuil

Add a test to check that streaming I/O works for vidtv.

It would be nice if we could also compare the TS data, but this
contains timestamps, so it is always different each time you run
it. It would be nice if vidtv would have a module option to
enforce fixed timestamps.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 contrib/test/test-media | 50 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/contrib/test/test-media b/contrib/test/test-media
index 80315dba..a1d8a10c 100755
--- a/contrib/test/test-media
+++ b/contrib/test/test-media
@@ -21,6 +21,7 @@ reunbind_time=9
 rmmod_time=1
 modprobe_time=3
 kobj_rel=0
+dvb_mmap=0
 v4l2_ctl=v4l2-ctl
 v4l2_compliance=v4l2-compliance
 compliance_args=
@@ -37,6 +38,9 @@ if [ -f /proc/config.gz ]; then
 	if cat /proc/config.gz | gunzip |grep -q CONFIG_DEBUG_KOBJECT_RELEASE=y ; then
 		kobj_rel=1
 	fi
+	if cat /proc/config.gz | gunzip |grep -q CONFIG_DVB_MMAP=y ; then
+		dvb_mmap=1
+	fi
 elif [ -f .config ]; then
 	if grep -q CONFIG_DEBUG_KOBJECT_RELEASE=y .config ; then
 		kobj_rel=1
@@ -886,6 +890,14 @@ if [ $vidtv -eq 1 ]; then
 		rmmod dvb_vidtv_bridge dvb_vidtv_tuner dvb_vidtv_demod 2&>/dev/null
 		exit 0
 	fi
+
+	if [ $setup -eq 0 ]; then
+		tmpdir=`mktemp -d`
+	else
+		tmpdir=/tmp/vidtv-test
+		rm -rf $tmpdir
+		mkdir $tmpdir
+	fi
 fi
 
 if [ $vidtv -eq 1 -a $setup -eq 0 ]; then
@@ -895,6 +907,44 @@ if [ $vidtv -eq 1 -a $setup -eq 0 ]; then
 	date
 	stdbuf -oL $v4l2_compliance -m platform:vidtv 2>&1 | tee -a $tmp
 
+	echo
+	echo vidtv scan tests | tee /dev/kmsg
+	echo
+	date
+	cat >$tmpdir/vidtv-channel.conf <<EOF
+[Channel]
+FREQUENCY = 474000000
+MODULATION = QAM/AUTO
+SYMBOL_RATE = 6940000
+INNER_FEC = AUTO
+DELIVERY_SYSTEM = DVBC/ANNEX_A
+EOF
+
+	dvbv5-scan $tmpdir/vidtv-channel.conf -o $tmpdir/dvb_channel.conf
+	if [ $dvb_mmap -eq 1 ]; then
+		dvbv5-scan -R $tmpdir/vidtv-channel.conf -o $tmpdir/dvb_channel-vb2.conf
+		vidtv_ok=0
+		vidtv_fail=0
+		if cmp $tmpdir/dvb_channel.conf $tmpdir/dvb_channel-vb2.conf; then
+			echo "OK: dvbv5-scan results are identical for read and streaming" | tee -a $tmp
+			vidtv_ok=1
+		else
+			diff -u $tmpdir/dvb_channel.conf $tmpdir/dvb_channel-vb2.conf
+			echo "FAIL: dvbv5-scan results differ for read and streaming" | tee -a $tmp
+			vidtv_fail=1
+		fi
+		echo Total for vidtv dvbv5-scan cmp tests: 1, Succeeded: $vidtv_ok, Failed: $vidtv_fail, Warnings: 0 | tee -a $tmp
+	fi
+
+	echo
+	echo vidtv stream tests | tee /dev/kmsg
+	echo
+	date
+	dvbv5-zap -c $tmpdir/dvb_channel.conf "Beethoven" -o $tmpdir/music.ts -P -t 10
+	if [ $dvb_mmap -eq 1 ]; then
+		dvbv5-zap -R -c $tmpdir/dvb_channel.conf "Beethoven" -o $tmpdir/music-vb2.ts -P -t 10
+	fi
+	rm -rf $tmpdir
 	echo
 	echo
 	echo
-- 
2.47.2


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

* Re: [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible
  2025-06-05 10:58 ` [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible Hans Verkuil
@ 2025-06-05 12:18   ` Mauro Carvalho Chehab
  2025-06-05 12:55     ` Hans Verkuil
  0 siblings, 1 reply; 12+ messages in thread
From: Mauro Carvalho Chehab @ 2025-06-05 12:18 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Mauro Carvalho Chehab

Em Thu,  5 Jun 2025 12:58:29 +0200
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> Several systems support DTV_BANDWIDTH_HZ, add it.
> 
> This fixes a dvbv5-scan error message about missing support for
> DTV_BANDWIDTH_HZ.
> 
> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
> ---
>  lib/libdvbv5/dvb-v5-std.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/lib/libdvbv5/dvb-v5-std.c b/lib/libdvbv5/dvb-v5-std.c
> index c0a14175..74e2e4fe 100644
> --- a/lib/libdvbv5/dvb-v5-std.c
> +++ b/lib/libdvbv5/dvb-v5-std.c
> @@ -81,6 +81,7 @@ const unsigned int sys_isdbt_props[] = {
>  const unsigned int sys_atsc_props[] = {
>  	DTV_FREQUENCY,
>  	DTV_MODULATION,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };

Indeed, ISDB-T could have a bandwidth. In the beginning, only
Japan and Brazil were using it, with a 6MHz bandwidth. As far as
I remember, all drivers we currently have are for devices with
such limit. Yet, the spec allows other bandwidths as well. Not sure
if any Country is using a different bandwidth in practice, though.

> @@ -111,12 +112,14 @@ const unsigned int sys_dvbc_annex_ac_props[] = {
>  	DTV_INVERSION,
>  	DTV_SYMBOL_RATE,
>  	DTV_INNER_FEC,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };
>  
>  const unsigned int sys_dvbc_annex_b_props[] = {
>  	DTV_FREQUENCY,
>  	DTV_MODULATION,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };
>  
> @@ -126,6 +129,7 @@ const unsigned int sys_dvbs_props[] = {
>  	DTV_SYMBOL_RATE,
>  	DTV_INNER_FEC,
>  	DTV_POLARIZATION,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };
>  
> @@ -139,6 +143,7 @@ const unsigned int sys_dvbs2_props[] = {
>  	DTV_ROLLOFF,
>  	DTV_POLARIZATION,
>  	DTV_STREAM_ID,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };
>  
> @@ -149,12 +154,14 @@ const unsigned int sys_turbo_props[] = {
>  	DTV_INNER_FEC,
>  	DTV_MODULATION,
>  	DTV_POLARIZATION,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };
>  
>  const unsigned int sys_isdbs_props[] = {
>  	DTV_FREQUENCY,
>  	DTV_STREAM_ID,
> +	DTV_BANDWIDTH_HZ,
>  	0
>  };

The above are not right: Satellite and Cable don't use bandwidth.
Instead, the bandwidth is indirectly calculated from the symbol
rate and rolloff, using something like this:

	float rolloff = 1.35;	/* DVB-S rolloff */

	int bandwidth_hz = int(symbol_rate * rolloff);



For DVB-C Annex A and B, and for DVB-S (and, afaikt, for DVB-TURBO), the
rolloff is fixed. DVB-S2 is the only one that supports different
rolloff factors.

In any case, DVB core calculates it. See this code snippet:

        switch (c->delivery_system) {
        case SYS_ATSC:
        case SYS_DVBC_ANNEX_B:
                c->bandwidth_hz = 6000000;
                break;
        case SYS_DVBC_ANNEX_A:
                rolloff = 115;
                break;
        case SYS_DVBC_ANNEX_C:
                rolloff = 113;
                break;
        case SYS_DSS:
                rolloff = 120;
                break;
        case SYS_DVBS:
        case SYS_TURBO:
        case SYS_ISDBS:
                rolloff = 135;
                break;
        case SYS_DVBS2:
                switch (c->rolloff) {
                case ROLLOFF_20:
                        rolloff = 120;
                        break;
                case ROLLOFF_25:
                        rolloff = 125;
                        break;
                default:
                case ROLLOFF_35:
                        rolloff = 135;
                }
                break;
        default:
                break;
        }
        if (rolloff)
                c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100);

The Kernel calculates the bandwidth and may return it, but the opposite
is not true: any set operation for a TV standard that has DTV_SYMBOL_RATE
will simply discard/ignore what is there at DTV_BANDWIDTH_HZ.

Currently, the logic inside libdvbv5 assumes that all parameters are
read/write.

Thanks,
Mauro

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

* Re: [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible
  2025-06-05 12:18   ` Mauro Carvalho Chehab
@ 2025-06-05 12:55     ` Hans Verkuil
  0 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2025-06-05 12:55 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media, Mauro Carvalho Chehab

On 6/5/25 14:18, Mauro Carvalho Chehab wrote:
> Em Thu,  5 Jun 2025 12:58:29 +0200
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> Several systems support DTV_BANDWIDTH_HZ, add it.
>>
>> This fixes a dvbv5-scan error message about missing support for
>> DTV_BANDWIDTH_HZ.
>>
>> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
>> ---
>>  lib/libdvbv5/dvb-v5-std.c | 7 +++++++
>>  1 file changed, 7 insertions(+)
>>
>> diff --git a/lib/libdvbv5/dvb-v5-std.c b/lib/libdvbv5/dvb-v5-std.c
>> index c0a14175..74e2e4fe 100644
>> --- a/lib/libdvbv5/dvb-v5-std.c
>> +++ b/lib/libdvbv5/dvb-v5-std.c
>> @@ -81,6 +81,7 @@ const unsigned int sys_isdbt_props[] = {
>>  const unsigned int sys_atsc_props[] = {
>>  	DTV_FREQUENCY,
>>  	DTV_MODULATION,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
> 
> Indeed, ISDB-T could have a bandwidth. In the beginning, only
> Japan and Brazil were using it, with a 6MHz bandwidth. As far as
> I remember, all drivers we currently have are for devices with
> such limit. Yet, the spec allows other bandwidths as well. Not sure
> if any Country is using a different bandwidth in practice, though.
> 
>> @@ -111,12 +112,14 @@ const unsigned int sys_dvbc_annex_ac_props[] = {
>>  	DTV_INVERSION,
>>  	DTV_SYMBOL_RATE,
>>  	DTV_INNER_FEC,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
>>  
>>  const unsigned int sys_dvbc_annex_b_props[] = {
>>  	DTV_FREQUENCY,
>>  	DTV_MODULATION,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
>>  
>> @@ -126,6 +129,7 @@ const unsigned int sys_dvbs_props[] = {
>>  	DTV_SYMBOL_RATE,
>>  	DTV_INNER_FEC,
>>  	DTV_POLARIZATION,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
>>  
>> @@ -139,6 +143,7 @@ const unsigned int sys_dvbs2_props[] = {
>>  	DTV_ROLLOFF,
>>  	DTV_POLARIZATION,
>>  	DTV_STREAM_ID,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
>>  
>> @@ -149,12 +154,14 @@ const unsigned int sys_turbo_props[] = {
>>  	DTV_INNER_FEC,
>>  	DTV_MODULATION,
>>  	DTV_POLARIZATION,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
>>  
>>  const unsigned int sys_isdbs_props[] = {
>>  	DTV_FREQUENCY,
>>  	DTV_STREAM_ID,
>> +	DTV_BANDWIDTH_HZ,
>>  	0
>>  };
> 
> The above are not right: Satellite and Cable don't use bandwidth.
> Instead, the bandwidth is indirectly calculated from the symbol
> rate and rolloff, using something like this:
> 
> 	float rolloff = 1.35;	/* DVB-S rolloff */
> 
> 	int bandwidth_hz = int(symbol_rate * rolloff);
> 
> 
> 
> For DVB-C Annex A and B, and for DVB-S (and, afaikt, for DVB-TURBO), the
> rolloff is fixed. DVB-S2 is the only one that supports different
> rolloff factors.
> 
> In any case, DVB core calculates it. See this code snippet:
> 
>         switch (c->delivery_system) {
>         case SYS_ATSC:
>         case SYS_DVBC_ANNEX_B:
>                 c->bandwidth_hz = 6000000;
>                 break;
>         case SYS_DVBC_ANNEX_A:
>                 rolloff = 115;
>                 break;
>         case SYS_DVBC_ANNEX_C:
>                 rolloff = 113;
>                 break;
>         case SYS_DSS:
>                 rolloff = 120;
>                 break;
>         case SYS_DVBS:
>         case SYS_TURBO:
>         case SYS_ISDBS:
>                 rolloff = 135;
>                 break;
>         case SYS_DVBS2:
>                 switch (c->rolloff) {
>                 case ROLLOFF_20:
>                         rolloff = 120;
>                         break;
>                 case ROLLOFF_25:
>                         rolloff = 125;
>                         break;
>                 default:
>                 case ROLLOFF_35:
>                         rolloff = 135;
>                 }
>                 break;
>         default:
>                 break;
>         }
>         if (rolloff)
>                 c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100);
> 
> The Kernel calculates the bandwidth and may return it, but the opposite
> is not true: any set operation for a TV standard that has DTV_SYMBOL_RATE
> will simply discard/ignore what is there at DTV_BANDWIDTH_HZ.
> 
> Currently, the logic inside libdvbv5 assumes that all parameters are
> read/write.

The issue I tried to fix is that dvbv5-scan complains about BANDWIDTH_HZ
being missing for DVB-C Annex A:

ERROR    command BANDWIDTH_HZ (5) not found during retrieve

Should this message just be suppressed in dvbv5-scan?

I'm not really sure what the best approach is, this isn't my area of
expertise...

Regards,

	Hans

> 
> Thanks,
> Mauro


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

end of thread, other threads:[~2025-06-05 12:55 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-05 10:58 [PATCH 0/9] v4l-utils: dvb: add streaming support Hans Verkuil
2025-06-05 10:58 ` [PATCH 1/9] dvbv5: streaming support using videobuf2 for DVR and auto-scan Hans Verkuil
2025-06-05 10:58 ` [PATCH 2/9] dvbv5: use proper dvb_v5 namespace Hans Verkuil
2025-06-05 10:58 ` [PATCH 3/9] dvb-vb2: add dvb_v5_stream_alloc/free Hans Verkuil
2025-06-05 10:58 ` [PATCH 4/9] libdvbv5: prepare for vb2 stream context Hans Verkuil
2025-06-05 10:58 ` [PATCH 5/9] dvbv5-scan: add -R streaming option Hans Verkuil
2025-06-05 10:58 ` [PATCH 6/9] libdvbv5/dvb-v5-std.c: add DTV_BANDWIDTH_HZ where possible Hans Verkuil
2025-06-05 12:18   ` Mauro Carvalho Chehab
2025-06-05 12:55     ` Hans Verkuil
2025-06-05 10:58 ` [PATCH 7/9] libdvbv5/dvb-scan: always requeue after dvb_parse_section Hans Verkuil
2025-06-05 10:58 ` [PATCH 8/9] libdvbv5/dvb-scan: flush any pending bufs after dvb_dmx_stop Hans Verkuil
2025-06-05 10:58 ` [PATCH 9/9] test-media: add initial vidtv streaming test Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).