|
| 1 | +extern crate ffmpeg_the_third as ffmpeg; |
| 2 | + |
| 3 | +use ffmpeg::{codec, format, frame, media, picture, software}; |
| 4 | +use std::env; |
| 5 | + |
| 6 | +fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 7 | + ffmpeg::init()?; |
| 8 | + |
| 9 | + let width = 1920; |
| 10 | + let height = 1080; |
| 11 | + let input_file = env::args().nth(1).expect("missing input file"); |
| 12 | + let output_file = env::args().nth(2).expect("missing output file"); |
| 13 | + |
| 14 | + // 打开输入/输出文件 |
| 15 | + let mut input_context = format::input(&input_file)?; |
| 16 | + let mut output_context = format::output(&output_file)?; |
| 17 | + |
| 18 | + // 获取视频流信息 |
| 19 | + let input_stream = input_context |
| 20 | + .streams() |
| 21 | + .best(media::Type::Video) |
| 22 | + .ok_or("no video stream found")?; |
| 23 | + let input_stream_index = input_stream.index(); |
| 24 | + let input_codec_context = codec::context::Context::from_parameters(input_stream.parameters())?; |
| 25 | + |
| 26 | + // 创建解码器 |
| 27 | + let mut decoder = input_codec_context.decoder().video().unwrap(); |
| 28 | + |
| 29 | + // 使用标准的帧率值(如 25fps) |
| 30 | + let frame_rate = ffmpeg::Rational::new(25, 1); |
| 31 | + // 使用标准的时基值(如 1/90000) |
| 32 | + let time_base = ffmpeg::Rational::new(1, 90000); |
| 33 | + println!("frame rate: {:?}, time base: {:?}", frame_rate, time_base); |
| 34 | + |
| 35 | + // 创建和配置编码器 |
| 36 | + let codec = codec::encoder::find(codec::Id::H264); |
| 37 | + let mut encoder = codec::context::Context::new_with_codec(codec.unwrap()) |
| 38 | + .encoder() |
| 39 | + .video()?; |
| 40 | + |
| 41 | + // 设置编码器参数 |
| 42 | + encoder.set_height(height); |
| 43 | + encoder.set_width(width); |
| 44 | + encoder.set_aspect_ratio(decoder.aspect_ratio()); |
| 45 | + encoder.set_format(decoder.format()); |
| 46 | + encoder.set_frame_rate(Some(frame_rate)); |
| 47 | + encoder.set_time_base(time_base); |
| 48 | + encoder.set_max_b_frames(0); |
| 49 | + encoder.set_gop(12); |
| 50 | + // 设置一些H.264特定的参数 |
| 51 | + encoder.set_bit_rate(2_000_000); |
| 52 | + |
| 53 | + let mut encoder = encoder.open_as(codec)?; |
| 54 | + |
| 55 | + // 创建输出流 |
| 56 | + let mut output_stream = output_context.add_stream(codec)?; |
| 57 | + output_stream.set_parameters_into(&encoder); |
| 58 | + output_context.write_header()?; |
| 59 | + |
| 60 | + // 创建缩放器 |
| 61 | + let mut scaler = software::scaling::Context::get( |
| 62 | + decoder.format(), |
| 63 | + decoder.width(), |
| 64 | + decoder.height(), |
| 65 | + encoder.format(), |
| 66 | + encoder.width(), |
| 67 | + encoder.height(), |
| 68 | + software::scaling::Flags::BILINEAR, |
| 69 | + )?; |
| 70 | + |
| 71 | + // 创建帧缓冲 |
| 72 | + let mut decoded_frame = frame::Video::empty(); |
| 73 | + let mut scaled_frame = frame::Video::empty(); |
| 74 | + let mut frame_count: i64 = 0; |
| 75 | + |
| 76 | + println!("video resize start..."); |
| 77 | + |
| 78 | + // 计算每帧的时间增量(以时基为单位) |
| 79 | + // 90000/25 = 3600,每帧增加3600个时基单位 |
| 80 | + let time_increment = 90000_i64 / 25; |
| 81 | + |
| 82 | + // 处理视频帧 |
| 83 | + for (stream, packet) in input_context.packets().filter_map(Result::ok) { |
| 84 | + if stream.index() == input_stream_index { |
| 85 | + decoder.send_packet(&packet)?; |
| 86 | + |
| 87 | + while decoder.receive_frame(&mut decoded_frame).is_ok() { |
| 88 | + // 缩放 |
| 89 | + scaler.run(&decoded_frame, &mut scaled_frame)?; |
| 90 | + |
| 91 | + // 计算正确的时间戳 (pts) |
| 92 | + let pts = frame_count * time_increment; |
| 93 | + scaled_frame.set_pts(Some(pts)); |
| 94 | + scaled_frame.set_kind(picture::Type::None); |
| 95 | + |
| 96 | + // println!("send frame to encoder, pts: {}, time: {:.3}s", pts, pts as f64 / 90000.0); |
| 97 | + encoder.send_frame(&scaled_frame)?; |
| 98 | + |
| 99 | + // 获取编码后的数据包 |
| 100 | + let mut encoded_packet = codec::packet::Packet::empty(); |
| 101 | + while encoder.receive_packet(&mut encoded_packet).is_ok() { |
| 102 | + encoded_packet.set_stream(0); |
| 103 | + encoded_packet.set_pts(Some(pts)); |
| 104 | + encoded_packet.set_dts(Some(pts)); |
| 105 | + // 写入数据包 |
| 106 | + encoded_packet.write_interleaved(&mut output_context)?; |
| 107 | + } |
| 108 | + |
| 109 | + frame_count += 1; |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + // 刷新编码器 |
| 115 | + encoder.send_eof()?; |
| 116 | + let mut packet = codec::packet::Packet::empty(); |
| 117 | + while encoder.receive_packet(&mut packet).is_ok() { |
| 118 | + let pts = frame_count * time_increment; |
| 119 | + packet.set_stream(0); |
| 120 | + packet.set_pts(Some(pts)); |
| 121 | + packet.set_dts(Some(pts)); |
| 122 | + packet.write_interleaved(&mut output_context)?; |
| 123 | + frame_count += 1; |
| 124 | + } |
| 125 | + |
| 126 | + // 写入文件尾部 |
| 127 | + output_context.write_trailer()?; |
| 128 | + |
| 129 | + println!("video resize complete: {}", output_file); |
| 130 | + println!("total frames processed: {}", frame_count); |
| 131 | + |
| 132 | + Ok(()) |
| 133 | +} |
0 commit comments