How to copy a stream to output?
niuhuan opened this issue · comments
THANK for you help first. This is not a problem. I can't skilled rusty_ffmpeg.
I wan't to merge a 1.video and 1.audio to 1.mp4.
I got streams use rusty_ffmpeg example
.video STREAMS
------------
AVStream->time_base before open coded 1/16000
AVStream->r_frame_rate before open coded 24000/1001
AVStream->start_time 0
AVStream->duration 10171499
finding the proper decoder (CODEC)
Video Codec: resolution 1920 x 1080
Codec h264 ID 27 bit_rate 1790212
------------
.audio STREAMS
------------
AVStream->time_base before open coded 1/48000
AVStream->r_frame_rate before open coded 0/0
AVStream->start_time 0
AVStream->duration 30518264
finding the proper decoder (CODEC)
Audio Codec: 2 channels, sample rate 48000
Codec aac ID 86018 bit_rate 128438
------------
This is I write rust code,
I want to know what I will do after avcodec_parameters_copy
use rusty_ffmpeg::ffi;
use rusty_ffmpeg::ffi::AVFormatContext;
use std::{
ffi::{CStr, CString},
fs::File,
io::Write,
ptr, slice,
};
fn main() {
main2(
"D:/tests/1.audio",
"D:/tests/1.video",
"D:/tests/1.mp4",
)
}
fn main2(audio: &str, video: &str, mp4: &str) {
// open MP4
let mp4_cstr: CString = CString::new(mp4).unwrap();
let mut format_context_ptr_mp4 = unsafe { ffi::avformat_alloc_context() };
if format_context_ptr_mp4.is_null() {
panic!("ERROR could not allocate memory for Format Context");
}
if unsafe {
ffi::avformat_alloc_output_context2(
&mut format_context_ptr_mp4,
ptr::null_mut(),
ptr::null_mut(),
mp4_cstr.as_ptr(),
)
} != 0
{
panic!("ERROR could not open the file");
}
// open audio
let audio_cstr: CString = CString::new(audio).unwrap();
let mut format_context_ptr_audio = unsafe { ffi::avformat_alloc_context() };
if format_context_ptr_audio.is_null() {
panic!("ERROR could not allocate memory for Format Context");
}
if unsafe {
ffi::avformat_open_input(
&mut format_context_ptr_audio,
audio_cstr.as_ptr(),
ptr::null_mut(),
ptr::null_mut(),
)
} != 0
{
panic!("ERROR could not open the file");
}
let audio_format_context = unsafe { format_context_ptr_audio.as_mut() }.unwrap();
let audio_streams = unsafe {
slice::from_raw_parts(
audio_format_context.streams,
audio_format_context.nb_streams as usize,
)
};
//
for (i, audio_stream) in audio_streams
.iter()
.map(|stream| unsafe { stream.as_ref() }.unwrap())
.enumerate()
{
// audio
let local_codec_params = unsafe { audio_stream.codecpar.as_ref() }.unwrap();
let local_codec =
unsafe { ffi::avcodec_find_decoder(local_codec_params.codec_id).as_ref() }
.expect("ERROR unsupported codec!");
let codec_name = unsafe { CStr::from_ptr(local_codec.name) }
.to_str()
.unwrap();
println!("from {}", codec_name);
// copy params to mp4
let mut out_stream = unsafe {
ffi::avformat_new_stream(format_context_ptr_mp4, local_codec)
.as_ref()
.expect("ERROR unsupported out_stream!")
};
let ret = unsafe { ffi::avcodec_parameters_copy(out_stream.codecpar, local_codec_params) };
if ret != 0 {
panic!("ERROR avcodec_parameters_copy");
}
///
}
}
After copying audio parameters to the output audio streams, you also need to copy video parameters to the output video stream.
After that, you need to extract packets from the video and audio files, then feed them to the output format context.
Dealing with raw FFmpeg
api is not that easy, you can try the high level wrapper of rusty_ffmpeg: rsmpeg, there are some code examples under its tests folder you can refer from.