From b430944a06070f7183ec374306c31b1b055d00c8 Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Mon, 9 Mar 2020 01:31:15 +0100 Subject: [PATCH] Improved error handling --- src/ffmpeg_api/api.rs | 151 ++++++++++++++++++------------------------ src/ingest/extract.rs | 12 +++- 2 files changed, 75 insertions(+), 88 deletions(-) diff --git a/src/ffmpeg_api/api.rs b/src/ffmpeg_api/api.rs index 9e6b2e3..c44435f 100644 --- a/src/ffmpeg_api/api.rs +++ b/src/ffmpeg_api/api.rs @@ -25,9 +25,9 @@ impl<'a> AVFormatContext { pub fn open_input(&mut self, path: &Path) -> Result<(), failure::Error> { let path = path .to_str() - .ok_or_else(|| failure::format_err!("Could not convert path to c string"))?; + .ok_or(failure::format_err!("Could not convert path to c string"))?; let path = std::ffi::CString::new(path) - .map_err(|_| failure::format_err!("Could not convert path to c string"))?; + .map_err(|err| failure::format_err!("Could not convert path to c string: {}", err))?; match unsafe { ffi::avformat_open_input( @@ -42,8 +42,11 @@ impl<'a> AVFormatContext { } } - pub fn input_format(&self) -> AVInputFormat { - AVInputFormat::new(unsafe { (*self.base).iformat.as_mut() }.expect("not null")) + pub fn input_format(&self) -> Result<AVInputFormat, failure::Error> { + let base: &mut ffi::AVInputFormat = unsafe { (*self.base).iformat.as_mut() } + .ok_or(failure::format_err!("No AVInputFormat found"))?; + + Ok(AVInputFormat::new(base)) } pub fn streams(&self) -> Vec<AVStream> { @@ -51,7 +54,8 @@ impl<'a> AVFormatContext { std::slice::from_raw_parts((*self.base).streams, (*self.base).nb_streams as usize) }) .iter() - .map(|stream| AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"))) + .filter_map(|stream: &*mut ffi::AVStream| unsafe { (*stream).as_mut() }) + .map(|stream| AVStream::new(stream)) .collect() } @@ -63,17 +67,15 @@ impl<'a> AVFormatContext { std::slice::from_raw_parts((*self.base).streams, (*self.base).nb_streams as usize) }) .iter() - .map(|stream| AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"))) + .filter_map(|stream: &*mut ffi::AVStream| unsafe { (*stream).as_mut() }) + .map(|stream| AVStream::new(stream)) .find(predicate) } pub fn read_frame(&mut self, packet: &mut AVPacket) -> Result<(), failure::Error> { match unsafe { ffi::av_read_frame(self.base, packet.base) } { 0 => Ok(()), - errno => Err(failure::format_err!( - "Error while decoding frame: {}", - errno - )), + errno => bail!("Error while decoding frame: {}", errno), } } @@ -104,7 +106,7 @@ impl<'a> AVInputFormat<'a> { let raw: *const ::std::os::raw::c_char = self.base.long_name; if raw.is_null() { - Err(failure::format_err!("No long name found for input format")) + bail!("No long name found for input format") } else { Ok(String::from( unsafe { std::ffi::CStr::from_ptr(raw) } @@ -123,7 +125,7 @@ impl<'a> AVInputFormat<'a> { let raw: *const ::std::os::raw::c_char = self.base.name; if raw.is_null() { - Err(failure::format_err!("No name found for input format")) + bail!("No name found for input format") } else { Ok(String::from( unsafe { std::ffi::CStr::from_ptr(raw) } @@ -201,22 +203,20 @@ impl AVPacket { Ok(AVPacket { base }) } - pub fn pts(&self) -> i64 { - let base = unsafe { self.base.as_ref() }.expect("not null"); + fn as_ref(&self) -> &ffi::AVPacket { + unsafe { self.base.as_ref() }.unwrap_or_else(|| panic!("AVPacket base unexpectedly null")) + } - base.pts + pub fn pts(&self) -> i64 { + self.as_ref().pts } pub fn dts(&self) -> i64 { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.dts + self.as_ref().dts } pub fn stream_index(&self) -> i32 { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.stream_index + self.as_ref().stream_index } } @@ -249,11 +249,9 @@ impl AVFrame { height: i32, format: AVPixelFormat, ) -> Result<(), failure::Error> { - let mut base = unsafe { self.base.as_mut() }.expect("not null"); - - base.width = width; - base.height = height; - base.format = format as ffi::AVPixelFormat; + self.as_mut().width = width; + self.as_mut().height = height; + self.as_mut().format = format as ffi::AVPixelFormat; self.buffer = AVBuffer::new(self.size())?; @@ -270,22 +268,24 @@ impl AVFrame { Ok(()) } - pub fn width(&self) -> i32 { - let base = unsafe { self.base.as_ref() }.expect("not null"); + fn as_ref(&self) -> &ffi::AVFrame { + unsafe { self.base.as_ref() }.unwrap_or_else(|| panic!("AVFrame base unexpectedly null")) + } - base.width + fn as_mut(&mut self) -> &mut ffi::AVFrame { + unsafe { self.base.as_mut() }.unwrap_or_else(|| panic!("AVFrame base unexpectedly null")) } - pub fn height(&self) -> i32 { - let base = unsafe { self.base.as_ref() }.expect("not null"); + pub fn width(&self) -> i32 { + self.as_ref().width + } - base.height + pub fn height(&self) -> i32 { + self.as_ref().height } pub fn format(&self) -> AVPixelFormat { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - AVPixelFormat::from_i32(base.format).unwrap_or(AVPixelFormat::NONE) + AVPixelFormat::from_i32(self.as_ref().format).unwrap_or(AVPixelFormat::NONE) } pub fn size(&self) -> usize { @@ -299,57 +299,39 @@ impl AVFrame { } pub fn key_frame(&self) -> bool { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.key_frame != 0 + self.as_ref().key_frame != 0 } pub fn pts(&self) -> i64 { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.pts + self.as_ref().pts } pub fn coded_picture_number(&self) -> i32 { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.coded_picture_number + self.as_ref().coded_picture_number } pub fn display_picture_number(&self) -> i32 { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.display_picture_number + self.as_ref().display_picture_number } pub fn linesize(&self) -> &[i32] { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - &base.linesize + &self.as_ref().linesize } pub fn data_ptr(&self) -> *const *const u8 { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - base.data.as_ptr() as *const *const u8 + self.as_ref().data.as_ptr() as *const *const u8 } pub fn data_mut_ptr(&mut self) -> *mut *mut u8 { - let base = unsafe { self.base.as_mut() }.expect("not null"); - - base.data.as_mut_ptr() as *mut *mut u8 + self.as_mut().data.as_mut_ptr() as *mut *mut u8 } pub fn data(&self, index: usize) -> &[u8] { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - unsafe { std::slice::from_raw_parts(base.data[index], self.size()) } + unsafe { std::slice::from_raw_parts(self.as_ref().data[index], self.size()) } } pub fn data_mut(&mut self, index: usize) -> &mut [u8] { - let base = unsafe { self.base.as_mut() }.expect("not null"); - - unsafe { std::slice::from_raw_parts_mut(base.data[index], self.size()) } + unsafe { std::slice::from_raw_parts_mut(self.as_mut().data[index], self.size()) } } } @@ -416,11 +398,12 @@ impl<'a> AVStream<'a> { ) } - pub fn codec_parameters(&self) -> AVCodecParameters { - AVCodecParameters::new( - unsafe { self.base.codecpar.as_mut() }.expect("not null"), + pub fn codec_parameters(&self) -> Result<AVCodecParameters, failure::Error> { + Ok(AVCodecParameters::new( + unsafe { self.base.codecpar.as_mut() } + .ok_or(failure::format_err!("No AVCodecParameters found"))?, self, - ) + )) } } @@ -452,7 +435,7 @@ impl<'a> AVCodecParameters<'a> { pub fn find_decoder(&self) -> AVCodec { AVCodec::new( unsafe { ffi::avcodec_find_decoder(self.base.codec_id).as_mut() } - .expect("Decoder not found"), + .expect("AVCodec was unexpectedly null"), self, ) } @@ -513,40 +496,38 @@ impl AVCodecContext { } } - pub fn skip_loop_filter(&self) -> Option<AVDiscard> { - let base = unsafe { self.base.as_ref() }.expect("not null"); + fn as_ref(&self) -> &ffi::AVCodecContext { + unsafe { self.base.as_ref() } + .unwrap_or_else(|| panic!("AVCodecContext base unexpectedly null")) + } - AVDiscard::from_i32(base.skip_loop_filter) + fn as_mut(&mut self) -> &mut ffi::AVCodecContext { + unsafe { self.base.as_mut() } + .unwrap_or_else(|| panic!("AVCodecContext base unexpectedly null")) } - pub fn set_skip_loop_filter(&mut self, value: AVDiscard) { - let base = unsafe { self.base.as_mut() }.expect("not null"); + pub fn skip_loop_filter(&self) -> Option<AVDiscard> { + AVDiscard::from_i32(self.as_ref().skip_loop_filter) + } - base.skip_loop_filter = value as ffi::AVDiscard + pub fn set_skip_loop_filter(&mut self, value: AVDiscard) { + self.as_mut().skip_loop_filter = value as ffi::AVDiscard } pub fn skip_idct(&self) -> Option<AVDiscard> { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - AVDiscard::from_i32(base.skip_idct) + AVDiscard::from_i32(self.as_ref().skip_idct) } pub fn set_skip_idct(&mut self, value: AVDiscard) { - let base = unsafe { self.base.as_mut() }.expect("not null"); - - base.skip_idct = value as ffi::AVDiscard + self.as_mut().skip_idct = value as ffi::AVDiscard } pub fn skip_frame(&self) -> Option<AVDiscard> { - let base = unsafe { self.base.as_ref() }.expect("not null"); - - AVDiscard::from_i32(base.skip_frame) + AVDiscard::from_i32(self.as_ref().skip_frame) } pub fn set_skip_frame(&mut self, value: AVDiscard) { - let base = unsafe { self.base.as_mut() }.expect("not null"); - - base.skip_frame = value as ffi::AVDiscard + self.as_mut().skip_frame = value as ffi::AVDiscard } pub fn set_parameters(&mut self, params: &AVCodecParameters) { diff --git a/src/ingest/extract.rs b/src/ingest/extract.rs index c7abd23..91ccd15 100644 --- a/src/ingest/extract.rs +++ b/src/ingest/extract.rs @@ -34,14 +34,20 @@ pub fn extract( ); let mut stream: AVStream = avformat_context - .find_stream(|stream| stream.codec_parameters().codec_type() == AVMediaType::Video) + .find_stream(|stream| { + if let Ok(codec_parameters) = stream.codec_parameters() { + return codec_parameters.codec_type() == AVMediaType::Video; + } + + false + }) .ok_or_else(|| format_err!("Could not find video stream"))?; stream.set_discard(AVDiscard::NonKey); let index = stream.index(); let time_base = stream.time_base(); - let codec_parameters = stream.codec_parameters(); + let codec_parameters = stream.codec_parameters()?; let local_codec = codec_parameters.find_decoder(); println!( @@ -53,7 +59,7 @@ pub fn extract( let mut metadata = StreamMetadata::new( avformat_context - .input_format() + .input_format()? .determine_mime(local_codec.name())?, duration, codec_parameters.bit_rate() / 1000, -- GitLab