Merge branch 'fix/track-description-iteration' into 'master'
Fix track description iteration See merge request videolan/vlc-rs!22merge-requests/22/merge
commit
615e8ab798
11
src/audio.rs
11
src/audio.rs
|
|
@ -5,7 +5,7 @@
|
||||||
use vlc_sys as sys;
|
use vlc_sys as sys;
|
||||||
use crate::MediaPlayer;
|
use crate::MediaPlayer;
|
||||||
use crate::TrackDescription;
|
use crate::TrackDescription;
|
||||||
use crate::tools::from_cstr;
|
use crate::tools::track_descriptions_from_raw;
|
||||||
|
|
||||||
pub trait MediaPlayerAudioEx {
|
pub trait MediaPlayerAudioEx {
|
||||||
fn get_mute(&self) -> Option<bool>;
|
fn get_mute(&self) -> Option<bool>;
|
||||||
|
|
@ -44,16 +44,9 @@ impl MediaPlayerAudioEx for MediaPlayer {
|
||||||
unsafe{
|
unsafe{
|
||||||
let p0 = sys::libvlc_audio_get_track_description(self.ptr);
|
let p0 = sys::libvlc_audio_get_track_description(self.ptr);
|
||||||
if p0.is_null() { return None; }
|
if p0.is_null() { return None; }
|
||||||
let mut td = Vec::new();
|
let td = track_descriptions_from_raw(p0);
|
||||||
let mut p = p0;
|
|
||||||
|
|
||||||
while !(*p).p_next.is_null() {
|
|
||||||
td.push(TrackDescription{ id: (*p).i_id, name: from_cstr((*p).psz_name) });
|
|
||||||
p = (*p).p_next;
|
|
||||||
}
|
|
||||||
sys::libvlc_track_description_list_release(p0);
|
sys::libvlc_track_description_list_release(p0);
|
||||||
Some(td)
|
Some(td)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
95
src/tools.rs
95
src/tools.rs
|
|
@ -2,10 +2,12 @@
|
||||||
// This file is part of vlc-rs.
|
// This file is part of vlc-rs.
|
||||||
// Licensed under the MIT license, see the LICENSE file.
|
// Licensed under the MIT license, see the LICENSE file.
|
||||||
|
|
||||||
use std::ffi::{CString, CStr, NulError};
|
use crate::TrackDescription;
|
||||||
use std::path::Path;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::ffi::{CStr, CString, NulError};
|
||||||
|
use std::path::Path;
|
||||||
|
use vlc_sys as sys;
|
||||||
|
|
||||||
// Convert String to CString.
|
// Convert String to CString.
|
||||||
// Panic if the string includes null bytes.
|
// Panic if the string includes null bytes.
|
||||||
|
|
@ -17,7 +19,7 @@ pub fn to_cstr(s: &str) -> CString {
|
||||||
pub unsafe fn from_cstr(p: *const c_char) -> Option<String> {
|
pub unsafe fn from_cstr(p: *const c_char) -> Option<String> {
|
||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
None
|
None
|
||||||
}else{
|
} else {
|
||||||
let cstr = CStr::from_ptr(p);
|
let cstr = CStr::from_ptr(p);
|
||||||
|
|
||||||
Some(cstr.to_string_lossy().into_owned())
|
Some(cstr.to_string_lossy().into_owned())
|
||||||
|
|
@ -28,7 +30,7 @@ pub unsafe fn from_cstr(p: *const c_char) -> Option<String> {
|
||||||
pub unsafe fn from_cstr_ref<'a>(p: *const c_char) -> Option<Cow<'a, str>> {
|
pub unsafe fn from_cstr_ref<'a>(p: *const c_char) -> Option<Cow<'a, str>> {
|
||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
None
|
None
|
||||||
}else{
|
} else {
|
||||||
let cstr = CStr::from_ptr(p);
|
let cstr = CStr::from_ptr(p);
|
||||||
|
|
||||||
Some(cstr.to_string_lossy())
|
Some(cstr.to_string_lossy())
|
||||||
|
|
@ -41,3 +43,86 @@ pub fn path_to_cstr(path: &Path) -> Result<CString, NulError> {
|
||||||
|
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a libVLC track-description linked list into owned Rust values.
|
||||||
|
///
|
||||||
|
/// The caller retains ownership of the list and must release it using
|
||||||
|
/// `libvlc_track_description_list_release` when appropriate.
|
||||||
|
pub unsafe fn track_descriptions_from_raw(
|
||||||
|
mut track: *mut sys::libvlc_track_description_t,
|
||||||
|
) -> Vec<TrackDescription> {
|
||||||
|
let mut descriptions = Vec::new();
|
||||||
|
|
||||||
|
while !track.is_null() {
|
||||||
|
descriptions.push(TrackDescription {
|
||||||
|
id: (*track).i_id,
|
||||||
|
name: from_cstr((*track).psz_name),
|
||||||
|
});
|
||||||
|
track = (*track).p_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptions
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::track_descriptions_from_raw;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
|
use vlc_sys::libvlc_track_description_t;
|
||||||
|
|
||||||
|
fn track(
|
||||||
|
id: i32,
|
||||||
|
name: &CString,
|
||||||
|
next: *mut libvlc_track_description_t,
|
||||||
|
) -> libvlc_track_description_t {
|
||||||
|
libvlc_track_description_t {
|
||||||
|
i_id: id,
|
||||||
|
psz_name: name.as_ptr() as *mut _,
|
||||||
|
p_next: next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn track_descriptions_from_raw_handles_a_null_list() {
|
||||||
|
let descriptions = unsafe { track_descriptions_from_raw(ptr::null_mut()) };
|
||||||
|
|
||||||
|
assert!(descriptions.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn track_descriptions_from_raw_includes_a_singleton() {
|
||||||
|
let name = CString::new("English").unwrap();
|
||||||
|
let mut node = track(1, &name, ptr::null_mut());
|
||||||
|
|
||||||
|
let descriptions = unsafe { track_descriptions_from_raw(&mut node) };
|
||||||
|
|
||||||
|
assert_eq!(descriptions.len(), 1);
|
||||||
|
assert_eq!(descriptions[0].id, 1);
|
||||||
|
assert_eq!(descriptions[0].name.as_deref(), Some("English"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn track_descriptions_from_raw_includes_the_final_node() {
|
||||||
|
let first_name = CString::new("English").unwrap();
|
||||||
|
let second_name = CString::new("French").unwrap();
|
||||||
|
let mut second = track(2, &second_name, ptr::null_mut());
|
||||||
|
let mut first = track(1, &first_name, &mut second);
|
||||||
|
|
||||||
|
let descriptions = unsafe { track_descriptions_from_raw(&mut first) };
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
descriptions,
|
||||||
|
vec![
|
||||||
|
crate::TrackDescription {
|
||||||
|
id: 1,
|
||||||
|
name: Some("English".to_owned()),
|
||||||
|
},
|
||||||
|
crate::TrackDescription {
|
||||||
|
id: 2,
|
||||||
|
name: Some("French".to_owned()),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
10
src/video.rs
10
src/video.rs
|
|
@ -6,7 +6,7 @@ use vlc_sys as sys;
|
||||||
use crate::MediaPlayer;
|
use crate::MediaPlayer;
|
||||||
use crate::TrackDescription;
|
use crate::TrackDescription;
|
||||||
use crate::enums::VideoAdjustOption;
|
use crate::enums::VideoAdjustOption;
|
||||||
use crate::tools::{to_cstr, from_cstr};
|
use crate::tools::{to_cstr, from_cstr, track_descriptions_from_raw};
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
|
|
||||||
pub trait MediaPlayerVideoEx {
|
pub trait MediaPlayerVideoEx {
|
||||||
|
|
@ -98,13 +98,7 @@ impl MediaPlayerVideoEx for MediaPlayer {
|
||||||
unsafe{
|
unsafe{
|
||||||
let p0 = sys::libvlc_video_get_track_description(self.ptr);
|
let p0 = sys::libvlc_video_get_track_description(self.ptr);
|
||||||
if p0.is_null() { return None; }
|
if p0.is_null() { return None; }
|
||||||
let mut td = Vec::new();
|
let td = track_descriptions_from_raw(p0);
|
||||||
let mut p = p0;
|
|
||||||
|
|
||||||
while !(*p).p_next.is_null() {
|
|
||||||
td.push(TrackDescription{ id: (*p).i_id, name: from_cstr((*p).psz_name) });
|
|
||||||
p = (*p).p_next;
|
|
||||||
}
|
|
||||||
sys::libvlc_track_description_list_release(p0);
|
sys::libvlc_track_description_list_release(p0);
|
||||||
Some(td)
|
Some(td)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue