@@ -16,6 +16,7 @@ pub struct H264EncoderBuilder {
1616 bpp : f32 ,
1717 input_config : VideoInfo ,
1818 preset : H264Preset ,
19+ output_size : Option < ( u32 , u32 ) > ,
1920}
2021
2122#[ derive( Clone , Copy ) ]
@@ -43,6 +44,7 @@ impl H264EncoderBuilder {
4344 input_config,
4445 bpp : Self :: QUALITY_BPP ,
4546 preset : H264Preset :: Ultrafast ,
47+ output_size : None ,
4648 }
4749 }
4850
@@ -56,45 +58,95 @@ impl H264EncoderBuilder {
5658 self
5759 }
5860
61+ pub fn with_output_size ( mut self , width : u32 , height : u32 ) -> Self {
62+ if width == 0 || height == 0 {
63+ self . output_size = None ;
64+ } else {
65+ self . output_size = Some ( ( width, height) ) ;
66+ }
67+ self
68+ }
69+
5970 pub fn build (
6071 self ,
6172 output : & mut format:: context:: Output ,
6273 ) -> Result < H264Encoder , H264EncoderError > {
63- let input_config = & self . input_config ;
64- let ( codec, encoder_options) = get_codec_and_options ( input_config, self . preset )
74+ let input_config = self . input_config ;
75+ let ( codec, encoder_options) = get_codec_and_options ( & input_config, self . preset )
6576 . ok_or ( H264EncoderError :: CodecNotFound ) ?;
6677
67- let ( format, converter) = if !codec
68- . video ( )
69- . unwrap ( )
78+ let ( mut output_width, mut output_height) = self
79+ . output_size
80+ . unwrap_or ( ( input_config. width , input_config. height ) ) ;
81+
82+ if output_width == 0 || output_height == 0 {
83+ output_width = input_config. width ;
84+ output_height = input_config. height ;
85+ }
86+
87+ let codec_video = codec. video ( ) . unwrap ( ) ;
88+ let encoder_supports_input_format = codec_video
7089 . formats ( )
7190 . unwrap ( )
72- . any ( |f| f == input_config. pixel_format )
73- {
91+ . any ( |f| f == input_config. pixel_format ) ;
92+
93+ let mut needs_pixel_conversion = false ;
94+
95+ let output_format = if encoder_supports_input_format {
96+ input_config. pixel_format
97+ } else {
98+ needs_pixel_conversion = true ;
7499 let format = ffmpeg:: format:: Pixel :: NV12 ;
75100 debug ! (
76101 "Converting from {:?} to {:?} for H264 encoding" ,
77102 input_config. pixel_format, format
78103 ) ;
79- (
80- format,
81- Some (
82- ffmpeg:: software:: converter (
83- ( input_config. width , input_config. height ) ,
84- input_config. pixel_format ,
85- format,
86- )
87- . map_err ( |e| {
104+ format
105+ } ;
106+
107+ let needs_scaling =
108+ output_width != input_config. width || output_height != input_config. height ;
109+
110+ if needs_scaling {
111+ debug ! (
112+ "Scaling video frames for H264 encoding from {}x{} to {}x{}" ,
113+ input_config. width, input_config. height, output_width, output_height
114+ ) ;
115+ }
116+
117+ let converter = if needs_pixel_conversion || needs_scaling {
118+ let flags = if needs_scaling {
119+ ffmpeg:: software:: scaling:: flag:: Flags :: BICUBIC
120+ } else {
121+ ffmpeg:: software:: scaling:: flag:: Flags :: FAST_BILINEAR
122+ } ;
123+
124+ match ffmpeg:: software:: scaling:: Context :: get (
125+ input_config. pixel_format ,
126+ input_config. width ,
127+ input_config. height ,
128+ output_format,
129+ output_width,
130+ output_height,
131+ flags,
132+ ) {
133+ Ok ( context) => Some ( context) ,
134+ Err ( e) => {
135+ if needs_pixel_conversion {
88136 error ! (
89- "Failed to create converter from {:?} to NV12 : {:?}" ,
90- input_config. pixel_format, e
137+ "Failed to create converter from {:?} to {:?} : {:?}" ,
138+ input_config. pixel_format, output_format , e
91139 ) ;
92- H264EncoderError :: PixFmtNotSupported ( input_config. pixel_format )
93- } ) ?,
94- ) ,
95- )
140+ return Err ( H264EncoderError :: PixFmtNotSupported (
141+ input_config. pixel_format ,
142+ ) ) ;
143+ }
144+
145+ return Err ( H264EncoderError :: FFmpeg ( e) ) ;
146+ }
147+ }
96148 } else {
97- ( input_config . pixel_format , None )
149+ None
98150 } ;
99151
100152 let mut encoder_ctx = context:: Context :: new_with_codec ( codec) ;
@@ -105,16 +157,16 @@ impl H264EncoderBuilder {
105157 encoder_ctx. set_threading ( Config :: count ( thread_count) ) ;
106158 let mut encoder = encoder_ctx. encoder ( ) . video ( ) ?;
107159
108- encoder. set_width ( input_config . width ) ;
109- encoder. set_height ( input_config . height ) ;
110- encoder. set_format ( format ) ;
160+ encoder. set_width ( output_width ) ;
161+ encoder. set_height ( output_height ) ;
162+ encoder. set_format ( output_format ) ;
111163 encoder. set_time_base ( input_config. time_base ) ;
112164 encoder. set_frame_rate ( Some ( input_config. frame_rate ) ) ;
113165
114166 // let target_bitrate = compression.bitrate();
115167 let bitrate = get_bitrate (
116- input_config . width ,
117- input_config . height ,
168+ output_width ,
169+ output_height ,
118170 input_config. frame_rate . 0 as f32 / input_config. frame_rate . 1 as f32 ,
119171 self . bpp ,
120172 ) ;
@@ -133,17 +185,21 @@ impl H264EncoderBuilder {
133185 Ok ( H264Encoder {
134186 base : EncoderBase :: new ( stream_index) ,
135187 encoder,
136- config : self . input_config ,
137188 converter,
189+ output_format,
190+ output_width,
191+ output_height,
138192 } )
139193 }
140194}
141195
142196pub struct H264Encoder {
143197 base : EncoderBase ,
144198 encoder : encoder:: Video ,
145- config : VideoInfo ,
146199 converter : Option < ffmpeg:: software:: scaling:: Context > ,
200+ output_format : format:: Pixel ,
201+ output_width : u32 ,
202+ output_height : u32 ,
147203}
148204
149205#[ derive( thiserror:: Error , Debug ) ]
@@ -170,16 +226,16 @@ impl H264Encoder {
170226 self . base
171227 . update_pts ( & mut frame, timestamp, & mut self . encoder ) ;
172228
173- let frame = if let Some ( converter) = & mut self . converter {
174- let mut new_frame = frame:: Video :: empty ( ) ;
229+ if let Some ( converter) = & mut self . converter {
230+ let pts = frame. pts ( ) ;
231+ let mut converted =
232+ frame:: Video :: new ( self . output_format , self . output_width , self . output_height ) ;
175233 converter
176- . run ( & frame, & mut new_frame )
234+ . run ( & frame, & mut converted )
177235 . map_err ( QueueFrameError :: Converter ) ?;
178- new_frame. set_pts ( frame. pts ( ) ) ;
179- new_frame
180- } else {
181- frame
182- } ;
236+ converted. set_pts ( pts) ;
237+ frame = converted;
238+ }
183239
184240 self . base
185241 . send_frame ( & frame, output, & mut self . encoder )
0 commit comments