diff --git a/src/avcodec/codec.rs b/src/avcodec/codec.rs index ff459c3..a58bd37 100644 --- a/src/avcodec/codec.rs +++ b/src/avcodec/codec.rs @@ -127,6 +127,7 @@ settable!(AVCodecContext { sample_aspect_ratio: AVRational, pix_fmt: i32, time_base: AVRational, + pkt_timebase: AVRational, sample_rate: i32, channels: i32, sample_fmt: i32, diff --git a/src/avformat/avformat.rs b/src/avformat/avformat.rs index 000e40a..ae6cf5c 100644 --- a/src/avformat/avformat.rs +++ b/src/avformat/avformat.rs @@ -147,7 +147,7 @@ impl AVFormatContextInput { match unsafe { ffi::av_read_frame(self.as_mut_ptr(), packet.as_mut_ptr()) }.upgrade() { Ok(_) => Ok(Some(packet)), Err(ffi::AVERROR_EOF) => Ok(None), - Err(x) => Err(RsmpegError::ReadFrameError(x)), + Err(x) => Err(x)?, } } @@ -340,9 +340,7 @@ impl AVFormatContextOutput { /// libavformat to handle the interleaving should call /// [`Self::interleaved_write_frame()`] instead of this function. pub fn write_frame(&mut self, packet: &mut AVPacket) -> Result<()> { - unsafe { ffi::av_write_frame(self.as_mut_ptr(), packet.as_mut_ptr()) } - .upgrade() - .map_err(RsmpegError::WriteFrameError)?; + unsafe { ffi::av_write_frame(self.as_mut_ptr(), packet.as_mut_ptr()) }.upgrade()?; Ok(()) } diff --git a/src/avutil/audio_fifo.rs b/src/avutil/audio_fifo.rs index 3b8a1b4..cc3eb27 100644 --- a/src/avutil/audio_fifo.rs +++ b/src/avutil/audio_fifo.rs @@ -1,8 +1,17 @@ use crate::{error::*, ffi, shared::*}; use std::ops::Drop; -wrap!(AVAudioFifo: ffi::AVAudioFifo); + +wrap!( + /// Context for an Audio FIFO Buffer. + /// + /// - Operates at the sample level rather than the byte level. + /// - Supports multiple channels with either planar or packed sample format. + /// - Automatic reallocation when writing to a full buffer. + AVAudioFifo: ffi::AVAudioFifo +); impl AVAudioFifo { + /// Allocate an AVAudioFifo. pub fn new(sample_fmt: ffi::AVSampleFormat, channels: i32, nb_samples: i32) -> Self { let fifo = unsafe { ffi::av_audio_fifo_alloc(sample_fmt, channels, nb_samples) } .upgrade() @@ -10,35 +19,7 @@ impl AVAudioFifo { unsafe { Self::from_raw(fifo) } } - /// Get the current number of samples in the [`AVAudioFifo`] available for - /// reading. - pub fn size(&self) -> i32 { - unsafe { - // function doesn't modify self, casting safe - ffi::av_audio_fifo_size(self.as_ptr() as *mut _) - } - } - - /// Get the current number of samples in the [`AVAudioFifo`] available for - /// writing. - pub fn space(&self) -> i32 { - unsafe { - // function doesn't modify self, casting safe - ffi::av_audio_fifo_space(self.as_ptr() as *mut _) - } - } - - pub fn reset(&mut self) { - unsafe { ffi::av_audio_fifo_reset(self.as_mut_ptr()) } - } - - pub fn drain(&mut self, nb_samples: i32) { - // FFI function only error when the nb_samples is negative. - unsafe { ffi::av_audio_fifo_drain(self.as_mut_ptr(), nb_samples) } - .upgrade() - .unwrap(); - } - + /// Reallocate an AVAudioFifo. pub fn realloc(&mut self, nb_samples: i32) { // Almost only panic on no memory, in other cases panic on invalid // parameters which is not possible with current good API. @@ -47,28 +28,91 @@ impl AVAudioFifo { .unwrap(); } - /// Write data to an AVAudioFifo. If successful, the number of samples - /// actually written will always be nb_samples. + /// Write data to an AVAudioFifo. /// /// The AVAudioFifo will be reallocated automatically if the available space /// is less than nb_samples. /// /// # Safety /// Function is safe when the `data` points to valid samples. - pub unsafe fn write(&mut self, data: *const *mut u8, nb_samples: i32) -> Result { - unsafe { ffi::av_audio_fifo_write(self.as_mut_ptr(), data as *mut _, nb_samples) } - .upgrade() - .map_err(RsmpegError::AudioFifoWriteError) + pub unsafe fn write(&mut self, data: *const *mut u8, nb_samples: i32) -> Result<()> { + let ret = unsafe { ffi::av_audio_fifo_write(self.as_mut_ptr(), data as _, nb_samples) } + .upgrade()?; + debug_assert_eq!(ret, nb_samples); + Ok(()) + } + + /// Peek data from an AVAudioFifo. + /// + /// # Safety + /// Function is safe when the `data` points to valid sample buffer. + pub unsafe fn peek(&mut self, data: *const *mut u8, nb_samples: i32) -> Result { + let ret = unsafe { ffi::av_audio_fifo_peek(self.as_mut_ptr(), data as _, nb_samples) } + .upgrade()?; + Ok(ret) } - /// Return actually read size if success. + /// Peek data from an AVAudioFifo. + /// + /// # Safety + /// Function is safe when the `data` points to valid sample buffer. + pub unsafe fn peek_at( + &mut self, + data: *const *mut u8, + nb_samples: i32, + offset: i32, + ) -> Result { + let ret = + unsafe { ffi::av_audio_fifo_peek_at(self.as_mut_ptr(), data as _, nb_samples, offset) } + .upgrade()?; + Ok(ret) + } + + /// Read data from an AVAudioFifo. + /// + /// This function returns actually read size if success. /// /// # Safety /// Function is safe when the `data` points to valid array such as AVFrame::data. - pub unsafe fn read(&mut self, data: *mut *mut u8, nb_samples: i32) -> Result { - unsafe { ffi::av_audio_fifo_read(self.as_mut_ptr(), data as _, nb_samples) } + pub unsafe fn read(&mut self, data: *const *mut u8, nb_samples: i32) -> Result { + let ret = unsafe { ffi::av_audio_fifo_read(self.as_mut_ptr(), data as _, nb_samples) } + .upgrade()?; + Ok(ret) + } + + /// Drain data from an AVAudioFifo. + /// + /// Removes the data without reading it. + pub fn drain(&mut self, nb_samples: i32) { + // FFI function only error when the nb_samples is negative. + unsafe { ffi::av_audio_fifo_drain(self.as_mut_ptr(), nb_samples) } .upgrade() - .map_err(RsmpegError::AudioFifoReadError) + .unwrap(); + } + + /// Reset the AVAudioFifo buffer. + /// + /// This empties all data in the buffer. + pub fn reset(&mut self) { + unsafe { ffi::av_audio_fifo_reset(self.as_mut_ptr()) } + } + + /// Get the current number of samples in the [`AVAudioFifo`] available for + /// reading. + pub fn size(&self) -> i32 { + unsafe { + // function doesn't modify self, casting safe + ffi::av_audio_fifo_size(self.as_ptr() as *mut _) + } + } + + /// Get the current number of samples in the [`AVAudioFifo`] available for + /// writing. + pub fn space(&self) -> i32 { + unsafe { + // function doesn't modify self, casting safe + ffi::av_audio_fifo_space(self.as_ptr() as *mut _) + } } } diff --git a/src/avutil/frame.rs b/src/avutil/frame.rs index 7bc25ae..0ebe782 100644 --- a/src/avutil/frame.rs +++ b/src/avutil/frame.rs @@ -73,6 +73,21 @@ impl AVFrame { Ok(()) } + /// Allocate new buffer(s) for audio or video data. + /// + /// The following fields must be set on frame before calling this function: + /// - format (pixel format for video, sample format for audio) + /// - width and height for video + /// - nb_samples and ch_layout for audio + /// + /// This function will fill AVFrame.data and AVFrame.buf arrays and, if + /// necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + /// For planar formats, one buffer will be allocated for each plane. + pub fn get_buffer(&mut self, align: i32) -> Result<()> { + unsafe { ffi::av_frame_get_buffer(self.as_mut_ptr(), align) }.upgrade()?; + Ok(()) + } + pub fn data_mut(&mut self) -> &mut [*mut u8; 8] { unsafe { &mut self.deref_mut().data } } diff --git a/src/avutil/samplefmt.rs b/src/avutil/samplefmt.rs index abccd45..1f1c355 100644 --- a/src/avutil/samplefmt.rs +++ b/src/avutil/samplefmt.rs @@ -120,11 +120,11 @@ pub fn sample_fmt_is_planar(sample_fmt: AVSampleFormat) -> bool { // > but for planar audio with more channels that can fit in data, // > extended_data must be used in order to access all channels. // -// This is the reason why `AVSamples` has a vector of channels for containing +// This is the reason why `AVSamples` has a vector of channels for holding // audio data. wrap! { - AVSamples: Vec, - audio_data: Vec<*mut u8> = Vec::new(), + AVSamples: Box<[u8]>, + audio_data: Box<[*mut u8]> = Vec::new().into_boxed_slice(), linesize: i32 = 0, nb_channels: i32 = 0, nb_samples: i32 = 0, @@ -183,14 +183,14 @@ impl AVSamples { // Implementation inspired by `av_samples_alloc_array_and_samples` and `av_samples_alloc`. let (_, buffer_size) = AVSamples::get_buffer_size(nb_channels, nb_samples, sample_fmt, align)?; - let linear = vec![0u8; buffer_size as usize]; + let buffer = vec![0u8; buffer_size as usize].into_boxed_slice(); let nb_planes = if sample_fmt_is_planar(sample_fmt) { nb_channels } else { 1 }; - let mut audio_data = vec![ptr::null_mut(); nb_planes as usize]; + let mut audio_data = vec![ptr::null_mut(); nb_planes as usize].into_boxed_slice(); let mut linesize = 0; // From the documentation, this function only error on no memory, so // unwrap. @@ -198,7 +198,7 @@ impl AVSamples { ffi::av_samples_fill_arrays( audio_data.as_mut_ptr(), &mut linesize, - linear.as_ptr(), + buffer.as_ptr(), nb_channels, nb_samples, sample_fmt, @@ -209,9 +209,9 @@ impl AVSamples { .unwrap(); // Leaks a Vec. - let linear = Box::leak(Box::new(linear)); + let buffer = Box::leak(Box::new(buffer)); - let mut samples = unsafe { AVSamples::from_raw(NonNull::new(linear).unwrap()) }; + let mut samples = unsafe { AVSamples::from_raw(NonNull::new(buffer).unwrap()) }; samples.audio_data = audio_data; samples.linesize = linesize; samples.nb_channels = nb_channels; diff --git a/src/error.rs b/src/error.rs index 8b902d0..8b6b85d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -80,10 +80,6 @@ pub enum RsmpegError { #[error("Failed to initialize bitstream filter context. ({0})")] BitstreamInitializationError(c_int), - #[error("Read frame to an input format context failed. ({0})")] - ReadFrameError(c_int), - #[error("Write frame to an output format context failed. ({0})")] - WriteFrameError(c_int), #[error("Interleaved write frame to an output format context failed. ({0})")] InterleavedWriteFrameError(c_int), @@ -104,19 +100,9 @@ pub enum RsmpegError { #[error("AVIO Open failure. ({0})")] AVIOOpenError(c_int), - #[error("SwrContext init failed. ({0})")] - SwrContextInitError(c_int), - #[error("SwrContext converting data failed. ({0})")] - SwrConvertError(c_int), - #[error("SwsContext scale failed. ({0})")] SwsScaleError(c_int), - #[error("AudioFifo write failed. ({0})")] - AudioFifoWriteError(c_int), - #[error("AudioFifo read failed. ({0})")] - AudioFifoReadError(c_int), - #[error("AVFrame buffer double allocating.")] AVFrameDoubleAllocatingError, #[error("AVFrame buffer allocating with incorrect parameters. ({0})")] @@ -153,19 +139,13 @@ impl RsmpegError { | Self::BitstreamSendPacketError(err) | Self::BitstreamReceivePacketError(err) | Self::BitstreamInitializationError(err) - | Self::ReadFrameError(err) - | Self::WriteFrameError(err) | Self::InterleavedWriteFrameError(err) | Self::BufferSrcAddFrameError(err) | Self::BufferSinkGetFrameError(err) | Self::DictionaryParseError(err) | Self::DictionaryGetStringError(err) | Self::AVIOOpenError(err) - | Self::SwrContextInitError(err) - | Self::SwrConvertError(err) | Self::SwsScaleError(err) - | Self::AudioFifoWriteError(err) - | Self::AudioFifoReadError(err) | Self::AVFrameInvalidAllocatingError(err) | Self::AVImageFillArrayError(err) => Some(*err), diff --git a/src/macros.rs b/src/macros.rs index 855c685..a7d9736 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -198,11 +198,12 @@ macro_rules! wrap_mut { /// Wrapping with XXX, XXX -> XXX. macro_rules! wrap { ( + $(#[$meta:meta])* $name: ident: $ffi_type: ty $(,$attach: ident: $attach_type: ty = $attach_default: expr)* $(,)? ) => { paste::paste! { - wrap_pure!(($name): $ffi_type $(,$attach: $attach_type = $attach_default)*); + wrap_pure!($(#[$meta])* ($name): $ffi_type $(,$attach: $attach_type = $attach_default)*); } }; } diff --git a/src/swresample/swresample.rs b/src/swresample/swresample.rs index 5f5e6c2..2ed73ed 100644 --- a/src/swresample/swresample.rs +++ b/src/swresample/swresample.rs @@ -1,9 +1,4 @@ -use crate::{ - avutil::{AVFrame, AVSamples}, - error::*, - ffi, - shared::*, -}; +use crate::{avutil::AVFrame, error::*, ffi, shared::*}; use std::{ ops::Drop, ptr::{self, NonNull}, @@ -42,7 +37,6 @@ impl SwrContext { ) -> Result { let mut context = ptr::null_mut(); unsafe { - // u64 to i64, safe ffi::swr_alloc_set_opts2( &mut context, out_ch_layout, @@ -61,9 +55,7 @@ impl SwrContext { /// Initialize context after user parameters have been set. pub fn init(&mut self) -> Result<()> { - unsafe { ffi::swr_init(self.as_mut_ptr()) } - .upgrade() - .map_err(RsmpegError::SwrContextInitError)?; + unsafe { ffi::swr_init(self.as_mut_ptr()) }.upgrade()?; Ok(()) } @@ -108,40 +100,6 @@ impl SwrContext { .unwrap() } - /// Convert audio to a given [`AVSamples`] buffer. - /// - /// `in_buffer` and `in_count` can be set to 0 to flush the last few samples - /// out at the end. If more input is provided than output space, then the - /// input will be buffered. You can avoid this buffering by using - /// [`SwrContext::get_out_samples`] to retrieve an upper bound on the - /// required number of output samples for the given number of input samples. - /// Conversion will run directly without copying whenever possible. - /// - /// `out_buffer` output buffers, only the first one need be set in case of packed audio - /// `in` input buffers, only the first one need to be set in case of packed audio - /// `in_count` number of input samples available in one channel - /// - /// Returns number of samples output per channel. - /// - /// # Safety - /// - /// Only safe when the `in_buffer` is valid. - pub unsafe fn convert( - &self, - out_buffer: &mut AVSamples, - in_buffer: *const *const u8, - in_count: i32, - ) -> Result { - unsafe { - self.convert_raw( - out_buffer.audio_data.as_mut_ptr(), - out_buffer.nb_samples, - in_buffer, - in_count, - ) - } - } - /// Convert audio. /// /// `in_buffer` and `in_count` can be set to 0 to flush the last few samples @@ -161,8 +119,8 @@ impl SwrContext { /// # Safety /// /// Only safe when the `in_buffer` is valid. - pub unsafe fn convert_raw( - &self, + pub unsafe fn convert( + &mut self, out_buffer: *mut *mut u8, out_count: i32, in_buffer: *const *const u8, @@ -175,17 +133,17 @@ impl SwrContext { // The swr_convert's documentation states: out_count is the amount of // space available for output in samples per channel, rather than being // the number of the output samples per channel. - unsafe { + let ret = unsafe { ffi::swr_convert( - self.as_ptr() as *mut _, + self.as_mut_ptr(), out_buffer, out_count, in_buffer as *mut _, in_count, ) } - .upgrade() - .map_err(RsmpegError::SwrConvertError) + .upgrade()?; + Ok(ret) } /// Convert the samples in the input `AVFrame` and write them to the output @@ -217,8 +175,7 @@ impl SwrContext { input.map(|x| x.as_ptr()).unwrap_or_else(ptr::null), ) } - .upgrade() - .map_err(RsmpegError::SwrConvertError)?; + .upgrade()?; Ok(()) } } diff --git a/tests/transcode_aac.rs b/tests/transcode_aac.rs index 419f4a9..74ea817 100644 --- a/tests/transcode_aac.rs +++ b/tests/transcode_aac.rs @@ -1,7 +1,6 @@ -// Due to usage of new channel layout api +//! RIIR: https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/transcode_aac.c use anyhow::{bail, Context as AnyhowContext, Result}; use cstr::cstr; -use once_cell::sync::Lazy as SyncLazy; use rsmpeg::{ avcodec::{AVCodec, AVCodecContext}, avformat::{AVFormatContextInput, AVFormatContextOutput}, @@ -10,18 +9,30 @@ use rsmpeg::{ ffi, swresample::SwrContext, }; -use std::{ffi::CStr, sync::Mutex}; +use std::{ + ffi::CStr, + sync::atomic::{AtomicI64, Ordering}, +}; + +/// The output bit rate in bit/s +const OUTPUT_BIT_RATE: i64 = 96000; +/// The number of output channels +const OUTPUT_CHANNELS: i32 = 2; fn open_input_file(input_file: &CStr) -> Result<(AVFormatContextInput, AVCodecContext, usize)> { - let input_format_context = - AVFormatContextInput::open(input_file, None, &mut None).context("Failed to get encoder")?; + let input_format_context = AVFormatContextInput::open(input_file, None, &mut None) + .context("Could not open input file")?; let (audio_index, decoder) = input_format_context .find_best_stream(ffi::AVMediaType_AVMEDIA_TYPE_AUDIO)? .context("Failed to find audio stream")?; + let stream = &input_format_context.streams()[audio_index]; let mut decode_context = AVCodecContext::new(&decoder); - decode_context.apply_codecpar(&input_format_context.streams()[audio_index].codecpar())?; - decode_context.open(None)?; + decode_context.apply_codecpar(&stream.codecpar())?; + decode_context + .open(None) + .context("Could not open input codec")?; + decode_context.set_pkt_timebase(stream.time_base); Ok((input_format_context, decode_context, audio_index)) } @@ -39,19 +50,13 @@ fn open_output_file( let mut encode_context = AVCodecContext::new(&encode_codec); - const OUTPUT_CHANNELS: i32 = 2; - const OUTPUT_BIT_RATE: i64 = 96000; // Set the basic encoder parameters. // The input file's sample rate is used to avoid a sample rate conversion. - encode_context.set_channels(OUTPUT_CHANNELS); encode_context.set_ch_layout(AVChannelLayout::from_nb_channels(OUTPUT_CHANNELS).into_inner()); encode_context.set_sample_rate(decode_context.sample_rate); encode_context.set_sample_fmt(encode_codec.sample_fmts().unwrap()[0]); encode_context.set_bit_rate(OUTPUT_BIT_RATE); - // Allow the use of the experimental AAC encoder. - encode_context.set_strict_std_compliance(ffi::FF_COMPLIANCE_EXPERIMENTAL); - // Open the encoder for the audio stream to use it later. encode_context.open(None)?; @@ -60,7 +65,7 @@ fn open_output_file( let mut stream = output_format_context.new_stream(); stream.set_codecpar(encode_context.extract_codecpar()); // Set the sample rate for the container. - stream.set_time_base(ra(decode_context.sample_rate, 1)); + stream.set_time_base(ra(1, decode_context.sample_rate)); } Ok((output_format_context, encode_context)) @@ -78,38 +83,41 @@ fn init_resampler( decode_context.sample_fmt, decode_context.sample_rate, ) - .context("Swrcontext parameters incorrect.")?; - resample_context.init()?; + .context("Could not allocate resample context")?; + resample_context + .init() + .context("Could not open resample context")?; Ok(resample_context) } fn add_samples_to_fifo( fifo: &mut AVAudioFifo, samples_buffer: &AVSamples, - num_samples: i32, + frame_size: i32, ) -> Result<()> { - fifo.realloc(fifo.size() + num_samples); - if unsafe { fifo.write(samples_buffer.audio_data.as_ptr(), num_samples) }? < num_samples { - bail!("samples doesn't all written."); - } + fifo.realloc(fifo.size() + frame_size); + unsafe { fifo.write(samples_buffer.audio_data.as_ptr(), frame_size) } + .context("Could not write data to FIFO")?; Ok(()) } -fn create_output_frame( +fn init_output_frame( nb_samples: i32, ch_layout: ffi::AVChannelLayout, sample_fmt: i32, sample_rate: i32, -) -> AVFrame { +) -> Result { let mut frame = AVFrame::new(); frame.set_nb_samples(nb_samples); frame.set_ch_layout(ch_layout); frame.set_format(sample_fmt); frame.set_sample_rate(sample_rate); - frame.alloc_buffer().unwrap(); - frame + .get_buffer(0) + .context("Could not allocate output frame samples")?; + + Ok(frame) } /// Return boolean: if data is written. @@ -118,12 +126,10 @@ fn encode_audio_frame( output_format_context: &mut AVFormatContextOutput, encode_context: &mut AVCodecContext, ) -> Result<()> { - static PTS: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); + static PTS: AtomicI64 = AtomicI64::new(0); if let Some(frame) = frame.as_mut() { - let mut pts = PTS.lock().unwrap(); - frame.set_pts(*pts); - *pts += frame.nb_samples as i64; + frame.set_pts(PTS.fetch_add(frame.nb_samples as i64, Ordering::Relaxed)); } encode_context.send_frame(frame.as_ref())?; @@ -133,10 +139,12 @@ fn encode_audio_frame( Err(RsmpegError::EncoderDrainError) | Err(RsmpegError::EncoderFlushedError) => { break; } - Err(e) => bail!(e), + Err(e) => Err(e).context("Could not encode frame")?, }; - output_format_context.write_frame(&mut packet)?; + output_format_context + .write_frame(&mut packet) + .context("Could not write frame")?; } Ok(()) } @@ -146,15 +154,15 @@ fn load_encode_and_write( output_format_context: &mut AVFormatContextOutput, encode_context: &mut AVCodecContext, ) -> Result<()> { - let nb_samples = fifo.size().min(encode_context.frame_size); - let mut frame = create_output_frame( - nb_samples, + let frame_size = fifo.size().min(encode_context.frame_size); + let mut frame = init_output_frame( + frame_size, encode_context.ch_layout().clone().into_inner(), encode_context.sample_fmt, encode_context.sample_rate, - ); - if unsafe { fifo.read(frame.data_mut().as_mut_ptr(), nb_samples)? } < nb_samples { - bail!("samples doesn't all read"); + )?; + if unsafe { fifo.read(frame.data_mut().as_mut_ptr(), frame_size)? } < frame_size { + bail!("Could not read data from FIFO"); } encode_audio_frame(Some(frame), output_format_context, encode_context)?; Ok(()) @@ -170,27 +178,36 @@ fn transcode_aac(input_file: &CStr, output_file: &CStr) -> Result<()> { open_output_file(output_file, &decode_context)?; // Initialize the resampler to be able to convert audio sample formats. - let resample_context = init_resampler(&mut decode_context, &mut encode_context)?; + let mut resample_context = init_resampler(&mut decode_context, &mut encode_context)?; // Initialize the FIFO buffer to store audio samples to be encoded. - let mut fifo = AVAudioFifo::new(encode_context.sample_fmt, encode_context.channels, 1); + let mut fifo = AVAudioFifo::new( + encode_context.sample_fmt, + encode_context.ch_layout.nb_channels, + 1, + ); // Write the header of the output file container. - output_format_context.write_header(&mut None)?; - - let output_nb_sample = encode_context.frame_size; + output_format_context + .write_header(&mut None) + .context("Could not write output file header")?; // Loop as long as we have input samples to read or output samples to write; // abort as soon as we have neither. loop { + let output_frame_size = encode_context.frame_size; + loop { // We get enough audio samples. - if fifo.size() >= output_nb_sample { + if fifo.size() >= output_frame_size { break; } // Break when no more input packets. - let packet = match input_format_context.read_packet()? { + let packet = match input_format_context + .read_packet() + .context("Could not read frame")? + { Some(x) => x, None => break, }; @@ -200,7 +217,9 @@ fn transcode_aac(input_file: &CStr, output_file: &CStr) -> Result<()> { continue; } - decode_context.send_packet(Some(&packet))?; + decode_context + .send_packet(Some(&packet)) + .context("Could not send packet for decoding")?; loop { let frame = match decode_context.receive_frame() { @@ -208,11 +227,11 @@ fn transcode_aac(input_file: &CStr, output_file: &CStr) -> Result<()> { Err(RsmpegError::DecoderDrainError) | Err(RsmpegError::DecoderFlushedError) => { break; } - Err(e) => bail!(e), + Err(e) => Err(e).context("Could not decode frame")?, }; let mut output_samples = AVSamples::new( - encode_context.channels, + encode_context.ch_layout.nb_channels, frame.nb_samples, encode_context.sample_fmt, 0, @@ -220,11 +239,14 @@ fn transcode_aac(input_file: &CStr, output_file: &CStr) -> Result<()> { .context("Create samples buffer failed.")?; unsafe { - resample_context.convert( - &mut output_samples, - frame.extended_data as *const _, - frame.nb_samples, - )?; + resample_context + .convert( + output_samples.audio_data.as_mut_ptr(), + output_samples.nb_samples, + frame.extended_data as *const _, + frame.nb_samples, + ) + .context("Could not convert input samples")?; } add_samples_to_fifo(&mut fifo, &output_samples, frame.nb_samples)?; @@ -232,12 +254,12 @@ fn transcode_aac(input_file: &CStr, output_file: &CStr) -> Result<()> { } // If we still cannot get enough samples, break. - if fifo.size() < output_nb_sample { + if fifo.size() < output_frame_size { break; } // Write frame as much as possible. - while fifo.size() >= output_nb_sample { + while fifo.size() >= output_frame_size { load_encode_and_write(&mut fifo, &mut output_format_context, &mut encode_context)?; } } @@ -245,7 +267,8 @@ fn transcode_aac(input_file: &CStr, output_file: &CStr) -> Result<()> { // Flush encode context encode_audio_frame(None, &mut output_format_context, &mut encode_context)?; - output_format_context.write_trailer().unwrap(); + output_format_context.write_trailer()?; + Ok(()) }