[vlc-devel] [PATCH 1/2] libvlc: Add Rust API for writing modules in rust

Kartik Ohri kartikohri13 at gmail.com
Sun Sep 20 13:00:46 CEST 2020


Hi!
On Sun, Sep 20, 2020 at 4:03 PM Alexandre Janniaux <ajanni at videolabs.io>
wrote:

> Hi,
>
> What is the integration plan when we integrate meson?
>
> Do we remove cargo support completly and ony use the
> meson rust support?
>
> No, I think meson rust support is very limited. We should continue using
cargo. We can run_command and custom_targets to integrate cargo with meson.
I had made the first iteration of the cuesheet module using meson. A sample
is here
<https://code.videolan.org/gsoc/gsoc2020/rustyc/vlc/-/commit/505f293767fcc540c9402829886b38205ef1da97>.
However, there are a few issues with this. The custom_target feature
requires files as output as opposed to directories though (I might be wrong
here since I am not much familiar with meson). The other option is to use
run_command, which works fine but run_command is executed during the
configure phase which means the build process will become a two step
process.

It is probably possible to modify cargo-c in a way to output specific
files, the work should be of moderate scale because cargo-c already
produces the required files. We just those in a flat layout. On the meson
side, we may need a source generator, Marvin might be able to advise here
in detail.

Also, is it finalized that the build system will be ported to meson ? If it
is still open for discussion and if Cmake has not been considered, I would
suggest that we experiment a bit with it. Otherwise, if meson is finalized
we can go ahead with it and make necessary adjustments as specified above
to get it to work with meson.

Regards,
Kartik

> Regards,
> --
> Alexandre Janniaux
> Videolabs
>
> On Sun, Sep 20, 2020 at 02:39:33AM +0530, Kartik Ohri wrote:
> > The API is written in two layers. vlccore-sys
> > crate contains one to one bindings of libvlc
> > functions. vlccore-rs crate wraps vlccore-sys and
> > exposes a Rust idiomatic API for writing modules
> > in rust. As of now, the API exposes only a subset
> > of the vlc_stream API. More functionality can be
> > added to Rust API as required in the future.
> > ---
> >  .gitignore                    |   2 +-
> >  configure.ac                  |  13 ++++
> >  modules/common.am             |   7 ++
> >  src/Cargo.toml                |   2 +
> >  src/vlccore-rs/Cargo.toml     |  10 +++
> >  src/vlccore-rs/src/lib.rs     |   2 +
> >  src/vlccore-rs/src/stream.rs  | 126 ++++++++++++++++++++++++++++++++++
> >  src/vlccore-rs/src/utils.rs   |  19 +++++
> >  src/vlccore-sys/Cargo.toml    |  10 +++
> >  src/vlccore-sys/src/lib.rs    |   3 +
> >  src/vlccore-sys/src/stream.rs |  46 +++++++++++++
> >  11 files changed, 239 insertions(+), 1 deletion(-)
> >  create mode 100644 src/Cargo.toml
> >  create mode 100644 src/vlccore-rs/Cargo.toml
> >  create mode 100644 src/vlccore-rs/src/lib.rs
> >  create mode 100644 src/vlccore-rs/src/stream.rs
> >  create mode 100644 src/vlccore-rs/src/utils.rs
> >  create mode 100644 src/vlccore-sys/Cargo.toml
> >  create mode 100644 src/vlccore-sys/src/lib.rs
> >  create mode 100644 src/vlccore-sys/src/stream.rs
> >
> > diff --git a/.gitignore b/.gitignore
> > index fc368212c8..6c049a80b1 100644
> > --- a/.gitignore
> > +++ b/.gitignore
> > @@ -46,7 +46,7 @@ wxvlc
> >  vlc_install_dir/*
> >  plugins.dat
> >  patches/*
> > -
> > +**/Cargo.lock
> >  include/vlc/libvlc_version.h
> >
> >  # Ignore build dirs
> > diff --git a/configure.ac b/configure.ac
> > index 99e4669942..53d56a725c 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -1896,6 +1896,19 @@ AS_IF([test "${enable_sout}" != "no"], [
> >  ])
> >  AM_CONDITIONAL([ENABLE_SOUT], [test "${enable_sout}" != "no"])
> >
> > +dnl Rust Modules
> > +AC_ARG_ENABLE([rust],
> > +    AS_HELP_STRING([--enable-rust], [enable building Rust modules
> (default disabled)]))
> > +AS_IF([test "${enable_rust}" = "yes"],
> > +      [AC_DEFINE(ENABLE_RUST, 1, [Define to 1 for building rust
> modules.])])
> > +AM_CONDITIONAL([BUILD_RUST], [test "${enable_rust}" = "yes"])
> > +if test "${enable_rust}" = "yes"
> > +then
> > +    AC_CHECK_PROG(CARGO, [cargo], [yes], [no])
> > +    AS_IF([test "x$CARGO" = "xno"],
> > +          AC_MSG_ERROR([cargo not found. cargo is required to build
> rust modules]))
> > +fi
> > +
> >  dnl Lua modules
> >  AC_ARG_ENABLE([lua],
> >    AS_HELP_STRING([--disable-lua],
> > diff --git a/modules/common.am b/modules/common.am
> > index b991f6ce2f..5edc14ea26 100644
> > --- a/modules/common.am
> > +++ b/modules/common.am
> > @@ -39,6 +39,13 @@ endif
> >  AM_YFLAGS = -d -Wno-yacc
> >
> >  SUFFIXES = .l .y .asm
> > +RUST_API = ../src/vlccore-sys/src/lib.rs \
> > +     ../src/vlccore-sys/src/stream.rs \
> > +     ../src/vlccore-sys/Cargo.toml \
> > +     ../src/vlccore-rs/src/lib.rs \
> > +     ../src/vlccore-rs/src/stream.rs \
> > +     ../src/vlccore-rs/Cargo.toml \
> > +     ../src/Cargo.toml
> >
> >  .asm.lo:
> >       $(LIBTOOL) --mode=compile --tag=ASM $(X86ASM) $(X86ASMFLAGS)
> $(X86ASMDEFS) -I$(top_srcdir)/extras/include/x86/ $< -o $@
> > diff --git a/src/Cargo.toml b/src/Cargo.toml
> > new file mode 100644
> > index 0000000000..4b6346fc23
> > --- /dev/null
> > +++ b/src/Cargo.toml
> > @@ -0,0 +1,2 @@
> > +[workspace]
> > +members = ["vlccore-sys", "vlccore-rs"]
> > \ No newline at end of file
> > diff --git a/src/vlccore-rs/Cargo.toml b/src/vlccore-rs/Cargo.toml
> > new file mode 100644
> > index 0000000000..108c849f80
> > --- /dev/null
> > +++ b/src/vlccore-rs/Cargo.toml
> > @@ -0,0 +1,10 @@
> > +[package]
> > +name = "vlccore-rs"
> > +version = "0.1.0"
> > +authors = ["Kartik Ohri <kartikohri13 at gmail.com>"]
> > +edition = "2018"
> > +license = "LGPL-2.1-or-later"
> > +
> > +[dependencies]
> > +libc = "0.2"
> > +vlccore-sys = {path="../vlccore-sys"}
> > \ No newline at end of file
> > diff --git a/src/vlccore-rs/src/lib.rs b/src/vlccore-rs/src/lib.rs
> > new file mode 100644
> > index 0000000000..9fffcbc8b5
> > --- /dev/null
> > +++ b/src/vlccore-rs/src/lib.rs
> > @@ -0,0 +1,2 @@
> > +pub mod stream;
> > +pub mod utils;
> > diff --git a/src/vlccore-rs/src/stream.rs b/src/vlccore-rs/src/stream.rs
> > new file mode 100644
> > index 0000000000..afa622b4f1
> > --- /dev/null
> > +++ b/src/vlccore-rs/src/stream.rs
> > @@ -0,0 +1,126 @@
> > +use libc::{c_char, c_void};
> > +use std::ffi::{CStr, CString};
> > +use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom};
> > +use std::ptr::null_mut;
> > +use vlccore_sys::stream as ffi;
> > +
> > +pub struct Stream {
> > +    stream: *mut ffi::stream_t,
> > +}
> > +
> > +impl Read for Stream {
> > +    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
> > +        let bytes_read: isize = unsafe {
> > +            ffi::vlc_stream_Read(self.stream, buf.as_mut_ptr() as *mut
> c_void, buf.len())
> > +        };
> > +        if bytes_read < 0 {
> > +            Err(Error::new(
> > +                ErrorKind::Other,
> > +                "Error while reading from stream",
> > +            ))
> > +        } else {
> > +            Ok(bytes_read as usize)
> > +        }
> > +    }
> > +}
> > +
> > +impl Seek for Stream {
> > +    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
> > +        let offset = match pos {
> > +            SeekFrom::Start(n) => n,
> > +            SeekFrom::Current(n) => {
> > +                let len = self.position();
> > +                if n >= 0 {
> > +                    len.checked_add(n as u64)
> > +                } else {
> > +                    len.checked_sub(n.wrapping_neg() as u64)
> > +                }
> > +                .ok_or(Error::new(ErrorKind::Other, "Position
> Overflow"))?
> > +            }
> > +            SeekFrom::End(n) => self.len().and_then(|position| {
> > +                if n >= 0 {
> > +                    position.checked_add(n as u64)
> > +                } else {
> > +                    position.checked_sub(n.wrapping_neg() as u64)
> > +                }
> > +                .ok_or(Error::new(ErrorKind::Other, "Position
> Overflow"))
> > +            })?,
> > +        };
> > +
> > +        let result = unsafe { ffi::vlc_stream_Seek(self.stream, offset)
> };
> > +        if result != 0 {
> > +            return Err(Error::new(ErrorKind::Other, "Could not seek
> stream"));
> > +        }
> > +        Ok(offset)
> > +    }
> > +}
> > +
> > +impl Drop for Stream {
> > +    fn drop(&mut self) {
> > +        unsafe { ffi::vlc_stream_Delete(self.stream) }
> > +    }
> > +}
> > +
> > +impl From<*mut ffi::stream_t> for Stream {
> > +    fn from(stream: *mut ffi::stream_t) -> Self {
> > +        Stream { stream }
> > +    }
> > +}
> > +
> > +impl Stream {
> > +    pub fn len(&self) -> std::result::Result<u64, Error> {
> > +        let size: u64 = 0;
> > +        let result = unsafe {
> > +            ffi::vlc_stream_Control(
> > +                self.stream,
> > +                ffi::stream_query_e_STREAM_GET_SIZE as i32,
> > +                &size,
> > +            )
> > +        };
> > +        if result != 0 {
> > +            return Err(Error::new(
> > +                ErrorKind::Other,
> > +                "Could not determine stream size",
> > +            ));
> > +        }
> > +        Ok(size)
> > +    }
> > +
> > +    pub fn position(&self) -> u64 {
> > +        unsafe { ffi::vlc_stream_Tell(self.stream) }
> > +    }
> > +
> > +    pub fn eof(&self) -> Result<bool> {
> > +        Ok(unsafe { ffi::vlc_stream_Eof(self.stream) })
> > +    }
> > +
> > +    pub fn mimetype(&self) -> Option<String> {
> > +        let content_type = self.contenttype()?;
> > +        let index = content_type.chars().position(|c| c == ';')?;
> > +        Some(content_type[..index].to_owned())
> > +    }
> > +
> > +    pub fn contenttype(&self) -> Option<String> {
> > +        let result: *mut c_char = null_mut();
> > +        unsafe {
> > +            if ffi::vlc_stream_Control(
> > +                self.stream,
> > +                ffi::stream_query_e_STREAM_GET_CONTENT_TYPE as i32,
> > +                result,
> > +            ) != 0
> > +            {
> > +                return None;
> > +            } else if result.is_null() {
> > +                return None;
> > +            }
> > +            // FIXME: Free the C pointer received but retain copy of
> data in Rust
> > +            CStr::from_ptr(result).to_str().map(|s| s.to_string()).ok()
> > +        }
> > +    }
> > +
> > +    pub fn new_with_url(&mut self, url: &str) -> Self {
> > +        let c_url = CString::new(url).unwrap().as_ptr();
> > +        let stream = unsafe { ffi::vlc_stream_NewURL(self.stream,
> c_url) };
> > +        Stream { stream }
> > +    }
> > +}
> > diff --git a/src/vlccore-rs/src/utils.rs b/src/vlccore-rs/src/utils.rs
> > new file mode 100644
> > index 0000000000..3d9e25ac31
> > --- /dev/null
> > +++ b/src/vlccore-rs/src/utils.rs
> > @@ -0,0 +1,19 @@
> > +use libc::{c_char, malloc};
> > +use std::ffi::CString;
> > +use std::ptr::null_mut;
> > +use std::slice::from_raw_parts_mut;
> > +
> > +pub unsafe fn convert_string_to_ptr(string: String) -> *mut c_char {
> > +    if string.is_empty() {
> > +        return std::ptr::null_mut();
> > +    }
> > +    let size = string.len() + 1;
> > +    CString::new(string)
> > +        .map(|ptr| {
> > +            let c_ptr = malloc(size * std::mem::size_of::<u8>()) as
> *mut u8;
> > +            let slice = from_raw_parts_mut(c_ptr, size);
> > +            slice[..size].copy_from_slice(ptr.as_bytes_with_nul());
> > +            c_ptr as *mut c_char
> > +        })
> > +        .unwrap_or(null_mut())
> > +}
> > diff --git a/src/vlccore-sys/Cargo.toml b/src/vlccore-sys/Cargo.toml
> > new file mode 100644
> > index 0000000000..0dde7b2e7d
> > --- /dev/null
> > +++ b/src/vlccore-sys/Cargo.toml
> > @@ -0,0 +1,10 @@
> > +[package]
> > +name = "vlccore-sys"
> > +version = "0.1.0"
> > +authors = ["Kartik Ohri <kartikohri13 at gmail.com>"]
> > +edition = "2018"
> > +license = "LGPL-2.1-or-later"
> > +
> > +[dependencies]
> > +libc = "0.2"
> > +
> > diff --git a/src/vlccore-sys/src/lib.rs b/src/vlccore-sys/src/lib.rs
> > new file mode 100644
> > index 0000000000..08201d88ba
> > --- /dev/null
> > +++ b/src/vlccore-sys/src/lib.rs
> > @@ -0,0 +1,3 @@
> > +#![allow(non_camel_case_types)]
> > +#![allow(non_upper_case_globals)]
> > +pub mod stream;
> > diff --git a/src/vlccore-sys/src/stream.rs b/src/vlccore-sys/src/
> stream.rs
> > new file mode 100644
> > index 0000000000..e9df363998
> > --- /dev/null
> > +++ b/src/vlccore-sys/src/stream.rs
> > @@ -0,0 +1,46 @@
> > +use libc::{c_char, c_int, c_void, size_t, ssize_t};
> > +
> > +#[repr(C)]
> > +pub struct stream_t {
> > +    _private: [u8; 0],
> > +}
> > +
> > +pub const stream_query_e_STREAM_CAN_SEEK: stream_query_e = 0;
> > +pub const stream_query_e_STREAM_CAN_FASTSEEK: stream_query_e = 1;
> > +pub const stream_query_e_STREAM_CAN_PAUSE: stream_query_e = 2;
> > +pub const stream_query_e_STREAM_CAN_CONTROL_PACE: stream_query_e = 3;
> > +pub const stream_query_e_STREAM_GET_SIZE: stream_query_e = 6;
> > +pub const stream_query_e_STREAM_GET_PTS_DELAY: stream_query_e = 257;
> > +pub const stream_query_e_STREAM_GET_TITLE_INFO: stream_query_e = 258;
> > +pub const stream_query_e_STREAM_GET_TITLE: stream_query_e = 259;
> > +pub const stream_query_e_STREAM_GET_SEEKPOINT: stream_query_e = 260;
> > +pub const stream_query_e_STREAM_GET_META: stream_query_e = 261;
> > +pub const stream_query_e_STREAM_GET_CONTENT_TYPE: stream_query_e = 262;
> > +pub const stream_query_e_STREAM_GET_SIGNAL: stream_query_e = 263;
> > +pub const stream_query_e_STREAM_GET_TAGS: stream_query_e = 264;
> > +pub const stream_query_e_STREAM_SET_PAUSE_STATE: stream_query_e = 512;
> > +pub const stream_query_e_STREAM_SET_TITLE: stream_query_e = 513;
> > +pub const stream_query_e_STREAM_SET_SEEKPOINT: stream_query_e = 514;
> > +pub const stream_query_e_STREAM_SET_RECORD_STATE: stream_query_e = 515;
> > +pub const stream_query_e_STREAM_SET_PRIVATE_ID_STATE: stream_query_e =
> 4096;
> > +pub const stream_query_e_STREAM_SET_PRIVATE_ID_CA: stream_query_e =
> 4097;
> > +pub const stream_query_e_STREAM_GET_PRIVATE_ID_STATE: stream_query_e =
> 4098;
> > +pub type stream_query_e = ::std::os::raw::c_uint;
> > +
> > +pub type vlc_object_t = stream_t;
> > +
> > +extern "C" {
> > +    pub fn vlc_stream_Read(s: *mut stream_t, buf: *mut c_void, len:
> size_t) -> ssize_t;
> > +
> > +    pub fn vlc_stream_Tell(s: *const stream_t) -> u64;
> > +
> > +    pub fn vlc_stream_Eof(s: *const stream_t) -> bool;
> > +
> > +    pub fn vlc_stream_Seek(s: *mut stream_t, offset: u64) -> c_int;
> > +
> > +    pub fn vlc_stream_Control(s: *mut stream_t, query: c_int, ...) ->
> c_int;
> > +
> > +    pub fn vlc_stream_Delete(s: *mut stream_t);
> > +
> > +    pub fn vlc_stream_NewURL(obj: *mut vlc_object_t, url: *const
> c_char) -> *mut stream_t;
> > +}
> > --
> > 2.25.1
> >
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200920/13dc338c/attachment.html>


More information about the vlc-devel mailing list