CCExtractor / rusty_ffmpeg

FFI bindings for FFmpeg inner libraries.

Home Page:https://crates.io/crates/rusty_ffmpeg

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.