1212from cython .cimports .av .packet import Packet
1313from cython .cimports .av .stream import Stream , wrap_stream
1414from cython .cimports .av .utils import dict_to_avdict , to_avrational
15- from cython .cimports .libc .stdint import uint8_t
15+ from cython .cimports .libc .stdint import int64_t , uint8_t
1616from cython .cimports .libc .string import memcpy , memset
1717
1818
@@ -146,12 +146,22 @@ def add_stream(
146146 has_time_base : cython .bint = "time_base" in kwargs
147147 if has_time_base :
148148 to_avrational (kwargs .pop ("time_base" ), cython .address (c_time_base ))
149+
150+ c_width : cython .int = 0
151+ c_height : cython .int = 0
152+ c_bit_rate : int64_t = 0
153+ c_bit_rate_tolerance : cython .int = 0
149154 if codec .type == lib .AVMEDIA_TYPE_VIDEO :
150155 to_avrational (rate or 24 , cython .address (c_framerate ))
151- elif codec .type == lib .AVMEDIA_TYPE_AUDIO and not (
152- rate is None or type (rate ) is int
153- ):
154- raise TypeError ("audio stream `rate` must be: int | None" )
156+ c_width = kwargs .pop ("width" , 640 )
157+ c_height = kwargs .pop ("height" , 480 )
158+ c_bit_rate = kwargs .pop ("bit_rate" , 0 )
159+ c_bit_rate_tolerance = kwargs .pop ("bit_rate_tolerance" , 128000 )
160+ elif codec .type == lib .AVMEDIA_TYPE_AUDIO :
161+ if not (rate is None or type (rate ) is int ):
162+ raise TypeError ("audio stream `rate` must be: int | None" )
163+ c_bit_rate = kwargs .pop ("bit_rate" , 0 )
164+ c_bit_rate_tolerance = kwargs .pop ("bit_rate_tolerance" , 32000 )
155165
156166 # Create new stream in the AVFormatContext, set AVCodecContext values.
157167 ctx : cython .pointer [lib .AVCodecContext ] = lib .avcodec_alloc_context3 (codec )
@@ -168,10 +178,10 @@ def add_stream(
168178 # Now let's set some more sane video defaults
169179 if codec .type == lib .AVMEDIA_TYPE_VIDEO :
170180 ctx .pix_fmt = lib .AV_PIX_FMT_YUV420P
171- ctx .width = kwargs . pop ( "width" , 640 )
172- ctx .height = kwargs . pop ( "height" , 480 )
173- ctx .bit_rate = kwargs . pop ( "bit_rate" , 0 )
174- ctx .bit_rate_tolerance = kwargs . pop ( "bit_rate_tolerance" , 128000 )
181+ ctx .width = c_width
182+ ctx .height = c_height
183+ ctx .bit_rate = c_bit_rate
184+ ctx .bit_rate_tolerance = c_bit_rate_tolerance
175185 ctx .framerate = c_framerate
176186
177187 stream .avg_frame_rate = ctx .framerate
@@ -190,8 +200,8 @@ def add_stream(
190200 )
191201 if out :
192202 ctx .sample_fmt = cython .cast (cython .pointer [lib .AVSampleFormat ], out )[0 ]
193- ctx .bit_rate = kwargs . pop ( "bit_rate" , 0 )
194- ctx .bit_rate_tolerance = kwargs . pop ( "bit_rate_tolerance" , 32000 )
203+ ctx .bit_rate = c_bit_rate
204+ ctx .bit_rate_tolerance = c_bit_rate_tolerance
195205 ctx .sample_rate = 48000 if rate is None else rate
196206 stream .time_base = ctx .time_base
197207 lib .av_channel_layout_default (cython .address (ctx .ch_layout ), 2 )
@@ -204,9 +214,13 @@ def add_stream(
204214 #
205215 # Subsequent changes to the codec context will be applied just before
206216 # encoding starts in `start_encoding()`.
207- err_check (lib .avcodec_parameters_from_context (stream .codecpar , ctx ))
217+ try :
218+ err_check (lib .avcodec_parameters_from_context (stream .codecpar , ctx ))
219+ except Exception :
220+ lib .avcodec_free_context (cython .address (ctx ))
221+ raise
208222
209- # Construct the user-land stream
223+ # Construct the user-land stream, which takes ownership of ctx.
210224 py_codec_context : CodecContext = wrap_codec_context (ctx , codec , hwaccel )
211225 py_stream : Stream = wrap_stream (self , stream , py_codec_context )
212226 self .streams .add_stream (py_stream )
@@ -268,10 +282,15 @@ def add_mux_stream(self, codec_name: str, rate=None, **kwargs) -> Stream:
268282 )
269283
270284 c_rate : lib .AVRational
271- if rate is not None :
272- if codec_type == lib .AVMEDIA_TYPE_VIDEO :
285+ c_width : cython .int = 0
286+ c_height : cython .int = 0
287+ if codec_type == lib .AVMEDIA_TYPE_VIDEO :
288+ if rate is not None :
273289 to_avrational (rate , cython .address (c_rate ))
274- elif codec_type == lib .AVMEDIA_TYPE_AUDIO and type (rate ) is not int :
290+ c_width = kwargs .pop ("width" , 0 )
291+ c_height = kwargs .pop ("height" , 0 )
292+ elif codec_type == lib .AVMEDIA_TYPE_AUDIO :
293+ if rate is not None and type (rate ) is not int :
275294 raise TypeError ("audio stream `rate` must be: int | None" )
276295
277296 # Create stream with no codec context.
@@ -285,8 +304,8 @@ def add_mux_stream(self, codec_name: str, rate=None, **kwargs) -> Stream:
285304 stream .codecpar .codec_type = codec_type
286305
287306 if codec_type == lib .AVMEDIA_TYPE_VIDEO :
288- stream .codecpar .width = kwargs . pop ( "width" , 0 )
289- stream .codecpar .height = kwargs . pop ( "height" , 0 )
307+ stream .codecpar .width = c_width
308+ stream .codecpar .height = c_height
290309 if rate is not None :
291310 stream .avg_frame_rate = c_rate
292311 elif codec_type == lib .AVMEDIA_TYPE_AUDIO and rate is not None :
@@ -346,28 +365,34 @@ def add_stream_from_template(
346365 lib .avcodec_free_context (cython .address (ctx ))
347366 raise MemoryError ("Could not allocate stream" )
348367
349- err_check (lib .avcodec_parameters_to_context (ctx , template .ptr .codecpar ))
350- # Reset the codec tag assuming we are remuxing.
351- ctx .codec_tag = 0
368+ try :
369+ err_check (lib .avcodec_parameters_to_context (ctx , template .ptr .codecpar ))
370+ # Reset the codec tag assuming we are remuxing.
371+ ctx .codec_tag = 0
352372
353- # Copy the template's stream time_base
354- stream .time_base = template .ptr .time_base
355- ctx .time_base = template .ptr .time_base
373+ # Copy the template's stream time_base
374+ stream .time_base = template .ptr .time_base
375+ ctx .time_base = template .ptr .time_base
356376
357- # Some formats want stream headers to be separate
358- if self .ptr .oformat .flags & lib .AVFMT_GLOBALHEADER :
359- ctx .flags |= lib .AV_CODEC_FLAG_GLOBAL_HEADER
377+ # Some formats want stream headers to be separate
378+ if self .ptr .oformat .flags & lib .AVFMT_GLOBALHEADER :
379+ ctx .flags |= lib .AV_CODEC_FLAG_GLOBAL_HEADER
360380
361- # Copy flags If we're creating a new codec object. This fixes some muxing issues.
362- # Overwriting `ctx.flags |= lib.AV_CODEC_FLAG_GLOBAL_HEADER` is intentional.
363- if not opaque :
364- ctx .flags = template .codec_context .flags
381+ # Copy flags If we're creating a new codec object. This fixes some
382+ # muxing issues. Overwriting the flag set just above is intentional.
383+ if not opaque :
384+ ctx .flags = template .codec_context .flags
365385
366- # Initialize stream codec parameters to populate the codec type. Subsequent changes to
367- # the codec context will be applied just before encoding starts in `start_encoding()`.
368- err_check (lib .avcodec_parameters_from_context (stream .codecpar , ctx ))
386+ # Initialize stream codec parameters to populate the codec type.
387+ # Subsequent changes to the codec context will be applied just
388+ # before encoding starts in `start_encoding()`.
389+ err_check (lib .avcodec_parameters_from_context (stream .codecpar , ctx ))
390+ except Exception :
391+ # Nothing owns ctx until wrap_codec_context() below.
392+ lib .avcodec_free_context (cython .address (ctx ))
393+ raise
369394
370- # Construct the user-land stream
395+ # Construct the user-land stream, which takes ownership of ctx.
371396 py_codec_context : CodecContext = wrap_codec_context (ctx , codec , None )
372397 py_codec_context ._ctxflags |= 1 # _template_initialized = True
373398 py_stream : Stream = wrap_stream (self , stream , py_codec_context )
@@ -509,7 +534,12 @@ def add_data_stream(self, codec_name=None, options: dict | None = None):
509534 ctx .flags |= lib .AV_CODEC_FLAG_GLOBAL_HEADER
510535
511536 # Initialize stream codec parameters
512- err_check (lib .avcodec_parameters_from_context (stream .codecpar , ctx ))
537+ try :
538+ err_check (lib .avcodec_parameters_from_context (stream .codecpar , ctx ))
539+ except Exception :
540+ # Nothing owns ctx until wrap_codec_context() below.
541+ lib .avcodec_free_context (cython .address (ctx ))
542+ raise
513543 else :
514544 # No codec available - set basic parameters for data stream
515545 stream .codecpar .codec_type = lib .AVMEDIA_TYPE_DATA
0 commit comments