[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