[vlc-devel] [PATCH 1/1] Added segments : an access_output module that saves MPEG-TS packets into files
Jérémy VIGNELLES
jeremy.vignelles at dev3i.fr
Thu Oct 12 11:17:01 CEST 2017
---
modules/MODULES_LIST | 1 +
modules/access_output/Makefile.am | 2 +
modules/access_output/segments.c | 257 ++++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
4 files changed, 261 insertions(+)
create mode 100644 modules/access_output/segments.c
diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index b896aa183b..e47f61642c 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -352,6 +352,7 @@ $Id$
* sdp: SDP fake access
* secret: store secrets via Gnome libsecret
* securetransport: TLS module for OS X and iOS
+ * segments: output to multiple MPEG-TS files
* sepia: Sepia video filter
* sftp: SFTP network access module
* sharpen: Sharpen video filter
diff --git a/modules/access_output/Makefile.am b/modules/access_output/Makefile.am
index bc954ee03b..353a35f297 100644
--- a/modules/access_output/Makefile.am
+++ b/modules/access_output/Makefile.am
@@ -4,6 +4,7 @@ libaccess_output_dummy_plugin_la_SOURCES = access_output/dummy.c
libaccess_output_file_plugin_la_SOURCES = access_output/file.c
libaccess_output_file_plugin_la_LIBADD = $(LIBPTHREAD)
libaccess_output_http_plugin_la_SOURCES = access_output/http.c
+libaccess_output_segments_plugin_la_SOURCES = access_output/segments.c
libaccess_output_udp_plugin_la_SOURCES = access_output/udp.c
libaccess_output_udp_plugin_la_LIBADD = $(SOCKET_LIBS) $(LIBPTHREAD)
@@ -11,6 +12,7 @@ access_out_LTLIBRARIES = \
libaccess_output_dummy_plugin.la \
libaccess_output_file_plugin.la \
libaccess_output_http_plugin.la \
+ libaccess_output_segments_plugin.la \
libaccess_output_udp_plugin.la
libaccess_output_livehttp_plugin_la_SOURCES = access_output/livehttp.c
diff --git a/modules/access_output/segments.c b/modules/access_output/segments.c
new file mode 100644
index 0000000000..b7ac2142ac
--- /dev/null
+++ b/modules/access_output/segments.c
@@ -0,0 +1,257 @@
+/*****************************************************************************
+ * segments.c
+ *****************************************************************************
+ * Copyright (C) 2017 VLC authors and VideoLAN
+ *
+ * Authors: Jérémy VIGNELLES <jeremy.vignelles at dev3i.fr>
+ *
+ * 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, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <limits.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_sout.h>
+#include <vlc_block.h>
+#include <vlc_fs.h>
+#include <vlc_strings.h>
+
+#ifndef O_LARGEFILE
+# define O_LARGEFILE 0
+#endif
+
+#define FORMAT_TEXT N_("File name pattern")
+#define FORMAT_LONGTEXT N_("Perform ISO C time and date formatting " \
+ "on the file path using strftime")
+
+// Default max file size = 94 MB, which is a round number of TS blocks (188 bytes each)
+#define DEFAULT_MAX_FILE_SIZE 98566144
+#define FILE_SIZE_TEXT N_("Maximum file size")
+#define FILE_SIZE_LONGTEXT N_("Maximum size, in bytes, of the output files.")
+
+struct sout_access_out_sys_t {
+ DIR* outputDirectory;
+ char* fileFormat;
+ int currentfd;
+ ssize_t currentFilePosition;
+ uint64_t maxFileSize;
+};
+
+#define SOUT_CFG_PREFIX "sout-segments-"
+
+/*****************************************************************************
+ * Write: standard write on a file descriptor.
+ *****************************************************************************/
+static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
+{
+ size_t i_write = 0;
+
+ while( p_buffer )
+ {
+ if(p_access->p_sys->currentfd == -1 || p_access->p_sys->currentFilePosition + p_buffer->i_buffer > p_access->p_sys->maxFileSize)
+ {
+ if(p_access->p_sys->currentfd != -1)
+ {
+ vlc_close(p_access->p_sys->currentfd);
+ p_access->p_sys->currentfd = -1;
+ }
+
+ char *fileName = vlc_strftime (p_access->p_sys->fileFormat);
+ char path[PATH_MAX];
+
+ if (snprintf(path, PATH_MAX, "%s"DIR_SEP"%s", p_access->psz_path, fileName) >= PATH_MAX)
+ {
+ block_ChainRelease (p_buffer);
+ msg_Err(p_access, "Unable to build path : the path is limited to %d bytes", PATH_MAX);
+ free(fileName);
+ return -1;
+ }
+
+ msg_Dbg(p_access, "Switching file. New file will be : %s", path);
+ p_access->p_sys->currentfd = vlc_open(path, O_RDWR | O_CREAT | O_LARGEFILE | O_TRUNC, 0666);
+ p_access->p_sys->currentFilePosition = 0;
+
+ free(fileName);
+
+ if(p_access->p_sys->currentfd == -1)
+ {
+ block_ChainRelease (p_buffer);
+ msg_Err(p_access, "Failed to create output file : %s", vlc_strerror_c(errno));
+ return -1;
+ }
+ }
+
+ ssize_t val = write (p_access->p_sys->currentfd, p_buffer->p_buffer, p_buffer->i_buffer);
+ if (val <= 0)
+ {
+ if (errno == EINTR) {
+ // Interrupted, retry writing the same block
+ continue;
+ }
+ block_ChainRelease (p_buffer);
+ msg_Err( p_access, "cannot write: %s", vlc_strerror_c(errno) );
+ return -1;
+ }
+
+ if ((size_t)val >= p_buffer->i_buffer)
+ {
+ block_t *p_next = p_buffer->p_next;
+ block_Release (p_buffer);
+ p_buffer = p_next;
+ }
+ else
+ {
+ p_buffer->p_buffer += val;
+ p_buffer->i_buffer -= val;
+ }
+ p_access->p_sys->currentFilePosition += val;
+ i_write += val;
+ }
+ return i_write;
+}
+
+static int Control( sout_access_out_t *p_access, int i_query, va_list args )
+{
+ VLC_UNUSED(p_access);
+ switch( i_query )
+ {
+ case ACCESS_OUT_CONTROLS_PACE:
+ {
+ bool *pb = va_arg( args, bool*);
+ *pb = false;
+ break;
+ }
+
+ case ACCESS_OUT_CAN_SEEK:
+ {
+ bool *pb = va_arg( args, bool*);
+ *pb = false;
+ break;
+ }
+
+ default:
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
+}
+
+static const char *const ppsz_sout_options[] = {
+ "format",
+ "max-filesize",
+ NULL
+};
+
+/*****************************************************************************
+ * Open: open the file
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+ sout_access_out_t *p_access = (sout_access_out_t*)p_this;
+
+ config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
+
+ if( !p_access->psz_path )
+ {
+ msg_Err( p_access, "no output directory specified" );
+ return VLC_EGENERIC;
+ }
+
+ int64_t maxFileSize = var_GetInteger(p_access, SOUT_CFG_PREFIX"max-filesize");
+ if(maxFileSize < 188)
+ {
+ msg_Err(p_access, "The file size must not be under 188 bytes long (= TS block size)");
+ return VLC_EGENERIC;
+ }
+
+ DIR *dir = vlc_opendir(p_access->psz_path);
+ if(dir == NULL)
+ {
+ msg_Err(p_access, "Cannot open directory `%s' (%s)", p_access->psz_path, vlc_strerror_c(errno));
+ return VLC_EGENERIC;
+ }
+
+ char* format = var_GetNonEmptyString (p_access, SOUT_CFG_PREFIX"format");
+ if(format == NULL)
+ {
+ closedir(dir);
+ msg_Err(p_access, "No file format specified");
+ return VLC_EGENERIC;
+ }
+
+ sout_access_out_sys_t *p_sys = malloc(sizeof(*p_sys));
+
+ p_sys->outputDirectory = dir;
+ p_sys->fileFormat = format;
+ p_sys->maxFileSize = (uint64_t)maxFileSize;
+ p_sys->currentfd = -1;
+
+ p_access->pf_write = Write;
+ p_access->pf_control = Control;
+ p_access->p_sys = p_sys;
+
+ msg_Dbg( p_access, "segments access output opened in folder : %s", p_access->psz_path );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: close the target
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+ sout_access_out_t *p_access = (sout_access_out_t*)p_this;
+
+ if(p_access->p_sys != NULL) {
+ if (p_access->p_sys->currentfd != -1)
+ {
+ vlc_close(p_access->p_sys->currentfd);
+ }
+
+ if (p_access->p_sys->outputDirectory != NULL) {
+ closedir(p_access->p_sys->outputDirectory);
+ }
+
+ if (p_access->p_sys->fileFormat != NULL) {
+ free(p_access->p_sys->fileFormat);
+ }
+
+ free(p_access->p_sys);
+ }
+
+ msg_Dbg( p_access, "segments access output closed" );
+}
+
+vlc_module_begin ()
+ set_description( N_("output to multiple MPEG-TS files. Requires `ts` as muxer.") )
+ set_shortname( N_("segments" ))
+ set_capability( "sout access", 0 )
+ set_category( CAT_SOUT )
+ set_subcategory( SUBCAT_SOUT_ACO )
+ add_shortcut( "segments" )
+ set_callbacks( Open, Close )
+ add_string( SOUT_CFG_PREFIX "format", "", FORMAT_TEXT, FORMAT_LONGTEXT, false )
+ add_integer_with_range( SOUT_CFG_PREFIX "max-filesize", DEFAULT_MAX_FILE_SIZE, 188, LLONG_MAX, FILE_SIZE_TEXT, FILE_SIZE_LONGTEXT, false )
+vlc_module_end ()
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5b4c5cbfc0..bfdbcab2ea 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -220,6 +220,7 @@ modules/access_output/dummy.c
modules/access_output/file.c
modules/access_output/http.c
modules/access_output/livehttp.c
+modules/access_output/segments.c
modules/access_output/shout.c
modules/access_output/udp.c
modules/access/pulse.c
--
2.11.0
More information about the vlc-devel
mailing list