Commit 948fb2ae authored by François Laignel's avatar François Laignel

Replace XXXReturn with Result<XXXSuccess, XXXError>

... in function signatures.

These breaking changes aim at improving usability by allowing users
to take advantage of Rust error management features sur as `ok_or`,
`map_err`, `expect` and the `?` operator. See the `examples` and
`tutorials` to get an idea of the impacts.
parent 226070d2
Pipeline #14758 passed with stages
in 8 minutes and 1 second
......@@ -386,6 +386,26 @@ status = "generate"
[object.function.return]
bool_return_is_error = "Failed to sync state with parent"
[[object.function]]
name = "change_state"
# Use Result<StateChangeSuccess, StateChangeError>
ignore = true
[[object.function]]
name = "continue_state"
# Use Result<StateChangeSuccess, StateChangeError>
ignore = true
[[object.function]]
name = "get_state"
# Use Result<StateChangeSuccess, StateChangeError>
ignore = true
[[object.function]]
name = "set_state"
# Use Result<StateChangeSuccess, StateChangeError>
ignore = true
[[object.function]]
name = "query"
# correct mutability
......@@ -645,6 +665,11 @@ status = "generate"
# Buffer can be NULL
ignore = true
[[object.function]]
name = "get_last_flow_return"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "query"
# Correct mutability
......@@ -685,6 +710,21 @@ status = "generate"
# Pass by value
ignore = true
[[object.function]]
name = "link"
# Use Result<PadLinkSuccess, PadLinkError>
ignore = true
[[object.function]]
name = "link_full"
# Use Result<PadLinkSuccess, PadLinkError>
ignore = true
[[object.function]]
name = "store_sticky_event"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "new_from_static_template"
# Correct mutability
......
......@@ -57,6 +57,16 @@ trait = false
# Action signal
ignore = true
[[object.signal]]
name = "new-sample"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.signal]]
name = "new-preroll"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "set_caps"
[[object.function.parameter]]
......@@ -98,6 +108,16 @@ trait = false
# Action signal
ignore = true
[[object.function]]
name = "end_of_stream"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "push_sample"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "set_latency"
# ClockTime
......
......@@ -77,16 +77,41 @@ name = "GstBase.BaseSink"
subclassing = true
status = "generate"
[[object.function]]
name = "wait"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "wait_preroll"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object]]
name = "GstBase.BaseSrc"
subclassing = true
status = "generate"
[[object.function]]
name = "start_complete"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "start_wait"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "submit_buffer_list"
# Pass by value, to be added manually
ignore = true
[[object.function]]
name = "wait_playing"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object]]
name = "GstBase.BaseTransform"
subclassing = true
......
......@@ -122,6 +122,16 @@ status = "generate"
name = "GstRtspServer.RTSPStream"
status = "generate"
[[object.function]]
name = "recv_rtcp"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "recv_rtp"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "query_position"
ignore = true
......@@ -160,6 +170,11 @@ name = "GstRtspServer.RTSPStreamTransport"
status = "generate"
concurrency = "none"
[[object.function]]
name = "recv_data"
# Use Result<FlowSuccess, FlowError>
ignore = true
[[object.function]]
name = "send_rtcp"
[object.function.return]
......
......@@ -87,22 +87,16 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// Add a handler to the "new-sample" signal.
.new_sample(|appsink| {
// Pull the sample in question out of the appsink's buffer.
let sample = match appsink.pull_sample() {
None => return gst::FlowReturn::Eos,
Some(sample) => sample,
};
let buffer = if let Some(buffer) = sample.get_buffer() {
buffer
} else {
let sample = appsink.pull_sample().ok_or(gst::FlowError::Eos)?;
let buffer = sample.get_buffer().ok_or_else(|| {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get buffer from appsink")
);
return gst::FlowReturn::Error;
};
gst::FlowError::Error
})?;
// At this point, buffer is only a reference to an existing memory region somewhere.
// When we want to access its content, we have to map it while requesting the required
......@@ -111,32 +105,28 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// on the machine's main memory itself, but rather in the GPU's memory.
// So mapping the buffer makes the underlying memory region accessible to us.
// See: https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/allocation.html
let map = if let Some(map) = buffer.map_readable() {
map
} else {
let map = buffer.map_readable().ok_or_else(|| {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to map buffer readable")
);
return gst::FlowReturn::Error;
};
gst::FlowError::Error
})?;
// We know what format the data in the memory region has, since we requested
// it by setting the appsink's caps. So what we do here is interpret the
// memory region we mapped as an array of signed 16 bit integers.
let samples = if let Ok(samples) = map.as_slice_of::<i16>() {
samples
} else {
let samples = map.as_slice_of::<i16>().map_err(|_| {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to interprete buffer as S16 PCM")
);
return gst::FlowReturn::Error;
};
gst::FlowError::Error
})?;
// For buffer (= chunk of samples), we calculate the root mean square:
// (https://en.wikipedia.org/wiki/Root_mean_square)
......@@ -150,7 +140,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
let rms = (sum / (samples.len() as f64)).sqrt();
println!("rms: {}", rms);
gst::FlowReturn::Ok
Ok(gst::FlowSuccess::Ok)
})
.build(),
);
......@@ -159,7 +149,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
}
fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
pipeline.set_state(gst::State::Playing).into_result()?;
pipeline.set_state(gst::State::Playing)?;
let bus = pipeline
.get_bus()
......@@ -171,7 +161,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Err(ErrorMessage {
src: msg
.get_src()
......@@ -186,7 +176,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
}
}
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Ok(())
}
......
......@@ -141,7 +141,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
}
fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
pipeline.set_state(gst::State::Playing).into_result()?;
pipeline.set_state(gst::State::Playing)?;
let bus = pipeline
.get_bus()
......@@ -153,7 +153,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Err(ErrorMessage {
src: msg
.get_src()
......@@ -168,7 +168,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
}
}
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Ok(())
}
......
......@@ -181,7 +181,7 @@ fn example_main() -> Result<(), Error> {
// Get the queue element's sink pad and link the decodebin's newly created
// src pad for the audio stream to it.
let sink_pad = queue.get_static_pad("sink").expect("queue has no sinkpad");
src_pad.link(&sink_pad).into_result()?;
src_pad.link(&sink_pad)?;
} else if is_video {
// decodebin found a raw videostream, so we build the follow-up pipeline to
// display it using the autovideosink.
......@@ -205,7 +205,7 @@ fn example_main() -> Result<(), Error> {
// Get the queue element's sink pad and link the decodebin's newly created
// src pad for the video stream to it.
let sink_pad = queue.get_static_pad("sink").expect("queue has no sinkpad");
src_pad.link(&sink_pad).into_result()?;
src_pad.link(&sink_pad)?;
}
Ok(())
......@@ -243,7 +243,7 @@ fn example_main() -> Result<(), Error> {
}
});
pipeline.set_state(gst::State::Playing).into_result()?;
pipeline.set_state(gst::State::Playing)?;
let bus = pipeline
.get_bus()
......@@ -259,7 +259,7 @@ fn example_main() -> Result<(), Error> {
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
#[cfg(feature = "v1_10")]
{
......@@ -313,7 +313,7 @@ fn example_main() -> Result<(), Error> {
}
}
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Ok(())
}
......
......@@ -210,7 +210,7 @@ fn example_main() -> Result<(), Error> {
let src_pad = resample
.get_static_pad("src")
.expect("resample has no srcpad");
src_pad.link(&enc_sink_pad).into_result()?;
src_pad.link(&enc_sink_pad)?;
for e in elements {
e.sync_state_with_parent()?;
......@@ -219,7 +219,7 @@ fn example_main() -> Result<(), Error> {
// Get the queue element's sink pad and link the decodebin's newly created
// src pad for the audio stream to it.
let sink_pad = queue.get_static_pad("sink").expect("queue has no sinkpad");
dbin_src_pad.link(&sink_pad).into_result()?;
dbin_src_pad.link(&sink_pad)?;
} else if is_video {
let queue =
gst::ElementFactory::make("queue", None).ok_or(MissingElement("queue"))?;
......@@ -243,7 +243,7 @@ fn example_main() -> Result<(), Error> {
let src_pad = scale
.get_static_pad("src")
.expect("videoscale has no srcpad");
src_pad.link(&enc_sink_pad).into_result()?;
src_pad.link(&enc_sink_pad)?;
for e in elements {
e.sync_state_with_parent()?
......@@ -252,7 +252,7 @@ fn example_main() -> Result<(), Error> {
// Get the queue element's sink pad and link the decodebin's newly created
// src pad for the video stream to it.
let sink_pad = queue.get_static_pad("sink").expect("queue has no sinkpad");
dbin_src_pad.link(&sink_pad).into_result()?;
dbin_src_pad.link(&sink_pad)?;
}
Ok(())
......@@ -280,7 +280,7 @@ fn example_main() -> Result<(), Error> {
}
});
pipeline.set_state(gst::State::Playing).into_result()?;
pipeline.set_state(gst::State::Playing)?;
let bus = pipeline
.get_bus()
......@@ -292,7 +292,7 @@ fn example_main() -> Result<(), Error> {
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
#[cfg(feature = "v1_10")]
{
......@@ -342,7 +342,7 @@ fn example_main() -> Result<(), Error> {
}
}
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Ok(())
}
......
......@@ -36,8 +36,9 @@ fn example_main() {
let pipeline = gst::parse_launch("audiotestsrc ! fakesink").unwrap();
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
// Need to move a new reference into the closure.
// !!ATTENTION!!:
......@@ -122,8 +123,9 @@ fn example_main() {
// (see above for how to do this).
main_loop.run();
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
// Remove the watch function from the bus.
// Again: There can always only be one watch function.
......
......@@ -25,8 +25,9 @@ fn example_main() {
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
// BusStream implements the Stream trait, but Stream::for_each is
// calling a closure for each item and returns a Future that resolves
......@@ -65,8 +66,9 @@ fn example_main() {
// Synchronously wait on the future we created above.
let _ = block_on(messages);
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
}
fn main() {
......
......@@ -100,8 +100,9 @@ fn main_loop(uri: &str) -> Result<(), glib::BoolError> {
clip.set_inpoint(duration / 2);
clip.set_duration(duration / 4);
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let bus = pipeline.get_bus().unwrap();
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
......@@ -122,8 +123,9 @@ fn main_loop(uri: &str) -> Result<(), glib::BoolError> {
}
}
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
Ok(())
}
......
......@@ -21,8 +21,9 @@ fn example_main() {
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let messages = gst::BusStream::new(&bus)
.for_each(|msg| {
......@@ -52,8 +53,9 @@ fn example_main() {
let _ = ctx.block_on(messages);
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
}
fn main() {
......
......@@ -428,34 +428,42 @@ impl App {
self.appsink.set_callbacks(
gst_app::AppSinkCallbacks::new()
.new_sample(move |appsink| {
let sample = match appsink.pull_sample() {
None => return gst::FlowReturn::Eos,
Some(sample) => sample,
};
let sample = appsink.pull_sample().ok_or(gst::FlowError::Eos)?;
let buffer = sample.get_buffer();
let info = sample
.get_caps()
.and_then(|caps| gst_video::VideoInfo::from_caps(caps.as_ref()));
if buffer.is_none() || info.is_none() {
let _buffer = sample.get_buffer().ok_or_else(|| {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get buffer from appsink")
);
return gst::FlowReturn::Error;
};
gst::FlowError::Error
})?;
match sender_clone.lock().unwrap().send(sample) {
Ok(_) => return gst::FlowReturn::Ok,
Err(_) => return gst::FlowReturn::Error,
}
let _info = sample
.get_caps()
.and_then(|caps| gst_video::VideoInfo::from_caps(caps.as_ref()))
.ok_or_else(|| {
gst_element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get video info from sample")
);
gst::FlowError::Error
})?;
sender_clone
.lock()
.unwrap()
.send(sample)
.map(|_| gst::FlowSuccess::Ok)
.map_err(|_| gst::FlowError::Error)
})
.build(),
);
self.pipeline.set_state(gst::State::Playing).into_result()?;
self.pipeline.set_state(gst::State::Playing)?;
Ok((bus_handler, receiver))
}
......@@ -576,7 +584,7 @@ fn main_loop(mut app: App) -> Result<(), Error> {
app.pipeline.send_event(gst::Event::new_eos().build());
bus_handler.join().expect("Could join bus handler thread");
app.pipeline.set_state(gst::State::Null).into_result()?;
app.pipeline.set_state(gst::State::Null)?;
Ok(())
}
......
......@@ -108,8 +108,9 @@ fn create_ui(app: &gtk::Application) {
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let app_weak = glib::SendWeakRef::from(app.downgrade());
bus.add_watch(move |_, msg| {
......@@ -141,8 +142,9 @@ fn create_ui(app: &gtk::Application) {
// destroyed once the app is destroyed
let timeout_id = RefCell::new(Some(timeout_id));
app.connect_shutdown(move |_| {
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
bus.remove_watch();
if let Some(timeout_id) = timeout_id.borrow_mut().take() {
......
......@@ -211,8 +211,9 @@ fn create_ui(app: &gtk::Application) {
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let app_weak = glib::SendWeakRef::from(app.downgrade());
bus.add_watch(move |_, msg| {
......@@ -244,8 +245,9 @@ fn create_ui(app: &gtk::Application) {
// destroyed once the app is destroyed
let timeout_id = RefCell::new(Some(timeout_id));
app.connect_shutdown(move |_| {
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
bus.remove_watch();
if let Some(timeout_id) = timeout_id.borrow_mut().take() {
......
......@@ -43,8 +43,9 @@ fn example_main() {
};
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
use gst::MessageView;
......@@ -64,8 +65,9 @@ fn example_main() {
}
}
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
}
fn main() {
......
......@@ -30,8 +30,9 @@ fn example_main() {
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.get_bus().unwrap();
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let main_loop_clone = main_loop.clone();
......@@ -60,8 +61,9 @@ fn example_main() {
main_loop.run();
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
// Here we remove the bus watch we added above. This avoids a memory leak, that might
// otherwise happen because we moved a strong reference (clone of main_loop) into the
......
......@@ -75,8 +75,9 @@ fn example_main() {
gst::PadProbeReturn::Ok
});
let ret = pipeline.set_state(gst::State::Playing);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let bus = pipeline.get_bus().unwrap();
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
......@@ -97,8 +98,9 @@ fn example_main() {
}
}
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
}
fn main() {
......
......@@ -237,7 +237,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
}
fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
pipeline.set_state(gst::State::Playing).into_result()?;
pipeline.set_state(gst::State::Playing)?;
let bus = pipeline
.get_bus()
......@@ -249,7 +249,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Err(ErrorMessage {
src: msg
.get_src()
......@@ -264,7 +264,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
}
}
pipeline.set_state(gst::State::Null).into_result()?;
pipeline.set_state(gst::State::Null)?;
Ok(())
}
......
......@@ -103,8 +103,9 @@ fn example_main() {
// created from an element factory.