mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-19 13:55:40 -04:00
Refactor: Introduce FFmpegPacket RAII wrapper
Co-authored-by: ijamespine <ijamespine@me.com>
This commit is contained in:
@@ -4,15 +4,14 @@ use crate::{
|
||||
codec_ctx::FFmpegCodecContext,
|
||||
error::{Error, FFmpegError},
|
||||
format_ctx::FFmpegFormatContext,
|
||||
packet::FFmpegPacket,
|
||||
utils::from_path,
|
||||
video_frame::FFmpegFrame,
|
||||
};
|
||||
|
||||
use std::{path::Path, slice};
|
||||
|
||||
use ffmpeg_sys_next::{
|
||||
av_frame_alloc, av_frame_free, av_packet_alloc, av_packet_free, av_packet_unref, av_read_frame,
|
||||
avcodec_find_decoder, AVFrame, AVMediaType, AVSampleFormat,
|
||||
};
|
||||
use ffmpeg_sys_next::{av_read_frame, avcodec_find_decoder, AVFrame, AVMediaType, AVSampleFormat};
|
||||
|
||||
/// Extract audio samples from a media file as 16kHz mono f32 PCM
|
||||
pub fn extract_audio_samples(filename: impl AsRef<Path>) -> Result<Vec<f32>, Error> {
|
||||
@@ -46,57 +45,44 @@ pub fn extract_audio_samples(filename: impl AsRef<Path>) -> Result<Vec<f32>, Err
|
||||
codec_ctx.parameters_to_context(codecpar)?;
|
||||
codec_ctx.open2(decoder)?;
|
||||
|
||||
// Allocate packet and frame
|
||||
let packet = av_packet_alloc();
|
||||
if packet.is_null() {
|
||||
return Err(FFmpegError::NullError.into());
|
||||
}
|
||||
|
||||
let frame = av_frame_alloc();
|
||||
if frame.is_null() {
|
||||
av_packet_free(&packet as *const _ as *mut _);
|
||||
return Err(FFmpegError::FrameAllocation.into());
|
||||
}
|
||||
// Allocate packet and frame using RAII wrappers for automatic cleanup
|
||||
let mut packet = FFmpegPacket::new()?;
|
||||
let mut frame = FFmpegFrame::new()?;
|
||||
|
||||
let mut samples = Vec::new();
|
||||
|
||||
// Read and decode packets
|
||||
while av_read_frame(format_ctx.as_mut(), packet) >= 0 {
|
||||
while av_read_frame(format_ctx.as_mut(), packet.as_ptr()) >= 0 {
|
||||
let pkt = packet.as_ref().ok_or(FFmpegError::NullError)?;
|
||||
|
||||
if pkt.stream_index == audio_stream_index {
|
||||
// Send packet to decoder
|
||||
if codec_ctx.send_packet(packet).is_err() {
|
||||
av_packet_unref(packet);
|
||||
if codec_ctx.send_packet(packet.as_ptr()).is_err() {
|
||||
packet.unref();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Receive decoded frames
|
||||
loop {
|
||||
match codec_ctx.receive_frame(frame) {
|
||||
match codec_ctx.receive_frame(frame.as_mut()) {
|
||||
Ok(true) => {
|
||||
let frame_ref = frame.as_ref().ok_or(FFmpegError::NullError)?;
|
||||
// Extract samples from this frame
|
||||
let frame_samples = extract_and_convert_frame(frame_ref)?;
|
||||
let frame_samples = extract_and_convert_frame(frame.as_ref())?;
|
||||
samples.extend_from_slice(&frame_samples);
|
||||
}
|
||||
Ok(false) | Err(FFmpegError::Again) => break,
|
||||
Err(e) => {
|
||||
av_packet_unref(packet);
|
||||
av_frame_free(&frame as *const _ as *mut _);
|
||||
av_packet_free(&packet as *const _ as *mut _);
|
||||
// RAII wrappers handle cleanup automatically via Drop
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
av_packet_unref(packet);
|
||||
packet.unref();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
av_frame_free(&frame as *const _ as *mut _);
|
||||
av_packet_free(&packet as *const _ as *mut _);
|
||||
// RAII wrappers handle cleanup automatically when they go out of scope
|
||||
|
||||
// Now resample to 16kHz mono if needed
|
||||
let codec_ref = codec_ctx.as_ref();
|
||||
|
||||
@@ -41,6 +41,7 @@ mod filter_graph;
|
||||
mod format_ctx;
|
||||
mod frame_decoder;
|
||||
pub mod model;
|
||||
mod packet;
|
||||
mod thumbnailer;
|
||||
mod utils;
|
||||
mod video_frame;
|
||||
|
||||
37
crates/ffmpeg/src/packet.rs
Normal file
37
crates/ffmpeg/src/packet.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use crate::error::FFmpegError;
|
||||
use ffmpeg_sys_next::{av_packet_alloc, av_packet_free, av_packet_unref, AVPacket};
|
||||
|
||||
pub struct FFmpegPacket(*mut AVPacket);
|
||||
|
||||
impl FFmpegPacket {
|
||||
pub(crate) fn new() -> Result<Self, FFmpegError> {
|
||||
let ptr = unsafe { av_packet_alloc() };
|
||||
if ptr.is_null() {
|
||||
return Err(FFmpegError::NullError);
|
||||
}
|
||||
Ok(Self(ptr))
|
||||
}
|
||||
|
||||
pub(crate) fn as_ptr(&self) -> *mut AVPacket {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn as_ref(&self) -> Option<&AVPacket> {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
|
||||
pub(crate) fn unref(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { av_packet_unref(self.0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FFmpegPacket {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { av_packet_free(&mut self.0) };
|
||||
self.0 = std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user