[vlc-devel] [RFC PATCH 1/3] libvlc: add stream API

Thomas Guillem thomas at gllm.fr
Tue May 24 16:01:34 CEST 2016


Add a low level API that open and read streams via VLC accesses. This can be
useful to dump simple streams that are handled by VLC like smb,nfs,http,ftp...
Threading and locking must be handled by the caller of the API.

Maybe this should be called libvlc_access to respect VLC core naming scheme.

TODO: libvlc_stream_interrupt() is not yet tested.
---
 include/vlc/libvlc_stream.h | 161 ++++++++++++++++++++++++++++
 include/vlc/vlc.h           |   1 +
 lib/Makefile.am             |   2 +
 lib/libvlc.sym              |  10 ++
 lib/stream.c                | 250 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 424 insertions(+)
 create mode 100644 include/vlc/libvlc_stream.h
 create mode 100644 lib/stream.c

diff --git a/include/vlc/libvlc_stream.h b/include/vlc/libvlc_stream.h
new file mode 100644
index 0000000..d02b244
--- /dev/null
+++ b/include/vlc/libvlc_stream.h
@@ -0,0 +1,161 @@
+/*****************************************************************************
+ * libvlc_stream.h: stream API
+ *****************************************************************************
+ * Copyright © 2016 VLC authors and VideoLAN
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef LIBVLC_STREAM_H
+#define LIBVLC_STREAM_H 1
+
+#include <stdbool.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/**
+ * @defgroup libvlc_stream LibVLC stream
+ * @ingroup libvlc
+ * @{
+ * @file
+ * LibVLC stream external API
+ */
+
+typedef struct libvlc_stream_t libvlc_stream_t;
+
+/**
+ * Create a stream
+ *
+ * @note The libvlc_stream API is reentrant but not thread safe. Only the
+ * libvlc_stream_interrupt() function can be called while a libvlc_stream
+ * function is executing. Call libvlc_stream_open_input() to open an input
+ * stream.
+ *
+ * @version LibVLC 3.0.0 and later
+ *
+ * @param p_instance the libvlc instance
+ * @return the newly created stream or NULL on error (to be released with
+ * libvlc_stream_release())
+ */
+LIBVLC_API libvlc_stream_t *
+libvlc_stream_new(libvlc_instance_t *p_instance);
+
+/**
+ * Release a stream
+ *
+ * @note This will stop the stream if it's not previously stopped
+ *
+ * @version LibVLC 3.0.0 and later
+ */
+LIBVLC_API void
+libvlc_stream_release(libvlc_stream_t *p_stream);
+
+/**
+ * Interrupt a stream operation
+ *
+ * The typical use of this function is to interrupt a thread that is blocked in
+ * a libvlc_stream function. The interrupted function will return immediately
+ * with an error code (-1).
+ *
+ * @note This function can be called while a libvlc_stream is executing, but
+ * not during libvlc_stream_release().
+ * 
+ * @version LibVLC 3.0.0 and later
+ */
+LIBVLC_API void
+libvlc_stream_interrupt(libvlc_stream_t *p_stream);
+
+/**
+ * Open an input stream
+ *
+ * @version LibVLC 3.0.0 and later
+ *
+ * @param psz_mrl the stream location
+ * @return 0 on success, -1 on error
+ */
+LIBVLC_API int
+libvlc_stream_open_input(libvlc_stream_t *p_stream, const char * psz_mrl);
+
+/**
+ * Close an input stream
+ *
+ * @version LibVLC 3.0.0 and later
+ */
+LIBVLC_API void
+libvlc_stream_close(libvlc_stream_t *p_stream);
+
+/**
+ * Read bytes from an input stream
+ *
+ * @version LibVLC 3.0.0 and later
+ *
+ * @param p_buf allocated buffer where to read the stream
+ * @param i_len number of bytes to read
+ * @return number of bytes read, or 0 at eos, or -1 in case of error
+ */
+LIBVLC_API ssize_t
+libvlc_stream_read(libvlc_stream_t *p_stream, void *p_buf, size_t i_len);
+
+/**
+ * Reposition the stream offset
+ *
+ * @version LibVLC 3.0.0 and later
+ *
+ * @param i_offset absolute position
+ * @return 0 on success, -1 on error
+ */
+LIBVLC_API int
+libvlc_stream_seekto(libvlc_stream_t *p_stream, uint64_t i_offset);
+
+/**
+ * Get the current stream position
+ *
+ * @version LibVLC 3.0.0 and later
+ *
+ * @param p_offset pointer to an absolute position
+ * @return 0 on success, -1 on error
+ */
+LIBVLC_API int
+libvlc_stream_tell(libvlc_stream_t *p_stream, uint64_t *p_offset);
+
+/**
+ * Tell if the stream is at the end (end of file or EOF)
+ *
+ * @version LibVLC 3.0.0 and later
+ * @return true if the stream is at the end
+ */
+LIBVLC_API bool
+libvlc_stream_eos(libvlc_stream_t *p_stream);
+
+/**
+ * Get the size of the stream
+ *
+ * @version LibVLC 3.0.0 and later
+ *
+ * @param p_size pointer to the size
+ * @return 0 if the size could be fetch
+ */
+LIBVLC_API int
+libvlc_stream_size(libvlc_stream_t *p_stream, uint64_t *p_size);
+
+/** @} */
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* LIBVLC_STREAM_H */
diff --git a/include/vlc/vlc.h b/include/vlc/vlc.h
index 1e2cf65..de0d30c 100644
--- a/include/vlc/vlc.h
+++ b/include/vlc/vlc.h
@@ -46,6 +46,7 @@ extern "C" {
 #include <vlc/libvlc_media_discoverer.h>
 #include <vlc/libvlc_events.h>
 #include <vlc/libvlc_dialog.h>
+#include <vlc/libvlc_stream.h>
 #include <vlc/libvlc_vlm.h>
 #include <vlc/deprecated.h>
 
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7a6b7c1..e635c13 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -19,6 +19,7 @@ pkginclude_HEADERS = \
 	../include/vlc/libvlc_media_list.h \
 	../include/vlc/libvlc_media_list_player.h \
 	../include/vlc/libvlc_media_player.h \
+	../include/vlc/libvlc_stream.h \
 	../include/vlc/libvlc_vlm.h \
 	../include/vlc/vlc.h
 
@@ -44,6 +45,7 @@ libvlc_la_SOURCES = \
 	video.c \
 	audio.c \
 	event.c \
+	stream.c \
 	media.c \
 	media_player.c \
 	media_list.c \
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index 816025d..6134521 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -294,3 +294,13 @@ libvlc_wait
 libvlc_audio_filter_list_get
 libvlc_video_filter_list_get
 libvlc_module_description_list_release
+libvlc_stream_new
+libvlc_stream_release
+libvlc_stream_interrupt
+libvlc_stream_open_input
+libvlc_stream_close
+libvlc_stream_read
+libvlc_stream_seekto
+libvlc_stream_tell
+libvlc_stream_eos
+libvlc_stream_size
diff --git a/lib/stream.c b/lib/stream.c
new file mode 100644
index 0000000..65f10d9
--- /dev/null
+++ b/lib/stream.c
@@ -0,0 +1,250 @@
+/*****************************************************************************
+ * stream.c: stream API
+ *****************************************************************************
+ * Copyright © 2016 VLC authors and VideoLAN
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_stream.h>
+
+#include <vlc_common.h>
+#include <vlc_access.h>
+#include <vlc_interrupt.h>
+
+#include "libvlc_internal.h"
+
+struct libvlc_stream_t
+{
+    libvlc_instance_t *p_libvlc;
+    vlc_interrupt_t *p_interrupt;
+    access_t *p_a;
+    uint64_t i_offset;
+    block_t *p_last_block;
+};
+
+libvlc_stream_t *
+libvlc_stream_new(libvlc_instance_t *p_instance)
+{
+    assert(p_instance != NULL);
+
+    libvlc_stream_t *p_stream = malloc(sizeof(*p_stream));
+    if (unlikely(p_stream == NULL))
+        return NULL;
+
+    p_stream->p_libvlc = p_instance;
+    p_stream->p_interrupt = vlc_interrupt_create();
+    if (unlikely(p_stream->p_interrupt == NULL))
+    {
+        free(p_stream);
+        return NULL;
+    }
+    vlc_interrupt_set(p_stream->p_interrupt);
+    p_stream->p_a = NULL;
+    p_stream->i_offset = 0;
+    p_stream->p_last_block = NULL;
+
+    libvlc_retain(p_instance);
+
+    return p_stream;
+}
+
+void
+libvlc_stream_release(libvlc_stream_t *p_stream)
+{
+    assert(p_stream != NULL);
+
+    if (p_stream->p_a != NULL)
+        libvlc_stream_close(p_stream);
+
+    libvlc_release(p_stream->p_libvlc);
+    vlc_interrupt_set(NULL);
+    vlc_interrupt_destroy(p_stream->p_interrupt);
+    free(p_stream);
+}
+
+void
+libvlc_stream_interrupt(libvlc_stream_t *p_stream)
+{
+    assert(p_stream != NULL);
+
+    vlc_interrupt_kill(p_stream->p_interrupt);
+}
+
+int
+libvlc_stream_open_input(libvlc_stream_t *p_stream, const char *psz_mrl)
+{
+    assert(p_stream != NULL && psz_mrl != NULL);
+
+    if (p_stream->p_a != NULL)
+        libvlc_stream_close(p_stream);
+
+    p_stream->p_a = vlc_access_NewMRL(VLC_OBJECT(p_stream->p_libvlc->p_libvlc_int),
+                                      psz_mrl);
+    if (p_stream->p_a == NULL)
+        return -1;
+    if (p_stream->p_a->pf_read == NULL && p_stream->p_a->pf_block == NULL)
+    {
+        vlc_access_Delete(p_stream->p_a);
+        return -1;
+    }
+    return 0;
+}
+
+void
+libvlc_stream_close(libvlc_stream_t *p_stream)
+{
+    assert(p_stream != NULL && p_stream->p_a != NULL);
+
+    vlc_access_Delete(p_stream->p_a);
+    p_stream->p_a = NULL;
+    p_stream->i_offset = 0;
+    if (p_stream->p_last_block != NULL)
+        block_Release(p_stream->p_last_block);
+    p_stream->p_last_block = NULL;
+}
+
+static ssize_t
+stream_read(libvlc_stream_t *p_stream, uint8_t *p_buf, size_t i_len)
+{
+    size_t i_read = 0;
+
+    while (i_read < i_len)
+    {
+        if (vlc_access_Eof(p_stream->p_a))
+            break;
+        if (vlc_killed())
+            return -1;
+
+        ssize_t i_ret =
+            vlc_access_Read(p_stream->p_a, p_buf + i_read, i_len - i_read);
+        if (i_ret == -1)
+            return -1;
+
+        i_read += i_ret;
+    }
+    p_stream->i_offset += i_read;
+    return i_read;
+}
+
+static ssize_t
+stream_read_block(libvlc_stream_t *p_stream, uint8_t *p_buf, size_t i_len)
+{
+    size_t i_read = 0;
+
+    while (i_read < i_len)
+    {
+        if (vlc_access_Eof(p_stream->p_a))
+            break;
+        if (vlc_killed())
+            return -1;
+
+        block_t *p_block = p_stream->p_last_block != NULL ?
+                           p_stream->p_last_block :
+                           vlc_access_Block(p_stream->p_a);
+        p_stream->p_last_block = NULL;
+
+        if (p_block == NULL)
+            continue;
+        if (p_block->i_buffer == 0)
+        {
+            block_Release(p_block);
+            continue;
+        }
+
+        size_t i_toread = i_len - i_read;
+        size_t i_copy = p_block->i_buffer < i_toread ? p_block->i_buffer : i_toread;
+        memcpy(p_buf + i_read, p_block->p_buffer, i_copy);
+
+        i_read += i_copy;
+
+        p_block->i_buffer -= i_copy;
+        p_block->p_buffer += i_copy;
+
+        if (p_block->i_buffer == 0)
+            block_Release(p_block);
+        else
+            p_stream->p_last_block = p_block;
+    }
+    p_stream->i_offset += i_read;
+    return i_read;
+}
+
+ssize_t
+libvlc_stream_read(libvlc_stream_t *p_stream, void *p_buf, size_t i_len)
+{
+    assert(p_stream != NULL && p_stream->p_a != NULL);
+
+    if (p_stream->p_a->pf_read != NULL)
+        return stream_read(p_stream, p_buf, i_len);
+    else
+        return stream_read_block(p_stream, p_buf, i_len);
+}
+
+int
+libvlc_stream_seekto(libvlc_stream_t *p_stream, uint64_t i_offset)
+{
+    assert(p_stream != NULL && p_stream->p_a != NULL);
+
+    if (i_offset == p_stream->i_offset)
+        return 0;
+    if (p_stream->p_last_block != NULL)
+    {
+        block_Release(p_stream->p_last_block);
+        p_stream->p_last_block = NULL;
+    }
+
+    int i_ret = vlc_access_Seek(p_stream->p_a, i_offset);
+    if (i_ret == VLC_SUCCESS)
+    {
+        p_stream->i_offset = i_offset;
+        return 0;
+    }
+    else
+        return -1;
+}
+
+int
+libvlc_stream_tell(libvlc_stream_t *p_stream, uint64_t *p_offset)
+{
+    assert(p_stream != NULL && p_stream->p_a != NULL);
+
+    *p_offset = p_stream->i_offset;
+    return 0;
+}
+
+bool
+libvlc_stream_eos(libvlc_stream_t *p_stream)
+{
+    assert(p_stream != NULL && p_stream->p_a != NULL);
+
+    return vlc_access_Eof(p_stream->p_a);
+}
+
+int
+libvlc_stream_size(libvlc_stream_t *p_stream, uint64_t *p_size)
+{
+    assert(p_stream != NULL && p_stream->p_a != NULL);
+
+    int i_ret = access_GetSize(p_stream->p_a, p_size);
+    return i_ret == VLC_SUCCESS ? 0 : -1;
+}
-- 
2.8.1



More information about the vlc-devel mailing list