pub struct Output { /* private fields */ }
Implementations§
source§impl Output
impl Output
pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self
pub unsafe fn as_ptr(&self) -> *const AVFormatContext
pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext
source§impl Output
impl Output
sourcepub fn format(&self) -> Output
pub fn format(&self) -> Output
Examples found in repository?
examples/transcode-x264.rs (line 49)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
fn new(
ist: &format::stream::Stream,
octx: &mut format::context::Output,
ost_index: usize,
x264_opts: Dictionary,
enable_logging: bool,
) -> Result<Self, ffmpeg::Error> {
let global_header = octx.format().flags().contains(format::Flags::GLOBAL_HEADER);
let decoder = ffmpeg::codec::context::Context::from_parameters(ist.parameters())?
.decoder()
.video()?;
let mut ost = octx.add_stream(encoder::find(codec::Id::H264))?;
let mut encoder = codec::context::Context::from_parameters(ost.parameters())?
.encoder()
.video()?;
encoder.set_height(decoder.height());
encoder.set_width(decoder.width());
encoder.set_aspect_ratio(decoder.aspect_ratio());
encoder.set_format(decoder.format());
encoder.set_frame_rate(decoder.frame_rate());
encoder.set_time_base(decoder.frame_rate().unwrap().invert());
if global_header {
encoder.set_flags(codec::Flags::GLOBAL_HEADER);
}
encoder
.open_with(x264_opts)
.expect("error opening libx264 encoder with supplied settings");
encoder = codec::context::Context::from_parameters(ost.parameters())?
.encoder()
.video()?;
ost.set_parameters(&encoder);
Ok(Self {
ost_index,
decoder,
encoder: codec::context::Context::from_parameters(ost.parameters())?
.encoder()
.video()?,
logging_enabled: enable_logging,
frame_count: 0,
last_log_frame_count: 0,
starting_time: Instant::now(),
last_log_time: Instant::now(),
})
}
More examples
examples/transcode-audio.rs (line 77)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
fn transcoder<P: AsRef<Path>>(
ictx: &mut format::context::Input,
octx: &mut format::context::Output,
path: &P,
filter_spec: &str,
) -> Result<Transcoder, ffmpeg::Error> {
let input = ictx
.streams()
.best(media::Type::Audio)
.expect("could not find best audio stream");
let context = ffmpeg::codec::context::Context::from_parameters(input.parameters())?;
let mut decoder = context.decoder().audio()?;
let codec = ffmpeg::encoder::find(octx.format().codec(path, media::Type::Audio))
.expect("failed to find encoder")
.audio()?;
let global = octx
.format()
.flags()
.contains(ffmpeg::format::flag::Flags::GLOBAL_HEADER);
decoder.set_parameters(input.parameters())?;
let mut output = octx.add_stream(codec)?;
let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?;
let mut encoder = context.encoder().audio()?;
let channel_layout = codec
.channel_layouts()
.map(|cls| cls.best(decoder.channel_layout().channels()))
.unwrap_or(ffmpeg::channel_layout::ChannelLayout::STEREO);
if global {
encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER);
}
encoder.set_rate(decoder.rate() as i32);
encoder.set_channel_layout(channel_layout);
encoder.set_channels(channel_layout.channels());
encoder.set_format(
codec
.formats()
.expect("unknown supported formats")
.next()
.unwrap(),
);
encoder.set_bit_rate(decoder.bit_rate());
encoder.set_max_bit_rate(decoder.max_bit_rate());
encoder.set_time_base((1, decoder.rate() as i32));
output.set_time_base((1, decoder.rate() as i32));
let encoder = encoder.open_as(codec)?;
output.set_parameters(&encoder);
let filter = filter(filter_spec, &decoder, &encoder)?;
let in_time_base = decoder.time_base();
let out_time_base = output.time_base();
Ok(Transcoder {
stream: input.index(),
filter,
decoder,
encoder,
in_time_base,
out_time_base,
})
}
sourcepub fn write_header(&mut self) -> Result<(), Error>
pub fn write_header(&mut self) -> Result<(), Error>
Examples found in repository?
examples/transcode-audio.rs (line 226)
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
fn main() {
ffmpeg::init().unwrap();
let input = env::args().nth(1).expect("missing input");
let output = env::args().nth(2).expect("missing output");
let filter = env::args().nth(3).unwrap_or_else(|| "anull".to_owned());
let seek = env::args().nth(4).and_then(|s| s.parse::<i64>().ok());
let mut ictx = format::input(&input).unwrap();
let mut octx = format::output(&output).unwrap();
let mut transcoder = transcoder(&mut ictx, &mut octx, &output, &filter).unwrap();
if let Some(position) = seek {
// If the position was given in seconds, rescale it to ffmpegs base timebase.
let position = position.rescale((1, 1), rescale::TIME_BASE);
// If this seek was embedded in the transcoding loop, a call of `flush()`
// for every opened buffer after the successful seek would be advisable.
ictx.seek(position, ..position).unwrap();
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
if stream.index() == transcoder.stream {
packet.rescale_ts(stream.time_base(), transcoder.in_time_base);
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx);
}
}
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx);
transcoder.flush_filter();
transcoder.get_and_process_filtered_frames(&mut octx);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx);
octx.write_trailer().unwrap();
}
More examples
examples/remux.rs (line 43)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
ffmpeg::init().unwrap();
log::set_level(log::Level::Warning);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
let mut stream_mapping = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 1); ictx.nb_streams() as _];
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
ost_index += 1;
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost = octx.stream(ost_index as _).unwrap();
packet.rescale_ts(ist_time_bases[ist_index], ost.time_base());
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
octx.write_trailer().unwrap();
}
examples/transcode-x264.rs (line 235)
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
let x264_opts = parse_opts(
env::args()
.nth(3)
.unwrap_or_else(|| DEFAULT_X264_OPTS.to_string()),
)
.expect("invalid x264 options string");
eprintln!("x264 options: {:?}", x264_opts);
ffmpeg::init().unwrap();
log::set_level(log::Level::Info);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
format::context::input::dump(&ictx, 0, Some(&input_file));
let best_video_stream_index = ictx
.streams()
.best(media::Type::Video)
.map(|stream| stream.index());
let mut stream_mapping: Vec<isize> = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut ost_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut transcoders = HashMap::new();
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
if ist_medium == media::Type::Video {
// Initialize transcoder for video stream.
transcoders.insert(
ist_index,
Transcoder::new(
&ist,
&mut octx,
ost_index as _,
x264_opts.to_owned(),
Some(ist_index) == best_video_stream_index,
)
.unwrap(),
);
} else {
// Set up for stream copy for non-video stream.
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
ost_index += 1;
}
octx.set_metadata(ictx.metadata().to_owned());
format::context::output::dump(&octx, 0, Some(&output_file));
octx.write_header().unwrap();
for (ost_index, _) in octx.streams().enumerate() {
ost_time_bases[ost_index] = octx.stream(ost_index as _).unwrap().time_base();
}
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost_time_base = ost_time_bases[ost_index as usize];
match transcoders.get_mut(&ist_index) {
Some(transcoder) => {
packet.rescale_ts(stream.time_base(), transcoder.decoder.time_base());
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
}
None => {
// Do stream copy on non-video streams.
packet.rescale_ts(ist_time_bases[ist_index], ost_time_base);
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
}
}
// Flush encoders and decoders.
for (ost_index, transcoder) in transcoders.iter_mut() {
let ost_time_base = ost_time_bases[*ost_index];
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx, ost_time_base);
}
octx.write_trailer().unwrap();
}
pub fn write_header_with( &mut self, options: Dictionary<'_> ) -> Result<Dictionary<'_>, Error>
sourcepub fn write_trailer(&mut self) -> Result<(), Error>
pub fn write_trailer(&mut self) -> Result<(), Error>
Examples found in repository?
examples/transcode-audio.rs (line 245)
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
fn main() {
ffmpeg::init().unwrap();
let input = env::args().nth(1).expect("missing input");
let output = env::args().nth(2).expect("missing output");
let filter = env::args().nth(3).unwrap_or_else(|| "anull".to_owned());
let seek = env::args().nth(4).and_then(|s| s.parse::<i64>().ok());
let mut ictx = format::input(&input).unwrap();
let mut octx = format::output(&output).unwrap();
let mut transcoder = transcoder(&mut ictx, &mut octx, &output, &filter).unwrap();
if let Some(position) = seek {
// If the position was given in seconds, rescale it to ffmpegs base timebase.
let position = position.rescale((1, 1), rescale::TIME_BASE);
// If this seek was embedded in the transcoding loop, a call of `flush()`
// for every opened buffer after the successful seek would be advisable.
ictx.seek(position, ..position).unwrap();
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
if stream.index() == transcoder.stream {
packet.rescale_ts(stream.time_base(), transcoder.in_time_base);
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx);
}
}
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx);
transcoder.flush_filter();
transcoder.get_and_process_filtered_frames(&mut octx);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx);
octx.write_trailer().unwrap();
}
More examples
examples/remux.rs (line 58)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
ffmpeg::init().unwrap();
log::set_level(log::Level::Warning);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
let mut stream_mapping = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 1); ictx.nb_streams() as _];
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
ost_index += 1;
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost = octx.stream(ost_index as _).unwrap();
packet.rescale_ts(ist_time_bases[ist_index], ost.time_base());
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
octx.write_trailer().unwrap();
}
examples/transcode-x264.rs (line 273)
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
let x264_opts = parse_opts(
env::args()
.nth(3)
.unwrap_or_else(|| DEFAULT_X264_OPTS.to_string()),
)
.expect("invalid x264 options string");
eprintln!("x264 options: {:?}", x264_opts);
ffmpeg::init().unwrap();
log::set_level(log::Level::Info);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
format::context::input::dump(&ictx, 0, Some(&input_file));
let best_video_stream_index = ictx
.streams()
.best(media::Type::Video)
.map(|stream| stream.index());
let mut stream_mapping: Vec<isize> = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut ost_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut transcoders = HashMap::new();
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
if ist_medium == media::Type::Video {
// Initialize transcoder for video stream.
transcoders.insert(
ist_index,
Transcoder::new(
&ist,
&mut octx,
ost_index as _,
x264_opts.to_owned(),
Some(ist_index) == best_video_stream_index,
)
.unwrap(),
);
} else {
// Set up for stream copy for non-video stream.
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
ost_index += 1;
}
octx.set_metadata(ictx.metadata().to_owned());
format::context::output::dump(&octx, 0, Some(&output_file));
octx.write_header().unwrap();
for (ost_index, _) in octx.streams().enumerate() {
ost_time_bases[ost_index] = octx.stream(ost_index as _).unwrap().time_base();
}
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost_time_base = ost_time_bases[ost_index as usize];
match transcoders.get_mut(&ist_index) {
Some(transcoder) => {
packet.rescale_ts(stream.time_base(), transcoder.decoder.time_base());
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
}
None => {
// Do stream copy on non-video streams.
packet.rescale_ts(ist_time_bases[ist_index], ost_time_base);
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
}
}
// Flush encoders and decoders.
for (ost_index, transcoder) in transcoders.iter_mut() {
let ost_time_base = ost_time_bases[*ost_index];
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx, ost_time_base);
}
octx.write_trailer().unwrap();
}
sourcepub fn add_stream<E: Encoder>(
&mut self,
codec: E
) -> Result<StreamMut<'_>, Error>
pub fn add_stream<E: Encoder>( &mut self, codec: E ) -> Result<StreamMut<'_>, Error>
Examples found in repository?
examples/transcode-x264.rs (line 53)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
fn new(
ist: &format::stream::Stream,
octx: &mut format::context::Output,
ost_index: usize,
x264_opts: Dictionary,
enable_logging: bool,
) -> Result<Self, ffmpeg::Error> {
let global_header = octx.format().flags().contains(format::Flags::GLOBAL_HEADER);
let decoder = ffmpeg::codec::context::Context::from_parameters(ist.parameters())?
.decoder()
.video()?;
let mut ost = octx.add_stream(encoder::find(codec::Id::H264))?;
let mut encoder = codec::context::Context::from_parameters(ost.parameters())?
.encoder()
.video()?;
encoder.set_height(decoder.height());
encoder.set_width(decoder.width());
encoder.set_aspect_ratio(decoder.aspect_ratio());
encoder.set_format(decoder.format());
encoder.set_frame_rate(decoder.frame_rate());
encoder.set_time_base(decoder.frame_rate().unwrap().invert());
if global_header {
encoder.set_flags(codec::Flags::GLOBAL_HEADER);
}
encoder
.open_with(x264_opts)
.expect("error opening libx264 encoder with supplied settings");
encoder = codec::context::Context::from_parameters(ost.parameters())?
.encoder()
.video()?;
ost.set_parameters(&encoder);
Ok(Self {
ost_index,
decoder,
encoder: codec::context::Context::from_parameters(ost.parameters())?
.encoder()
.video()?,
logging_enabled: enable_logging,
frame_count: 0,
last_log_frame_count: 0,
starting_time: Instant::now(),
last_log_time: Instant::now(),
})
}
fn send_packet_to_decoder(&mut self, packet: &Packet) {
self.decoder.send_packet(packet).unwrap();
}
fn send_eof_to_decoder(&mut self) {
self.decoder.send_eof().unwrap();
}
fn receive_and_process_decoded_frames(
&mut self,
octx: &mut format::context::Output,
ost_time_base: Rational,
) {
let mut frame = frame::Video::empty();
while self.decoder.receive_frame(&mut frame).is_ok() {
self.frame_count += 1;
let timestamp = frame.timestamp();
self.log_progress(f64::from(
Rational(timestamp.unwrap_or(0) as i32, 1) * self.decoder.time_base(),
));
frame.set_pts(timestamp);
frame.set_kind(picture::Type::None);
self.send_frame_to_encoder(&frame);
self.receive_and_process_encoded_packets(octx, ost_time_base);
}
}
fn send_frame_to_encoder(&mut self, frame: &frame::Video) {
self.encoder.send_frame(frame).unwrap();
}
fn send_eof_to_encoder(&mut self) {
self.encoder.send_eof().unwrap();
}
fn receive_and_process_encoded_packets(
&mut self,
octx: &mut format::context::Output,
ost_time_base: Rational,
) {
let mut encoded = Packet::empty();
while self.encoder.receive_packet(&mut encoded).is_ok() {
encoded.set_stream(self.ost_index);
encoded.rescale_ts(self.decoder.time_base(), ost_time_base);
encoded.write_interleaved(octx).unwrap();
}
}
fn log_progress(&mut self, timestamp: f64) {
if !self.logging_enabled
|| (self.frame_count - self.last_log_frame_count < 100
&& self.last_log_time.elapsed().as_secs_f64() < 1.0)
{
return;
}
eprintln!(
"time elpased: \t{:8.2}\tframe count: {:8}\ttimestamp: {:8.2}",
self.starting_time.elapsed().as_secs_f64(),
self.frame_count,
timestamp
);
self.last_log_frame_count = self.frame_count;
self.last_log_time = Instant::now();
}
}
fn parse_opts<'a>(s: String) -> Option<Dictionary<'a>> {
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)
}
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
let x264_opts = parse_opts(
env::args()
.nth(3)
.unwrap_or_else(|| DEFAULT_X264_OPTS.to_string()),
)
.expect("invalid x264 options string");
eprintln!("x264 options: {:?}", x264_opts);
ffmpeg::init().unwrap();
log::set_level(log::Level::Info);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
format::context::input::dump(&ictx, 0, Some(&input_file));
let best_video_stream_index = ictx
.streams()
.best(media::Type::Video)
.map(|stream| stream.index());
let mut stream_mapping: Vec<isize> = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut ost_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut transcoders = HashMap::new();
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
if ist_medium == media::Type::Video {
// Initialize transcoder for video stream.
transcoders.insert(
ist_index,
Transcoder::new(
&ist,
&mut octx,
ost_index as _,
x264_opts.to_owned(),
Some(ist_index) == best_video_stream_index,
)
.unwrap(),
);
} else {
// Set up for stream copy for non-video stream.
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
ost_index += 1;
}
octx.set_metadata(ictx.metadata().to_owned());
format::context::output::dump(&octx, 0, Some(&output_file));
octx.write_header().unwrap();
for (ost_index, _) in octx.streams().enumerate() {
ost_time_bases[ost_index] = octx.stream(ost_index as _).unwrap().time_base();
}
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost_time_base = ost_time_bases[ost_index as usize];
match transcoders.get_mut(&ist_index) {
Some(transcoder) => {
packet.rescale_ts(stream.time_base(), transcoder.decoder.time_base());
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
}
None => {
// Do stream copy on non-video streams.
packet.rescale_ts(ist_time_bases[ist_index], ost_time_base);
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
}
}
// Flush encoders and decoders.
for (ost_index, transcoder) in transcoders.iter_mut() {
let ost_time_base = ost_time_bases[*ost_index];
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx, ost_time_base);
}
octx.write_trailer().unwrap();
}
More examples
examples/remux.rs (line 32)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
ffmpeg::init().unwrap();
log::set_level(log::Level::Warning);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
let mut stream_mapping = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 1); ictx.nb_streams() as _];
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
ost_index += 1;
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost = octx.stream(ost_index as _).unwrap();
packet.rescale_ts(ist_time_bases[ist_index], ost.time_base());
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
octx.write_trailer().unwrap();
}
examples/transcode-audio.rs (line 87)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
fn transcoder<P: AsRef<Path>>(
ictx: &mut format::context::Input,
octx: &mut format::context::Output,
path: &P,
filter_spec: &str,
) -> Result<Transcoder, ffmpeg::Error> {
let input = ictx
.streams()
.best(media::Type::Audio)
.expect("could not find best audio stream");
let context = ffmpeg::codec::context::Context::from_parameters(input.parameters())?;
let mut decoder = context.decoder().audio()?;
let codec = ffmpeg::encoder::find(octx.format().codec(path, media::Type::Audio))
.expect("failed to find encoder")
.audio()?;
let global = octx
.format()
.flags()
.contains(ffmpeg::format::flag::Flags::GLOBAL_HEADER);
decoder.set_parameters(input.parameters())?;
let mut output = octx.add_stream(codec)?;
let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?;
let mut encoder = context.encoder().audio()?;
let channel_layout = codec
.channel_layouts()
.map(|cls| cls.best(decoder.channel_layout().channels()))
.unwrap_or(ffmpeg::channel_layout::ChannelLayout::STEREO);
if global {
encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER);
}
encoder.set_rate(decoder.rate() as i32);
encoder.set_channel_layout(channel_layout);
encoder.set_channels(channel_layout.channels());
encoder.set_format(
codec
.formats()
.expect("unknown supported formats")
.next()
.unwrap(),
);
encoder.set_bit_rate(decoder.bit_rate());
encoder.set_max_bit_rate(decoder.max_bit_rate());
encoder.set_time_base((1, decoder.rate() as i32));
output.set_time_base((1, decoder.rate() as i32));
let encoder = encoder.open_as(codec)?;
output.set_parameters(&encoder);
let filter = filter(filter_spec, &decoder, &encoder)?;
let in_time_base = decoder.time_base();
let out_time_base = output.time_base();
Ok(Transcoder {
stream: input.index(),
filter,
decoder,
encoder,
in_time_base,
out_time_base,
})
}
sourcepub fn add_chapter<R: Into<Rational>, S: AsRef<str>>(
&mut self,
id: i64,
time_base: R,
start: i64,
end: i64,
title: S
) -> Result<ChapterMut<'_>, Error>
pub fn add_chapter<R: Into<Rational>, S: AsRef<str>>( &mut self, id: i64, time_base: R, start: i64, end: i64, title: S ) -> Result<ChapterMut<'_>, Error>
Examples found in repository?
examples/chapters.rs (lines 31-37)
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
fn main() {
ffmpeg::init().unwrap();
match ffmpeg::format::input(&env::args().nth(1).expect("missing input file name")) {
Ok(ictx) => {
println!("Nb chapters: {}", ictx.nb_chapters());
for chapter in ictx.chapters() {
println!("chapter id {}:", chapter.id());
println!("\ttime_base: {}", chapter.time_base());
println!("\tstart: {}", chapter.start());
println!("\tend: {}", chapter.end());
for (k, v) in chapter.metadata().iter() {
println!("\t{}: {}", k, v);
}
}
let mut octx = ffmpeg::format::output(&"test.mkv").expect("Couldn't open test file");
for chapter in ictx.chapters() {
let title = match chapter.metadata().get("title") {
Some(title) => String::from(title),
None => String::new(),
};
match octx.add_chapter(
chapter.id(),
chapter.time_base(),
chapter.start(),
chapter.end(),
&title,
) {
Ok(chapter) => println!("Added chapter with id {} to output", chapter.id()),
Err(error) => {
println!("Error adding chapter with id: {} - {}", chapter.id(), error)
}
}
}
println!("\nOuput: nb chapters: {}", octx.nb_chapters());
for chapter in octx.chapters() {
println!("chapter id {}:", chapter.id());
println!("\ttime_base: {}", chapter.time_base());
println!("\tstart: {}", chapter.start());
println!("\tend: {}", chapter.end());
for (k, v) in chapter.metadata().iter() {
println!("\t{}: {}", k, v);
}
}
}
Err(error) => println!("error: {}", error),
}
}
sourcepub fn set_metadata(&mut self, dictionary: Dictionary<'_>)
pub fn set_metadata(&mut self, dictionary: Dictionary<'_>)
Examples found in repository?
examples/transcode-audio.rs (line 225)
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
fn main() {
ffmpeg::init().unwrap();
let input = env::args().nth(1).expect("missing input");
let output = env::args().nth(2).expect("missing output");
let filter = env::args().nth(3).unwrap_or_else(|| "anull".to_owned());
let seek = env::args().nth(4).and_then(|s| s.parse::<i64>().ok());
let mut ictx = format::input(&input).unwrap();
let mut octx = format::output(&output).unwrap();
let mut transcoder = transcoder(&mut ictx, &mut octx, &output, &filter).unwrap();
if let Some(position) = seek {
// If the position was given in seconds, rescale it to ffmpegs base timebase.
let position = position.rescale((1, 1), rescale::TIME_BASE);
// If this seek was embedded in the transcoding loop, a call of `flush()`
// for every opened buffer after the successful seek would be advisable.
ictx.seek(position, ..position).unwrap();
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
if stream.index() == transcoder.stream {
packet.rescale_ts(stream.time_base(), transcoder.in_time_base);
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx);
}
}
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx);
transcoder.flush_filter();
transcoder.get_and_process_filtered_frames(&mut octx);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx);
octx.write_trailer().unwrap();
}
More examples
examples/remux.rs (line 42)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
ffmpeg::init().unwrap();
log::set_level(log::Level::Warning);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
let mut stream_mapping = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 1); ictx.nb_streams() as _];
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
ost_index += 1;
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
octx.set_metadata(ictx.metadata().to_owned());
octx.write_header().unwrap();
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost = octx.stream(ost_index as _).unwrap();
packet.rescale_ts(ist_time_bases[ist_index], ost.time_base());
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
octx.write_trailer().unwrap();
}
examples/transcode-x264.rs (line 233)
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
fn main() {
let input_file = env::args().nth(1).expect("missing input file");
let output_file = env::args().nth(2).expect("missing output file");
let x264_opts = parse_opts(
env::args()
.nth(3)
.unwrap_or_else(|| DEFAULT_X264_OPTS.to_string()),
)
.expect("invalid x264 options string");
eprintln!("x264 options: {:?}", x264_opts);
ffmpeg::init().unwrap();
log::set_level(log::Level::Info);
let mut ictx = format::input(&input_file).unwrap();
let mut octx = format::output(&output_file).unwrap();
format::context::input::dump(&ictx, 0, Some(&input_file));
let best_video_stream_index = ictx
.streams()
.best(media::Type::Video)
.map(|stream| stream.index());
let mut stream_mapping: Vec<isize> = vec![0; ictx.nb_streams() as _];
let mut ist_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut ost_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _];
let mut transcoders = HashMap::new();
let mut ost_index = 0;
for (ist_index, ist) in ictx.streams().enumerate() {
let ist_medium = ist.parameters().medium();
if ist_medium != media::Type::Audio
&& ist_medium != media::Type::Video
&& ist_medium != media::Type::Subtitle
{
stream_mapping[ist_index] = -1;
continue;
}
stream_mapping[ist_index] = ost_index;
ist_time_bases[ist_index] = ist.time_base();
if ist_medium == media::Type::Video {
// Initialize transcoder for video stream.
transcoders.insert(
ist_index,
Transcoder::new(
&ist,
&mut octx,
ost_index as _,
x264_opts.to_owned(),
Some(ist_index) == best_video_stream_index,
)
.unwrap(),
);
} else {
// Set up for stream copy for non-video stream.
let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap();
ost.set_parameters(ist.parameters());
// We need to set codec_tag to 0 lest we run into incompatible codec tag
// issues when muxing into a different container format. Unfortunately
// there's no high level API to do this (yet).
unsafe {
(*ost.parameters().as_mut_ptr()).codec_tag = 0;
}
}
ost_index += 1;
}
octx.set_metadata(ictx.metadata().to_owned());
format::context::output::dump(&octx, 0, Some(&output_file));
octx.write_header().unwrap();
for (ost_index, _) in octx.streams().enumerate() {
ost_time_bases[ost_index] = octx.stream(ost_index as _).unwrap().time_base();
}
for (stream, mut packet) in ictx.packets() {
let ist_index = stream.index();
let ost_index = stream_mapping[ist_index];
if ost_index < 0 {
continue;
}
let ost_time_base = ost_time_bases[ost_index as usize];
match transcoders.get_mut(&ist_index) {
Some(transcoder) => {
packet.rescale_ts(stream.time_base(), transcoder.decoder.time_base());
transcoder.send_packet_to_decoder(&packet);
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
}
None => {
// Do stream copy on non-video streams.
packet.rescale_ts(ist_time_bases[ist_index], ost_time_base);
packet.set_position(-1);
packet.set_stream(ost_index as _);
packet.write_interleaved(&mut octx).unwrap();
}
}
}
// Flush encoders and decoders.
for (ost_index, transcoder) in transcoders.iter_mut() {
let ost_time_base = ost_time_bases[*ost_index];
transcoder.send_eof_to_decoder();
transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base);
transcoder.send_eof_to_encoder();
transcoder.receive_and_process_encoded_packets(&mut octx, ost_time_base);
}
octx.write_trailer().unwrap();
}