@@ -15,7 +15,12 @@ from av.container.output cimport OutputContainer
1515from av.container.pyio cimport pyio_close_custom_gil, pyio_close_gil
1616from av.error cimport err_check, stash_exception
1717from av.format cimport build_container_format
18- from av.utils cimport avdict_to_dict, avrational_to_fraction
18+ from av.utils cimport (
19+ avdict_to_dict,
20+ avrational_to_fraction,
21+ dict_to_avdict,
22+ to_avrational,
23+ )
1924
2025from av.dictionary import Dictionary
2126from av.logging import Capture as LogCapture
@@ -123,6 +128,17 @@ cdef int pyav_io_close_gil(lib.AVFormatContext *s, lib.AVIOContext *pb) noexcept
123128
124129 return result
125130
131+ cdef void _free_chapters(lib.AVFormatContext * ctx) noexcept nogil:
132+ cdef int i
133+ if ctx.chapters != NULL :
134+ for i in range (ctx.nb_chapters):
135+ if ctx.chapters[i] != NULL :
136+ if ctx.chapters[i].metadata != NULL :
137+ lib.av_dict_free(& ctx.chapters[i].metadata)
138+ lib.av_freep(< void ** > & ctx.chapters[i])
139+ lib.av_freep(< void ** > & ctx.chapters)
140+ ctx.nb_chapters = 0
141+
126142
127143class Flags (Flag ):
128144 gen_pts: " Generate missing pts even if it requires parsing future frames." = lib.AVFMT_FLAG_GENPTS
@@ -346,6 +362,39 @@ cdef class Container:
346362 })
347363 return result
348364
365+ def set_chapters (self , chapters ):
366+ self ._assert_open()
367+
368+ cdef int count = len (chapters)
369+ cdef int i
370+ cdef lib.AVChapter ** ch_array
371+ cdef lib.AVChapter * ch
372+ cdef dict entry
373+
374+ with nogil:
375+ _free_chapters(self .ptr)
376+
377+ ch_array = < lib.AVChapter ** > lib.av_malloc(count * sizeof(lib.AVChapter * ))
378+ if ch_array == NULL :
379+ raise MemoryError (" av_malloc failed for chapters" )
380+
381+ for i in range (count):
382+ entry = chapters[i]
383+ ch = < lib.AVChapter * > lib.av_malloc(sizeof(lib.AVChapter))
384+ if ch == NULL :
385+ raise MemoryError (" av_malloc failed for chapter" )
386+ ch.id = entry[" id" ]
387+ ch.start = < int64_t> entry[" start" ]
388+ ch.end = < int64_t> entry[" end" ]
389+ to_avrational(entry[" time_base" ], & ch.time_base)
390+ ch.metadata = NULL
391+ if " metadata" in entry:
392+ dict_to_avdict(& ch.metadata, entry[" metadata" ], self .metadata_encoding, self .metadata_errors)
393+ ch_array[i] = ch
394+
395+ self .ptr.nb_chapters = count
396+ self .ptr.chapters = ch_array
397+
349398def open (
350399 file ,
351400 mode = None ,
0 commit comments