11use anyhow:: bail;
22use std:: ffi:: CString ;
3- use std:: io:: Cursor ;
43use std:: path:: Path ;
54use std:: sync:: Arc ;
65use std:: thread:: { spawn, JoinHandle } ;
76use std:: time:: { Instant , SystemTime } ;
87
9- use bitstream_io:: { BigEndian , BitRead , BitReader } ;
108use crossbeam:: channel:: { Receiver , Sender } ;
119use derive_builder:: Builder ;
1210use ffmpeg:: util:: frame:: video:: Video ;
@@ -57,6 +55,27 @@ fn is_stream_key_framed(id: Id) -> Result<bool, String> {
5755 }
5856}
5957
58+ #[ pyclass]
59+ #[ derive( Clone , Debug ) ]
60+ pub struct BsfFilter {
61+ codec : String ,
62+ name : String ,
63+ params : Vec < ( String , String ) > ,
64+ }
65+
66+ #[ pymethods]
67+ impl BsfFilter {
68+ #[ new]
69+ #[ pyo3( signature = ( codec, name, params = vec![ ] ) ) ]
70+ fn new ( codec : String , name : String , params : Vec < ( String , String ) > ) -> Self {
71+ Self {
72+ codec,
73+ name,
74+ params,
75+ }
76+ }
77+ }
78+
6079#[ derive( Debug , Clone ) ]
6180#[ pyclass]
6281pub struct VideoFrameEnvelope {
@@ -179,6 +198,7 @@ struct HandleParams {
179198 autoconvert_raw_formats_to_rgb24 : bool ,
180199 block_if_queue_full : bool ,
181200 log_level : Arc < Mutex < Option < Level > > > ,
201+ bsf_filters : Vec < BsfFilter > ,
182202}
183203
184204struct BitStreamFilterContext {
@@ -324,36 +344,27 @@ fn handle(params: HandleParams) -> anyhow::Result<()> {
324344
325345 let mut video_filters = Vec :: new ( ) ;
326346
327- match video_input. codec ( ) . id ( ) {
328- Id :: H264 => {
329- video_filters. push ( init_bsf (
330- "h264_mp4toannexb" ,
331- & video_parameters,
332- time_base,
333- & [ ] ,
334- ) ?) ;
335- // video_filters.push(init_bsf(
336- // "h264_metadata",
337- // &video_parameters,
338- // time_base,
339- // &[("aud".into(), "insert".into())],
340- // )?);
341- }
342- Id :: HEVC | Id :: H265 => {
343- // video_filters.push(init_bsf(
344- // "hevc_metadata",
345- // &video_parameters,
346- // time_base,
347- // &[("aud".into(), "insert".into())],
348- // )?);
349- video_filters. push ( init_bsf (
350- "hevc_mp4toannexb" ,
351- & video_parameters,
352- time_base,
353- & [ ] ,
354- ) ?) ;
347+ let codec_name = video_input. codec ( ) . id ( ) . name ( ) ;
348+ for f in & params. bsf_filters {
349+ if f. codec != codec_name {
350+ info ! (
351+ "Skipping filter {} as it is not applicable to codec {}, must match {}" ,
352+ f. name, codec_name, f. codec
353+ ) ;
354+ continue ;
355355 }
356- _ => { }
356+
357+ info ! (
358+ "Initializing filter: {} with parameters {:?}" ,
359+ f. name, f. params
360+ ) ;
361+
362+ video_filters. push ( init_bsf (
363+ f. name . as_str ( ) ,
364+ & video_parameters,
365+ time_base,
366+ & f. params ,
367+ ) ?) ;
357368 }
358369
359370 let mut video_decoder =
@@ -594,7 +605,8 @@ impl FFMpegSource {
594605 autoconvert_raw_formats_to_rgb24 = false ,
595606 block_if_queue_full = false ,
596607 init_timeout_ms = 10000 ,
597- ffmpeg_log_level = FFmpegLogLevel :: Info )
608+ ffmpeg_log_level = FFmpegLogLevel :: Info ,
609+ bsf_filters = vec![ ] )
598610 ) ]
599611 pub fn new (
600612 uri : String ,
@@ -605,6 +617,7 @@ impl FFMpegSource {
605617 block_if_queue_full : bool ,
606618 init_timeout_ms : u64 ,
607619 ffmpeg_log_level : FFmpegLogLevel ,
620+ bsf_filters : Vec < BsfFilter > ,
608621 ) -> PyResult < Self > {
609622 assert ! ( queue_len > 0 , "Queue length must be a positive number" ) ;
610623
@@ -627,6 +640,7 @@ impl FFMpegSource {
627640 . autoconvert_raw_formats_to_rgb24 ( autoconvert_raw_formats_to_rgb24)
628641 . block_if_queue_full ( block_if_queue_full)
629642 . log_level ( log_level. clone ( ) )
643+ . bsf_filters ( bsf_filters. clone ( ) )
630644 . build ( )
631645 . map_err ( |e| {
632646 error ! ( "Unable to create handle params. Error is: {:?}" , e) ;
@@ -690,35 +704,6 @@ impl FFMpegSource {
690704 }
691705}
692706
693- // Function to decode Exp-Golomb codes from a slice and return a bit-string
694- #[ pyfunction]
695- fn decode_exp_golomb ( slice : & [ u8 ] ) -> String {
696- let mut reader = BitReader :: endian ( Cursor :: new ( slice) , BigEndian ) ;
697- let mut bit_string = String :: new ( ) ;
698-
699- // Step 1: Count the number of leading zeros
700- let mut leading_zeros = 0 ;
701- while let Ok ( bit) = reader. read_bit ( ) {
702- bit_string. push ( if bit { '1' } else { '0' } ) ; // Append bit to bit-string
703- if !bit {
704- leading_zeros += 1 ;
705- } else {
706- break ; // Stop at the first '1'
707- }
708- }
709-
710- // Step 2: Read the remainder of the code
711- let mut code_value = 1 ; // The first '1' already encountered
712- for _ in 0 ..leading_zeros {
713- if let Ok ( bit) = reader. read_bit ( ) {
714- bit_string. push ( if bit { '1' } else { '0' } ) ; // Append to bit-string
715- code_value = ( code_value << 1 ) | if bit { 1 } else { 0 } ;
716- }
717- }
718-
719- bit_string
720- }
721-
722707#[ pymodule]
723708fn ffmpeg_input ( _py : Python , m : & Bound < ' _ , PyModule > ) -> PyResult < ( ) > {
724709 _ = env_logger:: try_init_from_env ( "LOGLEVEL" ) . map_err ( |e| {
@@ -727,6 +712,6 @@ fn ffmpeg_input(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
727712 m. add_class :: < VideoFrameEnvelope > ( ) ?;
728713 m. add_class :: < FFMpegSource > ( ) ?;
729714 m. add_class :: < FFmpegLogLevel > ( ) ?;
730- m. add_function ( wrap_pyfunction ! ( decode_exp_golomb , m ) ? ) ?;
715+ m. add_class :: < BsfFilter > ( ) ?;
731716 Ok ( ( ) )
732717}
0 commit comments