Merge branch 'fix/track-description-iteration' into 'master'

Fix track description iteration

See merge request videolan/vlc-rs!22
merge-requests/22/merge
Martin Finkel 2026-09-07 13:38:37 +00:00
commit 615e8ab798
3 changed files with 96 additions and 24 deletions

View File

@ -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)
} }
} }
} }

View File

@ -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.
@ -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()),
},
]
);
}
}

View File

@ -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)
} }