From 67488f2d3ec9024b640c711041623261f3609724 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Mon, 15 Sep 2025 17:08:38 +0200 Subject: [PATCH 1/8] (feat) Add python && js code --- .../tutorials/filter-session-intro.md | 550 ++++++++++++++---- mkdocs.yml | 321 +++++----- 2 files changed, 602 insertions(+), 269 deletions(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 5345979f..28ea842e 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -47,12 +47,38 @@ The GPAC filter session object allows building media pipelines using multiple so The simplest way to create a session object is to use the gf_fs_new_defaults() function. -```C -GF_FilterSession *session = gf_fs_new_defaults(0u); -if (session == NULL) { - fprintf(stderr, "Failed to create GPAC session\n"); -} -``` + +=== "C" + + ```c + GF_FilterSession *session = gf_fs_new_defaults(0u); + if (session == NULL) { + fprintf(stderr, "Failed to create GPAC session\n"); + } + ``` + +=== "JavaScript" + + ```javascript + // session is accessible globally + if (!session) { + console.error("Failed to create GPAC session"); + } + ``` + +=== "Python" + + ```python + import sys + sys.path.append('/usr/share/gpac/python') + import libgpac as gpac + + fs = gpac.FilterSession() + if not fs: + print("Failed to create GPAC session") + ``` + + This function will create a new filter session, loading parameters from [gpac config](/Filters/core_config). This will also load all available filter registers not blacklisted. @@ -74,10 +100,29 @@ if (gf_err != GF_OK) ``` Alternatively to [gf_fs_load_source](https://doxygen.gpac.io/group__fs__grp.html#gafce8e6e28696bc68e863bd4153282f80) function we can use the more generic [gf_fs_load_filter](https://doxygen.gpac.io/group__fs__grp.html#ga962fa3063a69ef02e43f06abe14cfe65) and use the [Fin](/Filters/fin) filter (followed by its options with the syntax :opt=val) as follows: +=== "C" + + ```c + GF_Filter *src_filter = gf_fs_load_filter(session, "fin:src=logo.png", &gf_err); + ``` + +=== "JavaScript" + + ```javascript + let src_filter = session.add_filter("fin:src=logo.png"); + ``` + + + +=== "Python" + + ```python + src = fs.load("fin:src=logo.png") + ``` + + + -```C -GF_Filter *src_filter = gf_fs_load_filter(session, "fin:src=logo.png", &gf_err); -``` ### Loading a filter @@ -92,19 +137,65 @@ The filter session keeps an internal graph representation of all available filte The following code snippet provides an example to load the [reframer](/Filters/reframer) filter. -```C -GF_Filter *reframer_filter = gf_fs_load_filter(session, "reframer", &gf_err); -if (gf_err != GF_OK) -{ - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); -} -``` +=== "C" + + ```c + GF_Filter *reframer_filter = gf_fs_load_filter(session, "reframer", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + ``` + +=== "JavaScript" + + ```javascript + + let refr = session.add_filter("reframer"); + if (!refr) { + throw new Error("Failed to load filter: reframer"); + } + ``` + +=== "Python" + + ```python + + refr = fs.load("reframer") + if not refr: + raise RuntimeError("Failed to load filter: reframer") + ``` + + options can be specified the same way as in the CLI of gpac, as stated with ‘fin’ above. Here is another example: -```C -GF_Filter *reframer_filter = gf_fs_load_filter(session, "reframer:rt=on", &gf_err); -``` +=== "C" + + ```c + GF_Filter *reframer_filter = gf_fs_load_filter(session, "reframer:rt=on", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + ``` + +=== "JavaScript" + + ```javascript + + let refrRT = session.add_filter("reframer:rt=on"); + if (!refrRT) { + throw new Error("Failed to load filter: reframer:rt=on"); + } + ``` + +=== "Python" + + ```python + refr_rt = fs.load("reframer:rt=on") + if not refr_rt: + raise RuntimeError("Failed to load filter: reframer:rt=on") + ``` + ### Loading a destination filter @@ -114,26 +205,85 @@ Loading a destination filter, exactly like loading a source filter mentioned abo by using [gf_fs_load_destination()](https://doxygen.gpac.io/group__fs__grp.html#ga2fd8f1f59622bc781cc81aafee99ee7d) function : - -```C -GF_Err gf_err = GF_OK; -GF Filter *src_filter = gf_fs_load_destination(session, "logo_result.png", NULL, NULL, &gf_err); -if (gf_err != GF_OK) -{ - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); -} -``` +=== "C" + + ```c + GF_Err gf_err = GF_OK; + GF_Filter *src_filter = gf_fs_load_destination(session, "logo_result.png", NULL, NULL, &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + ``` + +=== "JavaScript" + + ```javascript + // Assume a global FilterSession object "session" exists + try { + let dst_filter_direct = session.add_destination("logo_result.png"); + if (!dst_filter_direct) { + throw new Error("Failed to load destination filter via add_destination"); + } + } catch (e) { + console.error("JavaScript error: " + e.message); + session.abort(1); + } + ``` + +=== "Python" + + ```python + + try: + dst_filter_direct = fs.load_dst("logo_result.png") + if not dst_filter_direct: + raise RuntimeError("Failed to load destination filter via load_dst") + finally: + fs.delete() + gpac.close() + ``` + + Or by using the gf_fs_load_filter and use the Fout filter (or any alternative output destinations pipes, sockets.. ) as follows: -```C -//load destination filter -GF_Filter *dst_filter = gf_fs_load_filter(session, "fout:dst=logo_result.png", &gf_err); -if (gf_err != GF_OK) -{ - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); -} -``` +=== "C" + + ```c + GF_Err gf_err = GF_OK; + GF_Filter *dst_filter = gf_fs_load_filter(session, "fout:dst=logo_result.png", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + ``` + +=== "JavaScript" + + ```javascript + // Assume a global FilterSession object "session" exists + try { + let dst_filter_fout = session.add_filter("fout:dst=logo_result.png"); + if (!dst_filter_fout) { + throw new Error("Failed to load destination filter via fout"); + } + } catch (e) { + console.error("JavaScript error: " + e.message); + session.abort(1); + } + ``` + +=== "Python" + + ```python + try: + dst_filter_fout = fs.load("fout:dst=logo_result.png") + if not dst_filter_fout: + raise RuntimeError("Failed to load destination filter via fout") + finally: + fs.delete() + gpac.close() + ``` + ## Connecting filters and creating a filter chain @@ -167,23 +317,97 @@ By default, the gpac filters session operates in a semi-blocking state. meaning The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e209aef33193e02f83ff5fcbab)() allows for executing the filter session. When the session is non-blocking, it processes tasks of the oldest scheduled filter, manages pending PID connections, and then returns. In the case of a blocking session, gf_fs_run() continues to run until the session concludes or is aborted. The function returns an error if any issues arise during execution, and the last errors can be retrieved using [gf_fs_get_last_connect_error](https://doxygen.gpac.io/group__fs__grp.html#ga026f96a009dd073700b7339fb3ade492) and [gf_fs_get_last_process_error](https://doxygen.gpac.io/group__fs__grp.html#ga2a217d0b7f3f44050f9f78cab10e577d). - -```C -gf_err = gf_fs_run(session); - -if (gf_err>=GF_OK) { - gf_err = gf_fs_get_last_connect_error(session); -if (gf_err>=GF_OK) - gf_err = gf_fs_get_last_process_error(session); -} - -//print connections -gf_fs_print_connections(session); -gf_fs_print_stats(session); - -gf_fs_del(session); -session = NULL; -``` +=== "C" + + ```c + gf_err = gf_fs_run(session); + + if (gf_err >= GF_OK) { + gf_err = gf_fs_get_last_connect_error(session); + if (gf_err >= GF_OK) + gf_err = gf_fs_get_last_process_error(session); + } + + // Print connections + gf_fs_print_connections(session); + gf_fs_print_stats(session); + + gf_fs_del(session); + session = NULL; + ``` + +=== "JavaScript" + + ```javascript + // Assume a global GPAC FilterSession object: `session` + + try { + let gf_err = session.run(); + + if (gf_err >= 0) { + const connect_error = session.last_connect_error; + const process_error = session.last_process_error; + if (connect_error < 0) { + console.error(`Last connection error: ${connect_error}`); + } + if (process_error < 0) { + console.error(`Last process error: ${process_error}`); + } + } else { + console.error(`Session run error: ${gf_err}`); + } + + session.print_connections(); + session.print_stats(); + } catch (e) { + console.error("JavaScript exception:", e); + + session.abort(1); + } + ``` + +=== "Python" + + ```python + + import sys + sys.path.append('/usr/share/gpac/python') + import libgpac as gpac + + fs = gpac.FilterSession() + try: + + fs.run() + + try: + connect_error = getattr(fs, "last_connect_error", None) + process_error = getattr(fs, "last_process_error", None) + if connect_error is not None and connect_error < gpac.GF_OK: + print(f"Last connection error: {connect_error}") + if process_error is not None and process_error < gpac.GF_OK: + print(f"Last process error: {process_error}") + except Exception: + pass + + try: + fs.print_graph() + except Exception: + pass + try: + fs.print_stats() + except Exception: + pass + + finally: + fs.delete() + try: + gpac.close() + except Exception: + pass + ``` + + + ## Sample code @@ -193,63 +417,169 @@ In the following example we reproduce a [testsuite example](https://github.com/g **_NOTE:_**: the reframer filter has no functionnnal use in this particular example. the example is just an illustartion of a filters chain. -```C -int main(int argc, char *argv[]) -{ - GF_Err gf_err = GF_OK; - - // session scheme for testing reframer with fin filter - GF_FilterSession *session = gf_fs_new_defaults(0u); - if (session == NULL) { - fprintf(stderr, "Failed to create GPAC session\n"); - return EXIT_FAILURE; - } - - // load source filter - GF_Filter * src_filter = gf_fs_load_filter(session, "fin:src=logo.png", &gf_err); - if (gf_err != GF_OK) - { - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); +=== "C" + + ```c + int main(int argc, char *argv[]) + { + GF_Err gf_err = GF_OK; + + // session scheme for testing reframer with fin filter + GF_FilterSession *session = gf_fs_new_defaults(0u); + if (session == NULL) { + fprintf(stderr, "Failed to create GPAC session\n"); + return EXIT_FAILURE; + } + + // load source filter + GF_Filter *src_filter = gf_fs_load_filter(session, "fin:src=logo.png", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + + // load reframer filter + GF_Filter *reframer_filter = gf_fs_load_filter(session, "reframer", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + + // load writergen filter + GF_Filter *writegen_filter = gf_fs_load_filter(session, "writegen", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + + // load destination filter + GF_Filter *dst_filter = gf_fs_load_filter(session, "fout:dst=logo_result.png", &gf_err); + if (gf_err != GF_OK) { + fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + } + + gf_filter_set_source(reframer_filter, src_filter, NULL); + gf_filter_set_source(writegen_filter, reframer_filter, NULL); + gf_filter_set_source(dst_filter, writegen_filter, NULL); + + gf_err = gf_fs_run(session); + if (gf_err >= GF_OK) { + gf_err = gf_fs_get_last_connect_error(session); + if (gf_err >= GF_OK) + gf_err = gf_fs_get_last_process_error(session); + } + + // print connections + gf_fs_print_connections(session); + gf_fs_print_stats(session); + + gf_fs_del(session); + session = NULL; + return EXIT_SUCCESS; } - //load reframer filter - GF_Filter *reframer_filter = gf_fs_load_filter(session, "reframer", &gf_err); - if (gf_err != GF_OK) - { - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); + ``` + +=== "JavaScript" + + ```javascript + try { + // Load filters + let src = session.add_filter("fin:src=logo.png"); + let reframer = session.add_filter("reframer"); + let writegen = session.add_filter("writegen"); + let dst = session.add_filter("fout:dst=logo_result.png"); + + if (!src || !reframer || !writegen || !dst) { + throw new Error("Failed to load one or more filters"); + } + + let gf_err = session.run(); + if (gf_err >= 0) { + const connect_error = session.last_connect_error; + const process_error = session.last_process_error; + if (connect_error < 0) { + console.error(`Last connection error: ${connect_error}`); + } + if (process_error < 0) { + console.error(`Last process error: ${process_error}`); + } + } else { + console.error(`Session run error: ${gf_err}`); } - //load writergen filter - GF_Filter *writegen_filter = gf_fs_load_filter(session, "writegen", &gf_err); - if (gf_err != GF_OK) - { - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); - } - - //load destination filter - GF_Filter *dst_filter = gf_fs_load_filter(session, "fout:dst=logo_result.png", &gf_err); - if (gf_err != GF_OK) - { - fprintf(stderr, "Failed to load filter: %s", gf_error_to_string(gf_err)); - } - - gf_filter_set_source(reframer_filter, src_filter, NULL); - gf_filter_set_source(writegen_filter,reframer_filter,NULL); - gf_filter_set_source(dst_filter ,writegen_filter,NULL); - - gf_err = gf_fs_run(session); - - if (gf_err>=GF_OK) - { - gf_err = gf_fs_get_last_connect_error(session); - if (gf_err>=GF_OK) - gf_err = gf_fs_get_last_process_error(session); + // Print connections and stats + session.print_connections(); + session.print_stats(); + } catch (e) { + console.error("JavaScript exception:", e); + session.abort(1); } - - //print connections - gf_fs_print_connections(session); - gf_fs_print_stats(session); - - gf_fs_del(session); - session = NULL; - return EXIT_SUCCESS; -} -``` + ``` + +=== "Python" + + ```python + import sys + sys.path.append('/usr/share/gpac/python') + import libgpac as gpac + + def main(): + fs = None + try: + fs = gpac.FilterSession() + + src = fs.load_src("logo.png") + if not src: + raise RuntimeError("Failed to load source filter: 'fin:src=logo.png'") + + reframer = fs.load("reframer") + if not reframer: + raise RuntimeError("Failed to load filter 'reframer'") + + writegen = fs.load("writegen") + if not writegen: + raise RuntimeError("Failed to load filter 'writegen'") + + dst = fs.load_dst("logo_result.png") + if not dst: + raise RuntimeError("Failed to load destination filter: 'fout:dst=logo_result.png'") + + reframer.set_source(src) + writegen.set_source(reframer) + dst.set_source(writegen) + + fs.run() + + try: + connect_error = getattr(fs, "last_connect_error", None) + process_error = getattr(fs, "last_process_error", None) + if connect_error is not None and connect_error < gpac.GF_OK: + print(f"Last connection error: {connect_error}", file=sys.stderr) + if process_error is not None and process_error < gpac.GF_OK: + print(f"Last process error: {process_error}", file=sys.stderr) + except Exception: + pass + + try: + fs.print_graph() + except Exception: + pass + + try: + fs.print_stats() + except Exception: + pass + + except RuntimeError as e: + print(f"Runtime error: {e}", file=sys.stderr) + return 1 + except Exception as e: + print(f"An unexpected error occurred: {e}", file=sys.stderr) + return 1 + finally: + if fs: + fs.delete() + gpac.close() + + return 0 + + if __name__ == "__main__": + sys.exit(main()) + ``` +``` diff --git a/mkdocs.yml b/mkdocs.yml index 382e5aa5..7e095296 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -73,6 +73,9 @@ plugins: hooks: - scripts/mkdocs_hooks.py markdown_extensions: +- pymdownx.tabbed: + alternate_style: true + - pymdownx.highlight: anchor_linenums: true line_spans: __span @@ -204,165 +207,165 @@ nav: - Global options: Filters/core_options.md - Logging: Filters/core_logs.md - Filters: - - Stream Manipulation: - - Audio/Video rewinder: Filters/rewind.md - - Bitstream metadata rewriter: Filters/bsrw.md - - FFmpeg bitstream filter: Filters/ffbsf.md - - HEVC Tile aggregator: Filters/tileagg.md - - HEVC Tile extractor: Filters/hevcsplit.md - - HEVC Tile merger: Filters/hevcmerge.md - - HEVC Tile splitter: Filters/tilesplit.md - - Layered bitstream aggregator: Filters/bsagg.md - - Layered bitstream splitter: Filters/bssplit.md - - MPEG-2 TS splitter: Filters/tssplit.md - - MPEG-2 TS timestamper: Filters/tsgendts.md - - Media reframer: Filters/reframer.md - - SEI message loader: Filters/seiload.md - - Sources concatenator: Filters/flist.md - - Timestamp rewriter: Filters/restamp.md - - Multimedia I/O: - - AV Counter Generator: Filters/avgen.md - - Audio output: Filters/aout.md - - DVB for Linux: Filters/dvbin.md - - DekTec SDI output: Filters/dtout.md - - FFmpeg AV capture: Filters/ffavin.md - - Text Generator: Filters/txtgen.md - - Uncompressed Video Generator: Filters/uncvg.md - - Video output: Filters/vout.md - - Web-based AV capture: Filters/webgrab.md - - Protocols I/O: - - DASH & HLS client: Filters/dashin.md - - DASH & HLS segmenter: Filters/dasher.md - - File input: Filters/fin.md - - File output: Filters/fout.md - - HTTP input: Filters/httpin.md - - HTTP server: Filters/httpout.md - - MABR & ROUTE input: Filters/routein.md - - MABR & ROUTE output: Filters/routeout.md - - Media Server: Filters/mediaserver.md - - Pipe input: Filters/pin.md - - Pipe output: Filters/pout.md - - RTP Streamer: Filters/rtpout.md - - RTP/RTSP/SDP input: Filters/rtpin.md - - RTSP server: Filters/rtspout.md - - UDP/TCP input: Filters/sockin.md - - UDP/TCP output: Filters/sockout.md - - Text & Subtitles: - - Closed-Caption decoder: Filters/ccdec.md - - Subtitle loader: Filters/txtin.md - - TTML sample merger: Filters/ttmlmerge.md - - TTML to SRT: Filters/ttml2srt.md - - TTML to WebVTT: Filters/ttml2vtt.md - - TX3G to SRT: Filters/tx3g2srt.md - - TX3G to TTML: Filters/tx3g2ttml.md - - TX3G to WebVTT: Filters/tx3g2vtt.md - - WebVTT to TX3G: Filters/vtt2tx3g.md - - Audio & Video Processing: - - Audio Video mixer: Filters/avmix.md - - Audio resampler: Filters/resample.md - - Compositor: Filters/compositor.md - - EVG video rescaler: Filters/evgs.md - - FFmpeg AV Filter: Filters/ffavf.md - - FFmpeg video rescaler: Filters/ffsws.md - - GPU texture uploader: Filters/glpush.md - - Thumbnail generator: Filters/thumbs.md - - Video cropper: Filters/vcrop.md - - Video flipper: Filters/vflip.md - - Utilities & Tools: - - JavaScript filter: Filters/jsf.md - - NHML reader: Filters/nhmlr.md - - NHML writer: Filters/nhmlw.md - - NHNT reader: Filters/nhntr.md - - NHNT writer: Filters/nhntw.md - - Packet inspector: Filters/inspect.md - - Source prober: Filters/probe.md - - Stream rewriter: Filters/unframer.md - - Stream to File converter: Filters/writegen.md - - Cryptography: - - CENC decryptor: Filters/cdcrypt.md - - CENC encryptor: Filters/cecrypt.md - - CryptFile input: Filters/cryptin.md - - CryptFile output: Filters/cryptout.md - - Bitstream Framing: - - AC3 reframer: Filters/rfac3.md - - AC4 reframer: Filters/rfac4.md - - AC4 writer: Filters/ufac4.md - - ADTS reframer: Filters/rfadts.md - - ADTS rewriter: Filters/ufadts.md - - AMR/EVRC reframer: Filters/rfamr.md - - AV1/IVF/VP9/IAMF reframer: Filters/rfav1.md - - AVC/HEVC reframer: Filters/rfnalu.md - - AVC/HEVC to AnnexB rewriter: Filters/ufnalu.md - - FLAC reframer: Filters/rfflac.md - - Framed to Unframed converter: Filters/writeuf.md - - H263 reframer: Filters/rfh263.md - - IVF/OBU/annexB rewriter: Filters/ufobu.md - - JPG/J2K/PNG/BMP reframer: Filters/rfimg.md - - LATM reframer: Filters/rflatm.md - - LATM rewriter: Filters/uflatm.md - - M1V/M2V/M4V reframer: Filters/rfmpgvid.md - - M4V rewriter: Filters/ufm4v.md - - MHAS rewriter: Filters/ufmhas.md - - MP3 reframer: Filters/rfmp3.md - - MPEH-H Audio Stream reframer: Filters/rfmhas.md - - PCM reframer: Filters/rfpcm.md - - ProRes reframer: Filters/rfprores.md - - QCP reframer: Filters/rfqcp.md - - QCP writer: Filters/writeqcp.md - - RAW video reframer: Filters/rfrawvid.md - - SRT reframer: Filters/rfsrt.md - - TX3G rewriter: Filters/ufttxt.md - - TrueHD reframer: Filters/rftruehd.md - - VC1 rewriter: Filters/ufvc1.md - - WebVTT rewriter: Filters/ufvtt.md - - Demultiplexers: - - AVI: Filters/avidmx.md - - FFmpeg: Filters/ffdmx.md - - GHI: Filters/ghidmx.md - - GSF: Filters/gsfdmx.md - - ISOBMFF/QT: Filters/mp4dmx.md - - MPEG PS: Filters/m2psdmx.md - - MPEG-2 TS: Filters/m2tsdmx.md - - OGG: Filters/oggdmx.md - - SAF: Filters/safdmx.md - - VobSub: Filters/vobsubdmx.md - - Mulitplexers: - - AVI: Filters/avimx.md - - FFmpeg: Filters/ffmx.md - - GSF: Filters/gsfmx.md - - ISOBMFF/QT: Filters/mp4mx.md - - MPEG-2 TS: Filters/m2tsmx.md - - OGG: Filters/oggmx.md - - Decoders: - - A52: Filters/a52dec.md - - BT/XMT/X3D: Filters/btplay.md - - FAAD: Filters/faad.md - - FFmpeg: Filters/ffdec.md - - MAD: Filters/maddec.md - - MPEG-4 BIFS: Filters/bifsdec.md - - MPEG-4 LASeR: Filters/lsrdec.md - - MPEG-4 OD: Filters/odfdec.md - - MediaCodec: Filters/mcdec.md - - NVidia: Filters/nvdec.md - - OpenHEVC: Filters/ohevcdec.md - - OpenJPEG2000: Filters/j2kdec.md - - OpenSVC: Filters/osvcdec.md - - PNG/JPG: Filters/imgdec.md - - SCTE35: Filters/scte35dec.md - - SVG: Filters/svgplay.md - - TTML: Filters/ttmldec.md - - TTXT/TX3G: Filters/ttxtdec.md - - Theora: Filters/theoradec.md - - UNCV: Filters/uncvdec.md - - Vorbis: Filters/vorbisdec.md - - WebCodec: Filters/wcdec.md - - WebVTT: Filters/vttdec.md - - XVid: Filters/xviddec.md - - Encoders: - - FFmpeg: Filters/ffenc.md - - JPG: Filters/jpgenc.md - - PNG: Filters/pngenc.md - - WebCodec: Filters/wcenc.md + - Stream Manipulation: + - Audio/Video rewinder: Filters/rewind.md + - Bitstream metadata rewriter: Filters/bsrw.md + - FFmpeg bitstream filter: Filters/ffbsf.md + - HEVC Tile aggregator: Filters/tileagg.md + - HEVC Tile extractor: Filters/hevcsplit.md + - HEVC Tile merger: Filters/hevcmerge.md + - HEVC Tile splitter: Filters/tilesplit.md + - Layered bitstream aggregator: Filters/bsagg.md + - Layered bitstream splitter: Filters/bssplit.md + - MPEG-2 TS splitter: Filters/tssplit.md + - MPEG-2 TS timestamper: Filters/tsgendts.md + - Media reframer: Filters/reframer.md + - SEI message loader: Filters/seiload.md + - Sources concatenator: Filters/flist.md + - Timestamp rewriter: Filters/restamp.md + - Multimedia I/O: + - AV Counter Generator: Filters/avgen.md + - Audio output: Filters/aout.md + - DVB for Linux: Filters/dvbin.md + - DekTec SDI output: Filters/dtout.md + - FFmpeg AV capture: Filters/ffavin.md + - Text Generator: Filters/txtgen.md + - Uncompressed Video Generator: Filters/uncvg.md + - Video output: Filters/vout.md + - Web-based AV capture: Filters/webgrab.md + - Protocols I/O: + - DASH & HLS client: Filters/dashin.md + - DASH & HLS segmenter: Filters/dasher.md + - File input: Filters/fin.md + - File output: Filters/fout.md + - HTTP input: Filters/httpin.md + - HTTP server: Filters/httpout.md + - MABR & ROUTE input: Filters/routein.md + - MABR & ROUTE output: Filters/routeout.md + - Media Server: Filters/mediaserver.md + - Pipe input: Filters/pin.md + - Pipe output: Filters/pout.md + - RTP Streamer: Filters/rtpout.md + - RTP/RTSP/SDP input: Filters/rtpin.md + - RTSP server: Filters/rtspout.md + - UDP/TCP input: Filters/sockin.md + - UDP/TCP output: Filters/sockout.md + - Text & Subtitles: + - Closed-Caption decoder: Filters/ccdec.md + - Subtitle loader: Filters/txtin.md + - TTML sample merger: Filters/ttmlmerge.md + - TTML to SRT: Filters/ttml2srt.md + - TTML to WebVTT: Filters/ttml2vtt.md + - TX3G to SRT: Filters/tx3g2srt.md + - TX3G to TTML: Filters/tx3g2ttml.md + - TX3G to WebVTT: Filters/tx3g2vtt.md + - WebVTT to TX3G: Filters/vtt2tx3g.md + - Audio & Video Processing: + - Audio Video mixer: Filters/avmix.md + - Audio resampler: Filters/resample.md + - Compositor: Filters/compositor.md + - EVG video rescaler: Filters/evgs.md + - FFmpeg AV Filter: Filters/ffavf.md + - FFmpeg video rescaler: Filters/ffsws.md + - GPU texture uploader: Filters/glpush.md + - Thumbnail generator: Filters/thumbs.md + - Video cropper: Filters/vcrop.md + - Video flipper: Filters/vflip.md + - Utilities & Tools: + - JavaScript filter: Filters/jsf.md + - NHML reader: Filters/nhmlr.md + - NHML writer: Filters/nhmlw.md + - NHNT reader: Filters/nhntr.md + - NHNT writer: Filters/nhntw.md + - Packet inspector: Filters/inspect.md + - Source prober: Filters/probe.md + - Stream rewriter: Filters/unframer.md + - Stream to File converter: Filters/writegen.md + - Cryptography: + - CENC decryptor: Filters/cdcrypt.md + - CENC encryptor: Filters/cecrypt.md + - CryptFile input: Filters/cryptin.md + - CryptFile output: Filters/cryptout.md + - Bitstream Framing: + - AC3 reframer: Filters/rfac3.md + - AC4 reframer: Filters/rfac4.md + - AC4 writer: Filters/ufac4.md + - ADTS reframer: Filters/rfadts.md + - ADTS rewriter: Filters/ufadts.md + - AMR/EVRC reframer: Filters/rfamr.md + - AV1/IVF/VP9/IAMF reframer: Filters/rfav1.md + - AVC/HEVC reframer: Filters/rfnalu.md + - AVC/HEVC to AnnexB rewriter: Filters/ufnalu.md + - FLAC reframer: Filters/rfflac.md + - Framed to Unframed converter: Filters/writeuf.md + - H263 reframer: Filters/rfh263.md + - IVF/OBU/annexB rewriter: Filters/ufobu.md + - JPG/J2K/PNG/BMP reframer: Filters/rfimg.md + - LATM reframer: Filters/rflatm.md + - LATM rewriter: Filters/uflatm.md + - M1V/M2V/M4V reframer: Filters/rfmpgvid.md + - M4V rewriter: Filters/ufm4v.md + - MHAS rewriter: Filters/ufmhas.md + - MP3 reframer: Filters/rfmp3.md + - MPEH-H Audio Stream reframer: Filters/rfmhas.md + - PCM reframer: Filters/rfpcm.md + - ProRes reframer: Filters/rfprores.md + - QCP reframer: Filters/rfqcp.md + - QCP writer: Filters/writeqcp.md + - RAW video reframer: Filters/rfrawvid.md + - SRT reframer: Filters/rfsrt.md + - TX3G rewriter: Filters/ufttxt.md + - TrueHD reframer: Filters/rftruehd.md + - VC1 rewriter: Filters/ufvc1.md + - WebVTT rewriter: Filters/ufvtt.md + - Demultiplexers: + - AVI: Filters/avidmx.md + - FFmpeg: Filters/ffdmx.md + - GHI: Filters/ghidmx.md + - GSF: Filters/gsfdmx.md + - ISOBMFF/QT: Filters/mp4dmx.md + - MPEG PS: Filters/m2psdmx.md + - MPEG-2 TS: Filters/m2tsdmx.md + - OGG: Filters/oggdmx.md + - SAF: Filters/safdmx.md + - VobSub: Filters/vobsubdmx.md + - Mulitplexers: + - AVI: Filters/avimx.md + - FFmpeg: Filters/ffmx.md + - GSF: Filters/gsfmx.md + - ISOBMFF/QT: Filters/mp4mx.md + - MPEG-2 TS: Filters/m2tsmx.md + - OGG: Filters/oggmx.md + - Decoders: + - A52: Filters/a52dec.md + - BT/XMT/X3D: Filters/btplay.md + - FAAD: Filters/faad.md + - FFmpeg: Filters/ffdec.md + - MAD: Filters/maddec.md + - MPEG-4 BIFS: Filters/bifsdec.md + - MPEG-4 LASeR: Filters/lsrdec.md + - MPEG-4 OD: Filters/odfdec.md + - MediaCodec: Filters/mcdec.md + - NVidia: Filters/nvdec.md + - OpenHEVC: Filters/ohevcdec.md + - OpenJPEG2000: Filters/j2kdec.md + - OpenSVC: Filters/osvcdec.md + - PNG/JPG: Filters/imgdec.md + - SCTE35: Filters/scte35dec.md + - SVG: Filters/svgplay.md + - TTML: Filters/ttmldec.md + - TTXT/TX3G: Filters/ttxtdec.md + - Theora: Filters/theoradec.md + - UNCV: Filters/uncvdec.md + - Vorbis: Filters/vorbisdec.md + - WebCodec: Filters/wcdec.md + - WebVTT: Filters/vttdec.md + - XVid: Filters/xviddec.md + - Encoders: + - FFmpeg: Filters/ffenc.md + - JPG: Filters/jpgenc.md + - PNG: Filters/pngenc.md + - WebCodec: Filters/wcenc.md - Build: - Overview: Build/Build-Introduction.md - Upgrading or Changing Branch: Build/Upgrading.md From 5342f44954da189270074848eb24bb4379980289 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Tue, 16 Sep 2025 11:50:26 +0200 Subject: [PATCH 2/8] fix: remove extraneous closing code block in filter session tutorial --- docs/Developers/tutorials/filter-session-intro.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 28ea842e..6c6a0036 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -582,4 +582,3 @@ In the following example we reproduce a [testsuite example](https://github.com/g if __name__ == "__main__": sys.exit(main()) ``` -``` From 041495d80bf0359130dd20394c78db5940ecaac8 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Wed, 24 Sep 2025 17:39:07 +0200 Subject: [PATCH 3/8] (refactor) Update JavaScript examples to use NodeJS syntax and improve error handling --- .../tutorials/filter-session-intro.md | 197 +++++++++--------- 1 file changed, 100 insertions(+), 97 deletions(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 28ea842e..2ba149b8 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -57,13 +57,15 @@ The simplest way to create a session object is to use the gf_fs_new_defaults() f } ``` -=== "JavaScript" +=== "NodeJS" ```javascript - // session is accessible globally - if (!session) { - console.error("Failed to create GPAC session"); - } + try { + const session = new gpac.FilterSession(); + console.log("GPAC FilterSession created!"); +} catch (e) { + console.error("Failed to create GPAC session :", e); +} ``` === "Python" @@ -106,10 +108,10 @@ Alternatively to [gf_fs_load_source](https://doxygen.gpac.io/group__fs__grp.html GF_Filter *src_filter = gf_fs_load_filter(session, "fin:src=logo.png", &gf_err); ``` -=== "JavaScript" +=== "NodeJS" ```javascript - let src_filter = session.add_filter("fin:src=logo.png"); + const src_filter = session.load_src("logo.png"); ``` @@ -146,11 +148,11 @@ The following code snippet provides an example to load the [reframer](/Filters/r } ``` -=== "JavaScript" +=== "NodeJS" ```javascript - let refr = session.add_filter("reframer"); + let refr = session.load("reframer"); if (!refr) { throw new Error("Failed to load filter: reframer"); } @@ -178,11 +180,11 @@ options can be specified the same way as in the CLI of gpac, as stated with ‘f } ``` -=== "JavaScript" +=== "NodeJS" ```javascript - let refrRT = session.add_filter("reframer:rt=on"); + let refrRT = session.load("reframer:rt=on"); if (!refrRT) { throw new Error("Failed to load filter: reframer:rt=on"); } @@ -215,18 +217,16 @@ by using [gf_fs_load_destination()](https://doxygen.gpac.io/group__fs__grp.html# } ``` -=== "JavaScript" +=== "NodeJS" ```javascript - // Assume a global FilterSession object "session" exists + try { - let dst_filter_direct = session.add_destination("logo_result.png"); - if (!dst_filter_direct) { - throw new Error("Failed to load destination filter via add_destination"); - } + let dst_filter = session.load_dst("logo_result.png"); + } catch (e) { - console.error("JavaScript error: " + e.message); - session.abort(1); + console.error("Error: " + e.message); + } ``` @@ -257,18 +257,16 @@ Or by using the gf_fs_load_filter and use the Fout filter (or any alternative ou } ``` -=== "JavaScript" +=== "NodeJS" ```javascript // Assume a global FilterSession object "session" exists try { - let dst_filter_fout = session.add_filter("fout:dst=logo_result.png"); - if (!dst_filter_fout) { - throw new Error("Failed to load destination filter via fout"); - } + let dst_filter = session.load("fout:dst=logo_result.png"); + } catch (e) { - console.error("JavaScript error: " + e.message); - session.abort(1); + console.error("Error: " + e.message); + } ``` @@ -336,34 +334,35 @@ The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e20 session = NULL; ``` -=== "JavaScript" +=== "NodeJS" ```javascript - // Assume a global GPAC FilterSession object: `session` + + // Ensure gpac the module is loaded + + let session = null; try { - let gf_err = session.run(); - - if (gf_err >= 0) { - const connect_error = session.last_connect_error; - const process_error = session.last_process_error; - if (connect_error < 0) { - console.error(`Last connection error: ${connect_error}`); - } - if (process_error < 0) { - console.error(`Last process error: ${process_error}`); - } + session = new gpac.FilterSession(); + /* + * ... Here, your code ... + */ + // Run the session in blocking mode + const err = session.run(); + if (err < gpac.GF_OK) { + console.error("Session execution failed with error: " + gpac.e2s(err)); } else { - console.error(`Session run error: ${gf_err}`); + session.print_graph(); + session.print_stats(); + } + } catch (e) { + console.error("A JavaScript exception was thrown: ", e); + } finally { + if (session) { + session.abort(); + session = null; + } } - - session.print_connections(); - session.print_stats(); - } catch (e) { - console.error("JavaScript exception:", e); - - session.abort(1); - } ``` === "Python" @@ -372,39 +371,32 @@ The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e20 import sys sys.path.append('/usr/share/gpac/python') - import libgpac as gpac + import libgpac as gpac - fs = gpac.FilterSession() + fs = None try: - - fs.run() - - try: - connect_error = getattr(fs, "last_connect_error", None) - process_error = getattr(fs, "last_process_error", None) - if connect_error is not None and connect_error < gpac.GF_OK: - print(f"Last connection error: {connect_error}") - if process_error is not None and process_error < gpac.GF_OK: - print(f"Last process error: {process_error}") - except Exception: - pass - - try: + fs = gpac.FilterSession() + /*... Here, your code ...*/ + err_code = fs.run() + if err_code < gpac.GF_OK: + print(f"L'exécution de la session a échoué avec l'erreur : {gpac.e2s(err_code)}") + else: fs.print_graph() - except Exception: - pass - try: fs.print_stats() - except Exception: - pass + + except Exception as e: + print(f"Error: {e}") finally: - fs.delete() + if fs: + fs.delete() + fs = None try: gpac.close() except Exception: pass ``` + @@ -476,42 +468,53 @@ In the following example we reproduce a [testsuite example](https://github.com/g } ``` -=== "JavaScript" +=== "NodeJS" ```javascript + + let session = null; + try { - // Load filters - let src = session.add_filter("fin:src=logo.png"); - let reframer = session.add_filter("reframer"); - let writegen = session.add_filter("writegen"); - let dst = session.add_filter("fout:dst=logo_result.png"); - - if (!src || !reframer || !writegen || !dst) { - throw new Error("Failed to load one or more filters"); + session = new gpac.FilterSession(); + if (!session) { + throw new Error("Failed to create GPAC session."); } - - let gf_err = session.run(); - if (gf_err >= 0) { - const connect_error = session.last_connect_error; - const process_error = session.last_process_error; - if (connect_error < 0) { - console.error(`Last connection error: ${connect_error}`); + + const src_filter = session.load_src("logo.png"); + const reframer_filter = session.load("reframer"); + const writegen_filter = session.load("writegen"); + const dst_filter = session.load("fout:dst=logo_result.png"); + + if (!dst_filter || !reframer_filter || !writegen_filter || !src_filter) { + throw new Error("Failed to load one or more filters."); } - if (process_error < 0) { - console.error(`Last process error: ${process_error}`); + + reframer_filter.set_source(src_filter); + writegen_filter.set_source(reframer_filter); + dst_filter.set_source(writegen_filter); + + + const err = session.run(); + + if (err < gpac.GF_OK) { + console.error("Session execution failed with error: " + gpac.e2s(err)); + } else { + + session.print_graph(); + session.print_stats(); } - } else { - console.error(`Session run error: ${gf_err}`); - } - // Print connections and stats - session.print_connections(); - session.print_stats(); + } catch (e) { - console.error("JavaScript exception:", e); - session.abort(1); + console.error("A JavaScript exception was thrown: ", e); + } finally { + + if (session) { + session.abort(); + session = null; + + } } ``` - === "Python" ```python From 08d943551fbc5f601c1eeb24decfacbc46724d89 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Thu, 25 Sep 2025 08:56:57 +0200 Subject: [PATCH 4/8] (fix) correct JavaScript example for creating a GPAC FilterSession --- docs/Developers/tutorials/filter-session-intro.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 03198651..12fb3970 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -60,14 +60,14 @@ The simplest way to create a session object is to use the gf_fs_new_defaults() f === "NodeJS" ```javascript - try { - const session = new gpac.FilterSession(); - console.log("GPAC FilterSession created!"); -} catch (e) { - console.error("Failed to create GPAC session :", e); -} + try { + let session = new gpac.FilterSession(); + + } catch (e) { + console.error("Failed to create GPAC session :", e); + } + ``` - === "Python" ```python From 77a10240584643670893f7555fb0dd6b35f8b7b1 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Thu, 25 Sep 2025 09:04:52 +0200 Subject: [PATCH 5/8] (fix) add missing require statement for gpac in NodeJS example --- docs/Developers/tutorials/filter-session-intro.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 12fb3970..fed4dbbf 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -60,6 +60,9 @@ The simplest way to create a session object is to use the gf_fs_new_defaults() f === "NodeJS" ```javascript + + const gpac = require(path/to/gpac/share/nodejs); + try { let session = new gpac.FilterSession(); From 374e31e5c4ea1953b49704058d022f4bec38c2a2 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Mon, 29 Sep 2025 10:59:08 +0200 Subject: [PATCH 6/8] (fix) update NodeJS and Python examples for filter session creation --- .../tutorials/filter-session-intro.md | 174 +++++++----------- 1 file changed, 65 insertions(+), 109 deletions(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 03198651..30c3c8a7 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -60,12 +60,15 @@ The simplest way to create a session object is to use the gf_fs_new_defaults() f === "NodeJS" ```javascript - try { - const session = new gpac.FilterSession(); - console.log("GPAC FilterSession created!"); -} catch (e) { - console.error("Failed to create GPAC session :", e); -} + const gpac = require(path/to/gpac/share/nodejs); + + try { + + let session = new gpac.FilterSession(); + + } catch (e) { + console.error("Failed to create GPAC session :", e); + } ``` === "Python" @@ -75,7 +78,8 @@ The simplest way to create a session object is to use the gf_fs_new_defaults() f sys.path.append('/usr/share/gpac/python') import libgpac as gpac - fs = gpac.FilterSession() + fs = gpac.FilterSession() + if not fs: print("Failed to create GPAC session") ``` @@ -119,7 +123,7 @@ Alternatively to [gf_fs_load_source](https://doxygen.gpac.io/group__fs__grp.html === "Python" ```python - src = fs.load("fin:src=logo.png") + src = fs.load_src("logo.png") ``` @@ -164,7 +168,7 @@ The following code snippet provides an example to load the [reframer](/Filters/r refr = fs.load("reframer") if not refr: - raise RuntimeError("Failed to load filter: reframer") + print("Failed to load filter: reframer") ``` @@ -194,8 +198,9 @@ options can be specified the same way as in the CLI of gpac, as stated with ‘f ```python refr_rt = fs.load("reframer:rt=on") + if not refr_rt: - raise RuntimeError("Failed to load filter: reframer:rt=on") + print("Failed to load filter: reframer:rt=on") ``` @@ -234,11 +239,12 @@ by using [gf_fs_load_destination()](https://doxygen.gpac.io/group__fs__grp.html# ```python - try: - dst_filter_direct = fs.load_dst("logo_result.png") - if not dst_filter_direct: - raise RuntimeError("Failed to load destination filter via load_dst") - finally: + + dst_filter = fs.load_dst("logo_result.png") + + if not dst_filter: + print("Failed to load destination filter via load_dst") + fs.delete() gpac.close() ``` @@ -260,26 +266,21 @@ Or by using the gf_fs_load_filter and use the Fout filter (or any alternative ou === "NodeJS" ```javascript - // Assume a global FilterSession object "session" exists + try { let dst_filter = session.load("fout:dst=logo_result.png"); } catch (e) { - console.error("Error: " + e.message); - + console.error("Error: " + e.message); } ``` === "Python" ```python - try: + dst_filter_fout = fs.load("fout:dst=logo_result.png") - if not dst_filter_fout: - raise RuntimeError("Failed to load destination filter via fout") - finally: - fs.delete() - gpac.close() + ``` @@ -338,7 +339,7 @@ The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e20 ```javascript - // Ensure gpac the module is loaded + const gpac = require(path/to/gpac/share/nodejs); let session = null; @@ -371,31 +372,21 @@ The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e20 import sys sys.path.append('/usr/share/gpac/python') - import libgpac as gpac + import libgpac as gpac - fs = None - try: - fs = gpac.FilterSession() - /*... Here, your code ...*/ - err_code = fs.run() - if err_code < gpac.GF_OK: - print(f"L'exécution de la session a échoué avec l'erreur : {gpac.e2s(err_code)}") - else: - fs.print_graph() - fs.print_stats() - - except Exception as e: - print(f"Error: {e}") - - finally: - if fs: - fs.delete() - fs = None - try: - gpac.close() - except Exception: - pass - ``` + + fs = gpac.FilterSession() + //.. Here, your code ... + + fs.run() + fs.print_graph() + fs.print_stats() + + + fs.delete() + gpac.close() + ``` + @@ -472,6 +463,8 @@ In the following example we reproduce a [testsuite example](https://github.com/g ```javascript + const gpac = require(path/to/gpac/share/nodejs); + let session = null; try { @@ -494,7 +487,7 @@ In the following example we reproduce a [testsuite example](https://github.com/g dst_filter.set_source(writegen_filter); - const err = session.run(); + session.run(); if (err < gpac.GF_OK) { console.error("Session execution failed with error: " + gpac.e2s(err)); @@ -523,65 +516,28 @@ In the following example we reproduce a [testsuite example](https://github.com/g import libgpac as gpac def main(): - fs = None - try: - fs = gpac.FilterSession() - - src = fs.load_src("logo.png") - if not src: - raise RuntimeError("Failed to load source filter: 'fin:src=logo.png'") - - reframer = fs.load("reframer") - if not reframer: - raise RuntimeError("Failed to load filter 'reframer'") - - writegen = fs.load("writegen") - if not writegen: - raise RuntimeError("Failed to load filter 'writegen'") - - dst = fs.load_dst("logo_result.png") - if not dst: - raise RuntimeError("Failed to load destination filter: 'fout:dst=logo_result.png'") - - reframer.set_source(src) - writegen.set_source(reframer) - dst.set_source(writegen) - - fs.run() - - try: - connect_error = getattr(fs, "last_connect_error", None) - process_error = getattr(fs, "last_process_error", None) - if connect_error is not None and connect_error < gpac.GF_OK: - print(f"Last connection error: {connect_error}", file=sys.stderr) - if process_error is not None and process_error < gpac.GF_OK: - print(f"Last process error: {process_error}", file=sys.stderr) - except Exception: - pass - - try: - fs.print_graph() - except Exception: - pass - - try: - fs.print_stats() - except Exception: - pass - - except RuntimeError as e: - print(f"Runtime error: {e}", file=sys.stderr) - return 1 - except Exception as e: - print(f"An unexpected error occurred: {e}", file=sys.stderr) - return 1 - finally: - if fs: - fs.delete() - gpac.close() - - return 0 + + fs = gpac.FilterSession() + + src = fs.load_src("logo.png") + reframer = fs.load("reframer") + writer = fs.load("writegen") + dst = fs.load_dst("logo_result.png") + + + reframer.set_source(src) + writer.set_source(reframer) + dst.set_source(writer) + + + fs.run() + + fs.print_graph() + fs.print_stats() + + fs.delete() + gpac.close() if __name__ == "__main__": - sys.exit(main()) + main() ``` From aaf7fb34d609e8b838770526ed6d251cc63044aa Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Mon, 29 Sep 2025 11:16:47 +0200 Subject: [PATCH 7/8] (fix) remove unnecessary cleanup calls in filter session tutorial --- docs/Developers/tutorials/filter-session-intro.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index ea946b47..7f5a8ddc 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -244,8 +244,7 @@ by using [gf_fs_load_destination()](https://doxygen.gpac.io/group__fs__grp.html# if not dst_filter: print("Failed to load destination filter via load_dst") - fs.delete() - gpac.close() + ``` From 54cfcffdb95131451465013bccc6d1823d1ebe84 Mon Sep 17 00:00:00 2001 From: PierreDillard <7gaspard77@gmail.com> Date: Wed, 1 Oct 2025 11:37:10 +0200 Subject: [PATCH 8/8] fix: correct syntax errors in filter session tutorial examples --- docs/Developers/tutorials/filter-session-intro.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/Developers/tutorials/filter-session-intro.md b/docs/Developers/tutorials/filter-session-intro.md index 7f5a8ddc..489593df 100644 --- a/docs/Developers/tutorials/filter-session-intro.md +++ b/docs/Developers/tutorials/filter-session-intro.md @@ -60,7 +60,7 @@ The simplest way to create a session object is to use the gf_fs_new_defaults() f === "NodeJS" ```javascript - const gpac = require(path/to/gpac/share/nodejs); + const gpac = require('path/to/gpac/share/nodejs'); try { @@ -337,7 +337,7 @@ The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e20 ```javascript - const gpac = require(path/to/gpac/share/nodejs); + const gpac = require('path/to/gpac/share/nodejs'); let session = null; @@ -374,7 +374,7 @@ The function [gf_fs_run](https://doxygen.gpac.io/group__fs__grp.html#gafdef85e20 fs = gpac.FilterSession() - //.. Here, your code ... + // Here, your code ... fs.run() fs.print_graph() @@ -461,7 +461,7 @@ In the following example we reproduce a [testsuite example](https://github.com/g ```javascript - const gpac = require(path/to/gpac/share/nodejs); + const gpac = require('path/to/gpac/share/nodejs'); let session = null; @@ -485,7 +485,7 @@ In the following example we reproduce a [testsuite example](https://github.com/g dst_filter.set_source(writegen_filter); - session.run(); + const err = session.run(); if (err < gpac.GF_OK) { console.error("Session execution failed with error: " + gpac.e2s(err)); @@ -537,5 +537,5 @@ In the following example we reproduce a [testsuite example](https://github.com/g gpac.close() if __name__ == "__main__": - main() + main() ```