
Recherche avancée
Autres articles (4)
-
Support de tous types de médias
10 avril 2011Contrairement à beaucoup de logiciels et autres plate-formes modernes de partage de documents, MediaSPIP a l’ambition de gérer un maximum de formats de documents différents qu’ils soient de type : images (png, gif, jpg, bmp et autres...) ; audio (MP3, Ogg, Wav et autres...) ; vidéo (Avi, MP4, Ogv, mpg, mov, wmv et autres...) ; contenu textuel, code ou autres (open office, microsoft office (tableur, présentation), web (html, css), LaTeX, Google Earth) (...)
-
Supporting all media types
13 avril 2011, parUnlike most software and media-sharing platforms, MediaSPIP aims to manage as many different media types as possible. The following are just a few examples from an ever-expanding list of supported formats : images : png, gif, jpg, bmp and more audio : MP3, Ogg, Wav and more video : AVI, MP4, OGV, mpg, mov, wmv and more text, code and other data : OpenOffice, Microsoft Office (Word, PowerPoint, Excel), web (html, CSS), LaTeX, Google Earth and (...)
-
MediaSPIP Init et Diogène : types de publications de MediaSPIP
11 novembre 2010, parÀ l’installation d’un site MediaSPIP, le plugin MediaSPIP Init réalise certaines opérations dont la principale consiste à créer quatre rubriques principales dans le site et de créer cinq templates de formulaire pour Diogène.
Ces quatre rubriques principales (aussi appelées secteurs) sont : Medias ; Sites ; Editos ; Actualités ;
Pour chacune de ces rubriques est créé un template de formulaire spécifique éponyme. Pour la rubrique "Medias" un second template "catégorie" est créé permettant d’ajouter (...)
Sur d’autres sites (3551)
-
ffmpeg-next potential bug in write_header causes timebase to bet set to Rational(1/15360)
7 septembre 2024, par HuhngutI am trying to encode a video using the ffmpeg_next crate. I got everything working and it successfully creates an output video.
The only problem is that the time_base of my stream is wrongly written to the file.
I can confirm that I set the timebase correctly for both the encoder as well as the stream.


By debug prints I was able to narrow the problem down.
octx.write_header().unwrap();
causes the stream timebase to be reset from Rational(1/30) to Rational(1/15360). Changing the timebase back afterwards has no effect. The wrong value must have been written to the header.

I modified the src code of ffmpeg-next and recompiled it. I can confirm that the correct value is set before the call to
avformat_write_header


pub fn write_header(&mut self) -> Result<(), Error> {
 println!(
 "_________________ {:?}",
 self.stream(0).unwrap().time_base()
 );
 unsafe {
 match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) {
 0 => Ok(()),
 e => Err(Error::from(e)),
 }
 }
 }



To my understanding this must be a bug in the crate but I dont want to accuse someone with my non existing knowledge about ffmpeg. Also the examples in the github repo seem not to have this problem. My fault then ? Unfortunately I was not able to get the transcode-x264 to run. Most of my code comes from this example.


Relevant code bits are these. I dont know how much the set_parameters influences anything. My testing said it has no influence. I also tried to set the timebase at the very end of the function if it gets reset my the parameters. This is not working


let mut ost = octx.add_stream(codec)?;
ost.set_time_base(Rational::new(1, FPS));

ost.set_parameters(&encoder);
encoder.set_time_base(Rational::new(1, FPS));
ost.set_parameters(&opened_encoder);



By default and in the above example the streams timebase is 0/0. If I leave it out or change it to this manually it has no effect.


I also noticed that changing the value inside set_pts influences the output fps. Although not the timebase. I think this is more of a sideeffect.


I will leave a minimal reproducible example below. Any help or hints would be appreciated


abstract main function


fn main() {
 let output_file = "output.mp4";
 let x264_opts = parse_opts("preset=medium".to_string()).expect("invalid x264 options string");

 ffmpeg_next::init().unwrap();
 let mut octx = format::output(output_file).unwrap();

 let mut encoder = Encoder::new(&mut octx, x264_opts).unwrap();

 format::context::output::dump(&octx, 0, Some(&output_file));
 //This line somehow clears the streams time base
 octx.write_header().unwrap();

 // Without this line, the next logs returns Rational(1/30) Rational(1/15360) indicating streams timebase is wrong. even thought I set it above
 // this line changes it back but only for the print but not the actual output. Because the faulty data is written into the header
 // octx.stream_mut(0)
 // .unwrap()
 // .set_time_base(Rational::new(1, FPS));

 println!(
 "---------------- {:?} {:?}",
 encoder.encoder.time_base(),
 octx.stream(0).unwrap().time_base(),
 );

 for frame_num in 0..100 {
 let mut frame = encoder.create_frame();
 frame.set_pts(Some(frame_num));
 encoder.add_frame(&frame, &mut octx);
 }

 encoder.close(&mut octx);
 octx.write_trailer().unwrap();
}



Encoder struct containing the implementation logic


struct Encoder {
 encoder: encoder::Video,
}

impl Encoder {
 fn new(
 octx: &mut format::context::Output,
 x264_opts: Dictionary,
 ) -> Result {
 let set_header = octx
 .format()
 .flags()
 .contains(ffmpeg_next::format::flag::Flags::GLOBAL_HEADER);

 let codec = encoder::find(codec::Id::H264);
 let mut ost = octx.add_stream(codec)?;
 ost.set_time_base(Rational::new(1, FPS));

 let mut encoder = codec::context::Context::new_with_codec(
 encoder::find(codec::Id::H264)
 .ok_or(ffmpeg_next::Error::InvalidData)
 .unwrap(),
 )
 .encoder()
 .video()
 .unwrap();
 ost.set_parameters(&encoder);

 encoder.set_width(WIDTH);
 encoder.set_height(HEIGHT);
 encoder.set_aspect_ratio(WIDTH as f64 / HEIGHT as f64);
 encoder.set_format(util::format::Pixel::YUV420P);
 encoder.set_frame_rate(Some(Rational::new(FPS, 1)));
 encoder.set_time_base(Rational::new(1, FPS));

 if set_header {
 encoder.set_flags(ffmpeg_next::codec::flag::Flags::GLOBAL_HEADER);
 }

 let opened_encoder = encoder
 .open_with(x264_opts.to_owned())
 .expect("error opening x264 with supplied settings");
 ost.set_parameters(&opened_encoder);

 println!(
 "\nost time_base: {}; encoder time_base: {}; encoder frame_rate: {}\n",
 ost.time_base(),
 &opened_encoder.time_base(),
 &opened_encoder.frame_rate()
 );

 Ok(Self {
 encoder: opened_encoder,
 })
 }

 fn add_frame(&mut self, frame: &frame::Video, octx: &mut format::context::Output) {
 self.encoder.send_frame(frame).unwrap();
 self.process_packets(octx);
 }

 fn close(&mut self, octx: &mut format::context::Output) {
 self.encoder.send_eof().unwrap();
 self.process_packets(octx);
 }

 fn process_packets(&mut self, octx: &mut format::context::Output) {
 let mut encoded = Packet::empty();
 while self.encoder.receive_packet(&mut encoded).is_ok() {
 encoded.set_stream(0);
 encoded.write_interleaved(octx).unwrap();
 }
 }

 fn create_frame(&self) -> frame::Video {
 return frame::Video::new(
 self.encoder.format(),
 self.encoder.width(),
 self.encoder.height(),
 );
 }
}



other util stuff


use ffmpeg_next::{
 codec::{self},
 encoder, format, frame, util, Dictionary, Packet, Rational,
};

const FPS: i32 = 30;
const WIDTH: u32 = 720;
const HEIGHT: u32 = 1080;

fn parse_opts<'a>(s: String) -> Option> {
 let mut dict = Dictionary::new();
 for keyval in s.split_terminator(',') {
 let tokens: Vec<&str> = keyval.split('=').collect();
 match tokens[..] {
 [key, val] => dict.set(key, val),
 _ => return None,
 }
 }
 Some(dict)
}



-
Revision 32594 : plugins en minuscules, et alias pour les noms de sites
1er novembre 2009, par fil@… — Logplugins en minuscules, et alias pour les noms de sites