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

Alexandre Janniaux ajanni at videolabs.io
Sun Sep 20 13:17:56 CEST 2020


Hi,

On Sun, Sep 20, 2020 at 04:30:46PM +0530, Kartik Ohri wrote:
> 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>.

The point of using Meson integration is actually that it is
limited. ;)

In my opinion, it would also greatly simplify the build
definitions by removing toml files, greatly decrease
compilation time if we are to integrate more Rust, and
provide a unified build system that all developers will
manipulate, be them Rust developers or not, so making the
Rust integration quite like the C++ one.

> 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.

Perfectly exact. Meson generate ninja makefiles, which need
all the targets information before running the compilation.
Talking about directories is talking about autodiscovery of
new targets during the build process so this is not possible.

> 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.

Yeah, it probably needs a bigger picture of the whole
generation process to answer correctly.

> 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.

That's a bit arbitrary coming from me, but please, no, there's
probably no point in switching from autotools to cmake, it's
quite the same buildsystem with the same features.

The benefit of Meson is the declarative approach without
scripting that constraint the buildsystem and require us to
find more elegant solution to most integration issues.

> 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

> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list