diff --git a/src/ffmpeg_api/api.rs b/src/ffmpeg_api/api.rs
index c44435fa10d0ee02e307bca2eefe158487b1a3d6..1f9607264f5fcc0086ddcb741365338694b7b991 100644
--- a/src/ffmpeg_api/api.rs
+++ b/src/ffmpeg_api/api.rs
@@ -1,20 +1,32 @@
 use std::marker::PhantomData;
+use std::path::Path;
 
 use enum_primitive::*;
-use failure::bail;
+use failure::{bail, format_err, Error};
 use ffmpeg_dev::sys as ffi;
 use fraction::Fraction;
 
 use crate::ffmpeg_api::enums::*;
 use crate::util::media_time;
-use std::path::Path;
+
+fn native_string(ptr: *const std::os::raw::c_char) -> Result<String, Error> {
+    if ptr.is_null() {
+        Err(format_err!("String is null"))
+    } else {
+        Ok(String::from(
+            unsafe { std::ffi::CStr::from_ptr(ptr) }
+                .to_str()
+                .map_err(|err| format_err!("String is not valid utf-8: {}", err))?,
+        ))
+    }
+}
 
 pub struct AVFormatContext {
     base: *mut ffi::AVFormatContext,
 }
 
-impl<'a> AVFormatContext {
-    pub fn new() -> Result<Self, failure::Error> {
+impl AVFormatContext {
+    pub fn new() -> Result<Self, Error> {
         let base = unsafe { ffi::avformat_alloc_context() };
         if base.is_null() {
             bail!("avformat_alloc_context() failed");
@@ -22,12 +34,12 @@ impl<'a> AVFormatContext {
         Ok(AVFormatContext { base })
     }
 
-    pub fn open_input(&mut self, path: &Path) -> Result<(), failure::Error> {
+    pub fn open_input(&mut self, path: &Path) -> Result<(), Error> {
         let path = path
             .to_str()
-            .ok_or(failure::format_err!("Could not convert path to c string"))?;
+            .ok_or(format_err!("Could not convert path to c string"))?;
         let path = std::ffi::CString::new(path)
-            .map_err(|err| failure::format_err!("Could not convert path to c string: {}", err))?;
+            .map_err(|err| format_err!("Could not convert path to c string: {}", err))?;
 
         match unsafe {
             ffi::avformat_open_input(
@@ -42,9 +54,9 @@ impl<'a> AVFormatContext {
         }
     }
 
-    pub fn input_format(&self) -> Result<AVInputFormat, failure::Error> {
+    pub fn input_format(&self) -> Result<AVInputFormat, Error> {
         let base: &mut ffi::AVInputFormat = unsafe { (*self.base).iformat.as_mut() }
-            .ok_or(failure::format_err!("No AVInputFormat found"))?;
+            .ok_or(format_err!("No AVInputFormat found"))?;
 
         Ok(AVInputFormat::new(base))
     }
@@ -72,14 +84,14 @@ impl<'a> AVFormatContext {
         .find(predicate)
     }
 
-    pub fn read_frame(&mut self, packet: &mut AVPacket) -> Result<(), failure::Error> {
+    pub fn read_frame(&mut self, packet: &mut AVPacket) -> Result<(), Error> {
         match unsafe { ffi::av_read_frame(self.base, packet.base) } {
             0 => Ok(()),
             errno => bail!("Error while decoding frame: {}", errno),
         }
     }
 
-    pub fn duration(&self) -> Result<media_time::MediaTime, failure::Error> {
+    pub fn duration(&self) -> Result<media_time::MediaTime, Error> {
         media_time::MediaTime::from_rational(
             unsafe { (*self.base).duration },
             Fraction::new(1 as u64, ffi::AV_TIME_BASE as u64),
@@ -102,45 +114,17 @@ impl<'a> AVInputFormat<'a> {
         return AVInputFormat { base };
     }
 
-    pub fn long_name(&self) -> Result<String, failure::Error> {
-        let raw: *const ::std::os::raw::c_char = self.base.long_name;
-
-        if raw.is_null() {
-            bail!("No long name found for input format")
-        } else {
-            Ok(String::from(
-                unsafe { std::ffi::CStr::from_ptr(raw) }
-                    .to_str()
-                    .map_err(|err| {
-                        failure::format_err!(
-                            "Could not convert long name for input format to string: {}",
-                            err
-                        )
-                    })?,
-            ))
-        }
+    pub fn long_name(&self) -> Result<String, Error> {
+        native_string(self.base.long_name)
+            .map_err(|err| format_err!("Could not access long name for input format: {}", err))
     }
 
-    pub fn name(&self) -> Result<String, failure::Error> {
-        let raw: *const ::std::os::raw::c_char = self.base.name;
-
-        if raw.is_null() {
-            bail!("No name found for input format")
-        } else {
-            Ok(String::from(
-                unsafe { std::ffi::CStr::from_ptr(raw) }
-                    .to_str()
-                    .map_err(|err| {
-                        failure::format_err!(
-                            "Could not convert name for input format to string: {}",
-                            err
-                        )
-                    })?,
-            ))
-        }
+    pub fn name(&self) -> Result<String, Error> {
+        native_string(self.base.name)
+            .map_err(|err| format_err!("Could not access short name for input format: {}", err))
     }
 
-    pub fn determine_mime<T: AsRef<str>>(&self, stream_codec: T) -> Result<&str, failure::Error> {
+    pub fn determine_mime(&self, stream_codec: impl AsRef<str>) -> Result<&str, Error> {
         let containers = self.name()?;
         let stream_codec = stream_codec.as_ref();
 
@@ -166,7 +150,7 @@ pub struct AVBuffer {
 }
 
 impl AVBuffer {
-    pub fn new(size: usize) -> Result<Self, failure::Error> {
+    pub fn new(size: usize) -> Result<Self, Error> {
         let base = unsafe { ffi::av_malloc(size) } as *mut u8;
         if base.is_null() {
             bail!("av_malloc() failed");
@@ -195,7 +179,7 @@ pub struct AVPacket {
 }
 
 impl AVPacket {
-    pub fn new() -> Result<Self, failure::Error> {
+    pub fn new() -> Result<Self, Error> {
         let base = unsafe { ffi::av_packet_alloc() };
         if base.is_null() {
             bail!("av_packet_alloc() failed");
@@ -232,7 +216,7 @@ pub struct AVFrame {
 }
 
 impl AVFrame {
-    pub fn new() -> Result<Self, failure::Error> {
+    pub fn new() -> Result<Self, Error> {
         let base = unsafe { ffi::av_frame_alloc() };
         if base.is_null() {
             bail!("avformat_alloc_frame() failed");
@@ -243,12 +227,7 @@ impl AVFrame {
         })
     }
 
-    pub fn init(
-        &mut self,
-        width: i32,
-        height: i32,
-        format: AVPixelFormat,
-    ) -> Result<(), failure::Error> {
+    pub fn init(&mut self, width: i32, height: i32, format: AVPixelFormat) -> Result<(), Error> {
         self.as_mut().width = width;
         self.as_mut().height = height;
         self.as_mut().format = format as ffi::AVPixelFormat;
@@ -350,25 +329,22 @@ impl<'a> AVStream<'a> {
         return AVStream { base };
     }
 
-    pub fn index(self: &AVStream<'a>) -> i32 {
+    pub fn index(&self) -> i32 {
         self.base.index
     }
 
-    pub fn time_base(self: &AVStream<'a>) -> Fraction {
+    pub fn time_base(&self) -> Fraction {
         Fraction::new(
             self.base.time_base.num as u32,
             self.base.time_base.den as u32,
         )
     }
 
-    pub fn timestamp(
-        self: &AVStream<'a>,
-        timestamp: i64,
-    ) -> Result<media_time::MediaTime, failure::Error> {
+    pub fn timestamp(&self, timestamp: i64) -> Result<media_time::MediaTime, Error> {
         media_time::MediaTime::from_rational(timestamp, self.time_base())
     }
 
-    pub fn duration(&self) -> Result<media_time::MediaTime, failure::Error> {
+    pub fn duration(&self) -> Result<media_time::MediaTime, Error> {
         self.timestamp(self.base.duration)
     }
 
@@ -398,10 +374,10 @@ impl<'a> AVStream<'a> {
         )
     }
 
-    pub fn codec_parameters(&self) -> Result<AVCodecParameters, failure::Error> {
+    pub fn codec_parameters(&self) -> Result<AVCodecParameters, Error> {
         Ok(AVCodecParameters::new(
             unsafe { self.base.codecpar.as_mut() }
-                .ok_or(failure::format_err!("No AVCodecParameters found"))?,
+                .ok_or(format_err!("No AVCodecParameters found"))?,
             self,
         ))
     }
@@ -432,12 +408,12 @@ impl<'a> AVCodecParameters<'a> {
         self.base.bit_rate
     }
 
-    pub fn find_decoder(&self) -> AVCodec {
-        AVCodec::new(
+    pub fn find_decoder(&self) -> Result<AVCodec, Error> {
+        Ok(AVCodec::new(
             unsafe { ffi::avcodec_find_decoder(self.base.codec_id).as_mut() }
-                .expect("AVCodec was unexpectedly null"),
+                .ok_or(format_err!("No AVCodec found"))?,
             self,
-        )
+        ))
     }
 }
 
@@ -454,12 +430,9 @@ impl<'a> AVCodec<'a> {
         };
     }
 
-    pub fn name(self: &AVCodec<'a>) -> std::string::String {
-        String::from(
-            unsafe { std::ffi::CStr::from_ptr(self.base.name) }
-                .to_str()
-                .unwrap(),
-        )
+    pub fn name(&self) -> Result<String, Error> {
+        native_string(self.base.name)
+            .map_err(|err| format_err!("Could not access name for codec: {}", err))
     }
 }
 
@@ -468,7 +441,7 @@ pub struct AVCodecContext {
 }
 
 impl AVCodecContext {
-    pub fn new(codec: &AVCodec) -> Result<Self, failure::Error> {
+    pub fn new(codec: &AVCodec) -> Result<Self, Error> {
         let base = unsafe { ffi::avcodec_alloc_context3(codec.base) };
         if base.is_null() {
             bail!("avcodec_alloc_context3() failed");
@@ -476,23 +449,17 @@ impl AVCodecContext {
         Ok(AVCodecContext { base })
     }
 
-    pub fn in_packet(&mut self, packet: &mut AVPacket) -> Result<(), failure::Error> {
+    pub fn in_packet(&mut self, packet: &mut AVPacket) -> Result<(), Error> {
         match unsafe { ffi::avcodec_send_packet(self.base, packet.base) } {
             0 => Ok(()),
-            errno => Err(failure::format_err!(
-                "Error while loading paclet: {}",
-                errno
-            )),
+            errno => Err(format_err!("Error while loading packet: {}", errno)),
         }
     }
 
-    pub fn out_frame(&mut self, frame: &mut AVFrame) -> Result<(), failure::Error> {
+    pub fn out_frame(&mut self, frame: &mut AVFrame) -> Result<(), Error> {
         match unsafe { ffi::avcodec_receive_frame(self.base, frame.base) } {
             0 => Ok(()),
-            errno => Err(failure::format_err!(
-                "Error while decoding frame: {}",
-                errno
-            )),
+            errno => Err(format_err!("Error while decoding frame: {}", errno)),
         }
     }
 
@@ -565,7 +532,7 @@ impl SwsContext {
         source: &AVFrame,
         target: &AVFrame,
         scaler: SwsScaler,
-    ) -> Result<(), failure::Error> {
+    ) -> Result<(), Error> {
         let base = unsafe {
             ffi::sws_getCachedContext(
                 self.base,
diff --git a/src/ingest/extract.rs b/src/ingest/extract.rs
index 91ccd15dbb38acee1d8dbed283851be6e027f6d6..28b5be0e53b049d4aa0247694ea5ffa2b131e779 100644
--- a/src/ingest/extract.rs
+++ b/src/ingest/extract.rs
@@ -1,6 +1,7 @@
-use failure::format_err;
 use std::path::Path;
 
+use failure::{format_err, Error};
+
 use crate::ffmpeg_api::api::*;
 use crate::ffmpeg_api::enums::*;
 use crate::ingest::spritesheet::*;
@@ -14,7 +15,7 @@ pub fn extract(
     frame_interval: MediaTime,
     input_file: &Path,
     output_folder: &Path,
-) -> Result<(), failure::Error> {
+) -> Result<(), Error> {
     let mut avformat_context = AVFormatContext::new()
         .map_err(|error| format_err!("Could not open video input: {}", error))?;
     avformat_context
@@ -48,19 +49,19 @@ pub fn extract(
     let time_base = stream.time_base();
 
     let codec_parameters = stream.codec_parameters()?;
-    let local_codec = codec_parameters.find_decoder();
+    let local_codec = codec_parameters.find_decoder()?;
 
     println!(
         "Stream #{}, type: {:#?}, codec: {:#?}",
         index,
         codec_parameters.codec_type(),
-        local_codec.name()
+        local_codec.name()?
     );
 
     let mut metadata = StreamMetadata::new(
         avformat_context
             .input_format()?
-            .determine_mime(local_codec.name())?,
+            .determine_mime(local_codec.name()?)?,
         duration,
         codec_parameters.bit_rate() / 1000,
     );
diff --git a/src/ingest/spritesheet.rs b/src/ingest/spritesheet.rs
index 42b61d5d42edf208af6ab2bcb601ca13aab46909..9a6daa9c5d955acf38146768c98bd1fce6e9ba8f 100644
--- a/src/ingest/spritesheet.rs
+++ b/src/ingest/spritesheet.rs
@@ -1,6 +1,6 @@
 use std::path::PathBuf;
 
-use failure::{bail, format_err};
+use failure::{bail, format_err, Error};
 use image::{ImageBuffer, RgbImage};
 
 use crate::util::media_time::MediaTime;
@@ -23,13 +23,13 @@ pub struct SpritesheetManager {
 }
 
 impl SpritesheetManager {
-    pub fn new<T: AsRef<str>, U: Into<PathBuf>>(
+    pub fn new(
         max_side: u32,
         num_horizontal: u32,
         num_vertical: u32,
         frame_interval: MediaTime,
-        output_path: U,
-        name: T,
+        output_path: impl Into<PathBuf>,
+        name: impl AsRef<str>,
     ) -> SpritesheetManager {
         SpritesheetManager {
             num_horizontal,
@@ -101,11 +101,7 @@ impl SpritesheetManager {
         self.current_image == 0 || timestamp - self.last_timestamp > self.frame_interval
     }
 
-    pub fn add_image(
-        &mut self,
-        timestamp: MediaTime,
-        image: RgbImage,
-    ) -> Result<(), failure::Error> {
+    pub fn add_image(&mut self, timestamp: MediaTime, image: RgbImage) -> Result<(), Error> {
         if image.width() != self.sprite_width || image.height() != self.sprite_height {
             bail!(
                 "Wrong image size: {}x{}, but expected {}x{}",
@@ -150,7 +146,7 @@ impl SpritesheetManager {
         ));
     }
 
-    fn save_spritesheet(&mut self) -> Result<(), failure::Error> {
+    fn save_spritesheet(&mut self) -> Result<(), Error> {
         self.spritesheet
             .save(self.output_path.join(format!(
                 "{}_{}.jpg",
@@ -162,7 +158,7 @@ impl SpritesheetManager {
         Ok(())
     }
 
-    pub fn save(&mut self) -> Result<(), failure::Error> {
+    pub fn save(&mut self) -> Result<(), Error> {
         self.save_spritesheet()?;
         self.metadata
             .save(self.output_path.join(format!("{}.vtt", self.name)))
diff --git a/src/main.rs b/src/main.rs
index 32c15efbd4aa5572b60af5bf75e20f7ccbf827d1..8db4ba3831ac8ccead385ac03b1a7fb0d09aabd4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,6 +6,7 @@ pub(crate) mod util;
 
 use std::path::Path;
 
+use failure::Error;
 use structopt::StructOpt;
 
 use crate::util::media_time::MediaTime;
@@ -25,7 +26,7 @@ struct Options {
     max_size: u32,
 }
 
-fn main() -> Result<(), failure::Error> {
+fn main() -> Result<(), Error> {
     let options = Options::from_args();
 
     ingest::extract::extract(
diff --git a/src/util/media_time.rs b/src/util/media_time.rs
index ef804856d595d9c497951ad41eb8743be4ce3877..00c5b11844700d0bb5487b4107f302c5a0bd375b 100644
--- a/src/util/media_time.rs
+++ b/src/util/media_time.rs
@@ -1,11 +1,11 @@
-use failure::format_err;
+use failure::{format_err, Error};
 use fraction::Fraction;
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub struct MediaTime(time::Duration);
 
 impl MediaTime {
-    pub fn from_rational(timestamp: i64, base: Fraction) -> Result<MediaTime, failure::Error> {
+    pub fn from_rational(timestamp: i64, base: Fraction) -> Result<MediaTime, Error> {
         let num: u64 = *base
             .numer()
             .ok_or_else(|| format_err!("time base of unusable format"))?;
diff --git a/src/util/stream_metadata.rs b/src/util/stream_metadata.rs
index 3d71b1af433424c66dcf0b4c1c73dd08f7be48d9..912034727fe86d9a2921530434be246d6367866a 100644
--- a/src/util/stream_metadata.rs
+++ b/src/util/stream_metadata.rs
@@ -17,11 +17,7 @@ pub struct StreamMetadata {
 }
 
 impl StreamMetadata {
-    pub fn new<T: AsRef<str>>(
-        content_type: T,
-        duration: MediaTime,
-        bitrate: i64,
-    ) -> StreamMetadata {
+    pub fn new(content_type: impl AsRef<str>, duration: MediaTime, bitrate: i64) -> StreamMetadata {
         StreamMetadata {
             content_type: String::from(content_type.as_ref()),
             duration: duration.seconds(),
@@ -38,7 +34,7 @@ impl StreamMetadata {
         self.aspect_ratio = (width as f64 / height as f64) as f32;
     }
 
-    pub fn save<T: AsRef<Path>>(&self, path: T) -> Result<(), std::io::Error> {
+    pub fn save(&self, path: impl AsRef<Path>) -> Result<(), std::io::Error> {
         serde_json::to_writer(BufWriter::new(File::create(path)?), self)?;
         Ok(())
     }
diff --git a/src/util/webvtt.rs b/src/util/webvtt.rs
index 782fac52f5e09791aa124d1fc52e46b79801edeb..7a6788e1abe9e70a1ebdc667c07bcd71d32da575 100644
--- a/src/util/webvtt.rs
+++ b/src/util/webvtt.rs
@@ -25,7 +25,7 @@ impl WebVTTFile {
         self.cues.push(cue);
     }
 
-    pub fn save<T: AsRef<Path>>(&self, path: T) -> Result<(), std::io::Error> {
+    pub fn save(&self, path: impl AsRef<Path>) -> Result<(), std::io::Error> {
         let file = File::create(path)?;
         let mut file = LineWriter::new(file);
         file.write_all(b"WEBVTT\n\n")?;