From c33ae3d73a24230a250658ca794c67e4ca3dd022 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Thu, 24 Feb 2022 23:33:02 +0100 Subject: [PATCH] New upstream version 2.0.0+dfsg1 --- .gitignore | 1 - .gitmodules | 2 +- .travis.yml | 12 +- Changelog | 154 +- Clean.bat | 23 - Makefile | 46 +- README.md | 66 +- SECURITY.md | 22 + applications/Makefile | 4 +- applications/generators/MPEG4/main.c | 2 +- applications/generators/MPEG4/templates5.txt | 4 +- applications/generators/MPEG4/templates9.txt | 4 +- applications/generators/SVG/main.c | 2 +- applications/generators/X3D/main.c | 2 +- applications/gpac/Makefile | 5 + applications/gpac/main.c | 1712 ++- applications/mp4box/Makefile | 6 +- applications/mp4box/filedump.c | 1563 +- applications/mp4box/fileimport.c | 1491 +- applications/mp4box/live.c | 12 +- applications/mp4box/main.c | 9543 ++++++------ applications/mp4box/mp4box.h | 79 +- applications/mp4box/wrapper.c | 102 - applications/mp4client/Makefile | 4 + applications/mp4client/main.c | 29 +- applications/mp4client/mp4client.rc | 4 +- configure | 469 +- gpac.spec | 13 +- include/gpac/00_doxy.h | 19 +- include/gpac/Remotery.h | 2 +- include/gpac/atsc.h | 229 - include/gpac/avparse.h | 100 +- include/gpac/bitstream.h | 25 +- include/gpac/cache.h | 7 +- include/gpac/color.h | 8 +- include/gpac/configuration.h | 11 +- include/gpac/constants.h | 414 +- include/gpac/crypt.h | 8 +- include/gpac/crypt_tools.h | 75 +- include/gpac/dash.h | 326 +- include/gpac/download.h | 25 +- include/gpac/events.h | 6 +- include/gpac/evg.h | 299 +- include/gpac/filters.h | 1225 +- include/gpac/ietf.h | 32 +- include/gpac/internal/avilib.h | 4 + include/gpac/internal/bifs_dev.h | 7 +- include/gpac/internal/compositor_dev.h | 168 +- include/gpac/internal/ietf_dev.h | 4 + include/gpac/internal/isomedia_dev.h | 488 +- include/gpac/internal/m3u8.h | 15 +- include/gpac/internal/media_dev.h | 378 +- include/gpac/internal/mesh.h | 1 + include/gpac/internal/odf_parse_common.h | 6 +- include/gpac/internal/scenegraph_dev.h | 11 +- include/gpac/internal/swf_dev.h | 2 +- include/gpac/isomedia.h | 1340 +- include/gpac/main.h | 63 +- include/gpac/maths.h | 11 +- include/gpac/media_tools.h | 125 +- include/gpac/mediaobject.h | 21 +- include/gpac/module.h | 9 - include/gpac/modules/audio_out.h | 2 +- include/gpac/modules/codec.h | 4 +- include/gpac/modules/video_out.h | 8 +- include/gpac/mpd.h | 192 +- include/gpac/mpeg4_odf.h | 200 +- include/gpac/mpegts.h | 190 +- include/gpac/network.h | 60 +- include/gpac/nodes_svg.h | 2 + include/gpac/options.h | 6 +- include/gpac/path2d.h | 6 +- include/gpac/route.h | 300 + include/gpac/scene_engine.h | 2 +- include/gpac/scene_manager.h | 2 +- include/gpac/scenegraph.h | 16 +- include/gpac/scenegraph_svg.h | 7 +- include/gpac/scenegraph_vrml.h | 4 +- include/gpac/setup.h | 56 +- include/gpac/svg_types.h | 20 +- include/gpac/term_info.h | 9 +- include/gpac/terminal.h | 13 +- include/gpac/thread.h | 34 +- include/gpac/tools.h | 263 +- include/gpac/utf.h | 36 +- include/gpac/version.h | 22 +- include/gpac/webvtt.h | 3 +- include/gpac/xml.h | 40 +- manifest.rc | 1 + mkdmg.sh | 5 +- modules/dektec_out/dektec_video_decl.c | 14 +- modules/dektec_out/out_dektec.vcxproj | 8 + modules/droid_out/droid_vout.c | 2 +- modules/dx_hw/dx_hw.rc | 18 +- modules/dx_hw/dx_window.c | 2 + modules/ft_font/ft_font.c | 124 +- modules/jack/jack.c | 1 + modules/sdl_out/video.c | 15 +- modules/test_filter/Makefile | 43 + modules/test_filter/test_filter.c | 115 + modules/test_filter/test_filter.vcxproj | 292 + modules/validator/validator.c | 54 +- modules/x11_out/x11_out.c | 27 +- packagers/win32_64/nsis/gpac_installer.nsi | 14 +- share/default.cfg | 4 +- share/doc/CODING_STYLE | 4 +- share/doc/configuration.html | 2 +- share/doc/doxyfile | 2 +- share/doc/idl/core.idl | 161 +- share/doc/idl/dash_algo.idl | 252 + share/doc/idl/evg.idl | 574 +- share/doc/idl/filtersession.idl | 85 +- share/doc/idl/jsf.idl | 128 +- share/doc/idl/nodejs.idl | 1492 ++ share/doc/idl/webgl.idl | 32 +- share/doc/man/gpac-filters.1 | 6014 ++++++-- share/doc/man/gpac.1 | 1533 +- share/doc/man/mp4box.1 | 1079 +- share/doc/man/mp4client.1 | 14 +- share/gpac.desktop | 18 + share/gui/extensions/player/fileopen.js | 2 +- share/gui/extensions/player/player.js | 38 +- share/gui/extensions/player/stats.js | 20 +- share/gui/gwlib.js | 2 +- share/lang/fr.txt | 72 +- share/nodejs/binding.gyp | 8 + share/nodejs/index.js | 2 + share/nodejs/package.json | 23 + share/nodejs/src/gpac_napi.c | 6066 ++++++++ share/nodejs/src/gpac_napi.h | 246 + share/nodejs/test/gpac.js | 602 + share/python/libgpac.py | 4500 ++++++ share/res/gpac_highres.png | Bin 0 -> 98776 bytes share/scripts/custom_dash.js | 68 + share/scripts/jsf/avgen/init.js | 772 + share/scripts/jsf/avgen/testcard.png | Bin 0 -> 43147 bytes share/scripts/jsf/avmix/help.js | 572 + share/scripts/jsf/avmix/init.js | 7989 +++++++++++ share/scripts/jsf/avmix/scenes/clear.js | 42 + share/scripts/jsf/avmix/scenes/clip.js | 42 + share/scripts/jsf/avmix/scenes/mask.js | 55 + share/scripts/jsf/avmix/scenes/shape.js | 1196 ++ share/scripts/jsf/avmix/transitions/fade.js | 82 + .../transitions/gl-transitions/Bounce.glsl | 29 + .../gl-transitions/BowTieHorizontal.glsl | 120 + .../gl-transitions/BowTieVertical.glsl | 114 + .../gl-transitions/BowTieWithParameter.glsl | 70 + .../gl-transitions/ButterflyWaveScrawler.glsl | 28 + .../gl-transitions/CircleCrop.glsl | 17 + .../gl-transitions/ColourDistance.glsl | 16 + .../gl-transitions/CrazyParametricFun.glsl | 17 + .../transitions/gl-transitions/CrossZoom.glsl | 64 + .../gl-transitions/Directional.glsl | 14 + .../gl-transitions/DoomScreenTransition.glsl | 59 + .../transitions/gl-transitions/Dreamy.glsl | 11 + .../gl-transitions/DreamyZoom.glsl | 40 + .../transitions/gl-transitions/FilmBurn.glsl | 59 + .../gl-transitions/GlitchDisplace.glsl | 79 + .../gl-transitions/GlitchMemories.glsl | 15 + .../transitions/gl-transitions/GridFlip.glsl | 72 + .../gl-transitions/InvertedPageCurl.glsl | 214 + .../transitions/gl-transitions/LeftRight.glsl | 25 + .../gl-transitions/LinearBlur.glsl | 26 + .../transitions/gl-transitions/Mosaic.glsl | 42 + .../gl-transitions/PolkaDotsCurtain.glsl | 10 + .../transitions/gl-transitions/Radial.glsl | 16 + .../gl-transitions/SimpleZoom.glsl | 17 + .../gl-transitions/StereoViewer.glsl | 210 + .../transitions/gl-transitions/Swirl.glsl | 31 + .../transitions/gl-transitions/TVStatic.glsl | 25 + .../transitions/gl-transitions/TopBottom.glsl | 24 + .../transitions/gl-transitions/WaterDrop.glsl | 16 + .../gl-transitions/ZoomInCircles.glsl | 38 + .../transitions/gl-transitions/angular.glsl | 21 + .../transitions/gl-transitions/burn.glsl | 10 + .../gl-transitions/cannabisleaf.glsl | 15 + .../transitions/gl-transitions/circle.glsl | 19 + .../gl-transitions/circleopen.glsl | 13 + .../gl-transitions/colorphase.glsl | 14 + .../gl-transitions/crosshatch.glsl | 16 + .../transitions/gl-transitions/crosswarp.glsl | 7 + .../transitions/gl-transitions/cube.glsl | 66 + .../gl-transitions/directional-easing.glsl | 15 + .../gl-transitions/directionalwarp.glsl | 15 + .../gl-transitions/directionalwipe.glsl | 17 + .../gl-transitions/displacement.glsl | 22 + .../transitions/gl-transitions/doorway.glsl | 50 + .../transitions/gl-transitions/fade.glsl | 10 + .../transitions/gl-transitions/fadecolor.glsl | 10 + .../gl-transitions/fadegrayscale.glsl | 17 + .../transitions/gl-transitions/flyeye.glsl | 17 + .../transitions/gl-transitions/heart.glsl | 16 + .../gl-transitions/hexagonalize.glsl | 74 + .../gl-transitions/kaleidoscope.glsl | 22 + .../transitions/gl-transitions/luma.glsl | 12 + .../gl-transitions/luminance_melt.glsl | 126 + .../transitions/gl-transitions/morph.glsl | 16 + .../gl-transitions/multiply_blend.glsl | 17 + .../transitions/gl-transitions/perlin.glsl | 64 + .../transitions/gl-transitions/pinwheel.glsl | 16 + .../transitions/gl-transitions/pixelize.glsl | 17 + .../gl-transitions/polar_function.glsl | 20 + .../gl-transitions/randomNoisex.glsl | 16 + .../gl-transitions/randomsquares.glsl | 15 + .../transitions/gl-transitions/ripple.glsl | 15 + .../gl-transitions/rotateTransition.glsl | 19 + .../gl-transitions/rotate_scale_fade.glsl | 32 + .../gl-transitions/squareswire.glsl | 20 + .../transitions/gl-transitions/squeeze.glsl | 19 + .../transitions/gl-transitions/swap.glsl | 59 + .../gl-transitions/tangentMotionBlur.glsl | 139 + .../gl-transitions/undulatingBurnOut.glsl | 47 + .../transitions/gl-transitions/wind.glsl | 19 + .../gl-transitions/windowblinds.glsl | 15 + .../gl-transitions/windowslice.glsl | 11 + .../transitions/gl-transitions/wipeDown.glsl | 9 + .../transitions/gl-transitions/wipeLeft.glsl | 9 + .../transitions/gl-transitions/wipeRight.glsl | 9 + .../transitions/gl-transitions/wipeUp.glsl | 9 + .../scripts/jsf/avmix/transitions/gltrans.js | 277 + share/scripts/jsf/avmix/transitions/mix.js | 44 + share/scripts/jsf/avmix/transitions/swipe.js | 544 + share/scripts/vout.js | 883 ++ share/scripts/webvtt-renderer.js | 4 + share/vis/Code/Console.js | 4 +- .../WindowManager/Styles/WindowManager.css | 2 +- src/Makefile | 82 +- src/bifs/bifs_codec.c | 23 +- src/bifs/com_dec.c | 78 +- src/bifs/field_decode.c | 66 +- src/bifs/field_encode.c | 2 +- src/bifs/memory_decoder.c | 31 +- src/bifs/script_dec.c | 12 +- src/bifs/unquantize.c | 3 +- src/compositor/audio_input.c | 12 +- src/compositor/audio_mixer.c | 362 +- src/compositor/audio_render.c | 46 +- src/compositor/compositor.c | 102 +- src/compositor/compositor_2d.c | 32 +- src/compositor/compositor_3d.c | 6 +- src/compositor/compositor_node_init.c | 11 + src/compositor/drawable.c | 71 +- src/compositor/drawable.h | 13 +- src/compositor/events.c | 32 +- src/compositor/font_engine.c | 10 +- src/compositor/hardcoded_protos.c | 32 +- src/compositor/media_object.c | 265 +- src/compositor/mesh.c | 69 +- src/compositor/mpeg4_audio.c | 6 +- src/compositor/mpeg4_background.c | 2 +- src/compositor/mpeg4_bitmap.c | 54 +- src/compositor/mpeg4_composite.c | 8 +- src/compositor/mpeg4_geometry_2d.c | 4 +- src/compositor/mpeg4_geometry_ils2d.c | 3 +- src/compositor/mpeg4_gradients.c | 9 +- src/compositor/mpeg4_inline.c | 27 +- src/compositor/mpeg4_inputsensor.c | 28 +- src/compositor/mpeg4_layer_2d.c | 27 +- src/compositor/mpeg4_mediacontrol.c | 18 +- src/compositor/mpeg4_mediasensor.c | 4 +- src/compositor/mpeg4_text.c | 37 +- src/compositor/mpeg4_textures.c | 4 +- src/compositor/navigate.c | 7 +- src/compositor/nodes_stacks.h | 2 + src/compositor/object_manager.c | 334 +- src/compositor/offscreen_cache.c | 4 +- src/compositor/scene.c | 283 +- src/compositor/scene_ns.c | 156 +- src/compositor/svg_external.c | 2 +- src/compositor/svg_filters.c | 2 +- src/compositor/svg_font.c | 23 +- src/compositor/svg_geometry.c | 2 +- src/compositor/svg_grouping.c | 54 +- src/compositor/svg_media.c | 2 +- src/compositor/svg_paint_servers.c | 77 +- src/compositor/svg_text.c | 15 +- src/compositor/texturing.c | 45 +- src/compositor/texturing_gl.c | 50 +- src/compositor/visual_manager.h | 2 +- src/compositor/visual_manager_2d.c | 19 +- src/compositor/visual_manager_2d_draw.c | 6 +- src/compositor/visual_manager_3d.c | 2 +- src/compositor/visual_manager_3d_gl.c | 12 +- src/crypto/g_crypt_openssl.c | 79 +- src/crypto/g_crypt_tinyaes.c | 71 +- src/evg/ftgrays.c | 522 +- src/evg/rast_soft.h | 420 +- src/evg/raster3d.c | 762 +- src/evg/raster_565.c | 27 +- src/evg/raster_argb.c | 29 +- src/evg/raster_rgb.c | 18 +- src/evg/raster_yuv.c | 301 +- src/evg/stencil.c | 2234 ++- src/evg/surface.c | 780 +- src/export.cpp | 540 +- src/filter_core/filter.c | 1466 +- src/filter_core/filter_pck.c | 342 +- src/filter_core/filter_pid.c | 2178 ++- src/filter_core/filter_props.c | 872 +- src/filter_core/filter_queue.c | 4 +- src/filter_core/filter_register.c | 29 +- src/filter_core/filter_session.c | 1382 +- src/filter_core/filter_session.h | 167 +- src/filter_core/filter_session_js.c | 445 +- src/filters/bs_agg.c | 925 ++ src/filters/bs_split.c | 1487 ++ src/filters/bsrw.c | 442 +- src/filters/compose.c | 375 +- src/filters/dasher.c | 4501 ++++-- src/filters/dec_ac52.c | 9 +- src/filters/dec_bifs.c | 8 +- src/filters/dec_faad.c | 69 +- src/filters/dec_img.c | 11 +- src/filters/dec_j2k.c | 11 +- src/filters/dec_laser.c | 20 +- src/filters/dec_mad.c | 147 +- src/filters/dec_mediacodec.c | 83 +- src/filters/dec_nvdec.c | 234 +- src/filters/dec_nvdec_sdk.c | 24 +- src/filters/dec_odf.c | 67 +- src/filters/dec_openhevc.c | 241 +- src/filters/dec_opensvc.c | 31 +- src/filters/dec_theora.c | 11 +- src/filters/dec_ttml.c | 28 +- src/filters/dec_ttxt.c | 31 +- src/filters/dec_vorbis.c | 16 +- src/filters/dec_vtb.c | 218 +- src/filters/dec_webvtt.c | 19 +- src/filters/dec_xvid.c | 13 +- src/filters/decrypt_cenc_isma.c | 1380 +- src/filters/dmx_avi.c | 62 +- src/filters/dmx_dash.c | 2256 ++- src/filters/dmx_gsf.c | 220 +- src/filters/dmx_m2ts.c | 300 +- src/filters/dmx_mpegps.c | 19 +- src/filters/dmx_nhml.c | 730 +- src/filters/dmx_nhnt.c | 35 +- src/filters/dmx_ogg.c | 184 +- src/filters/dmx_saf.c | 38 +- src/filters/dmx_vobsub.c | 38 +- src/filters/enc_jpg.c | 14 +- src/filters/enc_png.c | 12 +- src/filters/encrypt_cenc_isma.c | 1298 +- src/filters/ff_avf.c | 91 +- src/filters/ff_common.c | 246 +- src/filters/ff_common.h | 33 +- src/filters/ff_dec.c | 781 +- src/filters/ff_dmx.c | 517 +- src/filters/ff_enc.c | 856 +- src/filters/ff_mx.c | 267 +- src/filters/ff_rescale.c | 270 +- src/filters/filelist.c | 2621 +++- src/filters/hevcmerge.c | 136 +- src/filters/hevcsplit.c | 96 +- src/filters/in_atsc.c | 507 - src/filters/in_dvb4linux.c | 36 +- src/filters/in_file.c | 37 +- src/filters/in_http.c | 261 +- src/filters/in_pipe.c | 178 +- src/filters/in_route.c | 982 ++ src/filters/in_rtp.c | 94 +- src/filters/in_rtp.h | 11 +- src/filters/in_rtp_rtsp.c | 25 +- src/filters/in_rtp_sdp.c | 81 +- src/filters/in_rtp_signaling.c | 59 +- src/filters/in_rtp_stream.c | 96 +- src/filters/in_sock.c | 127 +- src/filters/inspect.c | 2806 +++- src/filters/io_fcryp.c | 653 + src/filters/isoffin.h | 48 +- src/filters/isoffin_load.c | 643 +- src/filters/isoffin_read.c | 503 +- src/filters/isoffin_read_ch.c | 499 +- src/filters/jsfilter.c | 1425 +- src/filters/load_bt_xmt.c | 185 +- src/filters/load_svg.c | 21 +- src/filters/load_text.c | 1054 +- src/filters/mux_avi.c | 94 +- src/filters/mux_gsf.c | 293 +- src/filters/mux_isom.c | 2687 +++- src/filters/mux_ts.c | 524 +- src/filters/out_audio.c | 237 +- src/filters/out_file.c | 231 +- src/filters/out_http.c | 1958 ++- src/filters/out_pipe.c | 59 +- src/filters/out_route.c | 2230 +++ src/filters/out_rtp.c | 182 +- src/filters/out_rtp.h | 5 +- src/filters/out_rtsp.c | 115 +- src/filters/out_sock.c | 54 +- src/filters/out_video.c | 964 +- src/filters/reframe_ac3.c | 112 +- src/filters/reframe_adts.c | 291 +- src/filters/reframe_amr.c | 34 +- src/filters/reframe_av1.c | 345 +- src/filters/reframe_flac.c | 71 +- src/filters/reframe_h263.c | 74 +- src/filters/reframe_img.c | 10 +- src/filters/reframe_latm.c | 106 +- src/filters/reframe_mhas.c | 910 ++ src/filters/reframe_mp3.c | 153 +- src/filters/reframe_mpgvid.c | 308 +- src/filters/reframe_nalu.c | 2159 ++- src/filters/reframe_prores.c | 73 +- src/filters/reframe_qcp.c | 36 +- src/filters/reframe_rawpcm.c | 25 +- src/filters/reframe_rawvid.c | 249 +- src/filters/reframe_truehd.c | 700 + src/filters/reframer.c | 1383 +- src/filters/resample_audio.c | 193 +- src/filters/restamp.c | 480 + src/filters/rewrite_adts.c | 168 +- src/filters/rewrite_mhas.c | 279 + src/filters/rewrite_mp4v.c | 42 +- src/filters/rewrite_nalu.c | 251 +- src/filters/rewrite_obu.c | 71 +- src/filters/tileagg.c | 365 +- src/filters/tilesplit.c | 596 + src/filters/tssplit.c | 54 +- src/filters/unit_test_filter.c | 44 +- src/filters/vcrop.c | 14 +- src/filters/vflip.c | 17 +- src/filters/write_generic.c | 665 +- src/filters/write_nhml.c | 89 +- src/filters/write_nhnt.c | 47 +- src/filters/write_qcp.c | 39 +- src/filters/write_vtt.c | 104 +- src/ietf/rtcp.c | 2 +- src/ietf/rtp.c | 3 +- src/ietf/rtp_depacketizer.c | 202 +- src/ietf/rtp_packetizer.c | 6 + src/ietf/rtp_pck_3gpp.c | 3 + src/ietf/rtp_pck_mpeg12.c | 4 + src/ietf/rtp_pck_mpeg4.c | 160 + src/ietf/rtp_streamer.c | 59 +- src/ietf/rtsp_command.c | 2 +- src/ietf/rtsp_response.c | 2 +- src/ietf/rtsp_session.c | 20 +- src/ietf/sdp.c | 16 +- src/isomedia/avc_ext.c | 732 +- src/isomedia/box_code_3gpp.c | 54 +- src/isomedia/box_code_adobe.c | 130 +- src/isomedia/box_code_apple.c | 62 +- src/isomedia/box_code_base.c | 2275 ++- src/isomedia/box_code_drm.c | 420 +- src/isomedia/box_code_meta.c | 92 +- src/isomedia/box_dump.c | 1051 +- src/isomedia/box_funcs.c | 597 +- src/isomedia/data_map.c | 24 +- src/isomedia/drm_sample.c | 563 +- src/isomedia/hint_track.c | 23 +- src/isomedia/hinting.c | 9 +- src/isomedia/iff.c | 903 +- src/isomedia/isom_intern.c | 313 +- src/isomedia/isom_read.c | 1370 +- src/isomedia/isom_store.c | 961 +- src/isomedia/isom_write.c | 2009 ++- src/isomedia/media.c | 205 +- src/isomedia/media_odf.c | 7 +- src/isomedia/meta.c | 980 +- src/isomedia/movie_fragments.c | 216 +- src/isomedia/sample_descs.c | 241 +- src/isomedia/stbl_read.c | 7 +- src/isomedia/stbl_write.c | 191 +- src/isomedia/track.c | 344 +- src/isomedia/tx3g.c | 118 +- src/jsmods/WebGLRenderingContextBase.c | 13 +- src/jsmods/core.c | 2138 ++- src/jsmods/evg.c | 3159 ++-- src/jsmods/scene_js.c | 271 +- src/jsmods/storage.c | 20 +- src/jsmods/webgl.c | 570 +- src/jsmods/webgl.h | 16 +- src/jsmods/xhr.c | 182 +- src/laser/lsr_dec.c | 727 +- src/laser/lsr_enc.c | 13 +- src/media_tools/ait.c | 4 +- src/media_tools/atsc_dmx.c | 1942 --- src/media_tools/av_parsers.c | 5415 +++++-- src/media_tools/avilib.c | 16 +- src/media_tools/crypt_tools.c | 307 +- src/media_tools/dash_client.c | 4363 +++--- src/media_tools/dash_segmenter.c | 156 +- src/media_tools/dvb_mpe.c | 94 +- src/media_tools/gpac_ogg.c | 20 +- src/media_tools/img.c | 12 +- src/media_tools/isom_hinter.c | 99 +- src/media_tools/isom_tools.c | 1210 +- src/media_tools/m2ts_mux.c | 493 +- src/media_tools/m3u8.c | 305 +- src/media_tools/media_export.c | 363 +- src/media_tools/media_import.c | 356 +- src/media_tools/mpd.c | 1472 +- src/media_tools/mpeg2_ps.c | 10 +- src/media_tools/mpegts.c | 172 +- src/media_tools/route_dmx.c | 2047 +++ src/media_tools/webvtt.c | 81 +- src/odf/descriptors.c | 515 +- src/odf/odf_code.c | 8 +- src/odf/odf_dump.c | 1 + src/odf/odf_parse.c | 1 + src/quickjs/GPAC_README.md | 23 +- src/quickjs/cutils.c | 45 +- src/quickjs/cutils.h | 4 + src/quickjs/libbf.c | 1256 +- src/quickjs/libbf.h | 124 +- src/quickjs/libregexp.c | 195 +- src/quickjs/libregexp.h | 1 + src/quickjs/libunicode-table.h | 3183 ++-- src/quickjs/libunicode.c | 16 - src/quickjs/quickjs-atom.h | 28 +- src/quickjs/quickjs-libc.c | 4404 ++++++ src/quickjs/quickjs-libc.h | 60 + src/quickjs/quickjs-opcode.h | 20 +- src/quickjs/quickjs.c | 11970 ++++++++++------ src/quickjs/quickjs.h | 131 +- src/scene_manager/encode_isom.c | 21 +- src/scene_manager/loader_bt.c | 2 +- src/scene_manager/loader_isom.c | 118 +- src/scene_manager/loader_svg.c | 6 +- src/scene_manager/loader_xmt.c | 13 +- src/scene_manager/scene_dump.c | 84 +- src/scene_manager/scene_engine.c | 20 +- src/scene_manager/scene_manager.c | 2 +- src/scene_manager/scene_stats.c | 5 + src/scene_manager/swf_bifs.c | 8 +- src/scene_manager/swf_svg.c | 6 +- src/scenegraph/base_scenegraph.c | 37 +- src/scenegraph/commands.c | 3 +- src/scenegraph/dom_events.c | 33 +- src/scenegraph/dom_js.c | 155 +- src/scenegraph/mpeg4_nodes.c | 15 +- src/scenegraph/qjs_common.h | 33 +- src/scenegraph/smil_anim.c | 97 +- src/scenegraph/smil_timing.c | 62 +- src/scenegraph/svg_attributes.c | 272 +- src/scenegraph/svg_js.c | 475 +- src/scenegraph/svg_properties.c | 3 + src/scenegraph/svg_types.c | 11 +- src/scenegraph/vrml_js.c | 695 +- src/scenegraph/vrml_proto.c | 37 +- src/scenegraph/vrml_script.c | 4 + src/scenegraph/vrml_tools.c | 15 +- src/scenegraph/x3d_nodes.c | 13 +- src/scenegraph/xml_ns.c | 16 +- src/terminal/terminal.c | 278 +- src/utils/Remotery.c | 11 +- src/utils/alloc.c | 63 +- src/utils/base_encoding.c | 4 +- src/utils/bitstream.c | 79 +- src/utils/cache.c | 197 +- src/utils/color.c | 21 +- src/utils/configfile.c | 6 +- src/utils/constants.c | 960 +- src/utils/dlmalloc.c | 6 +- src/utils/downloader.c | 2931 +++- src/utils/error.c | 180 +- src/utils/gltools.c | 568 +- src/utils/list.c | 7 +- src/utils/math.c | 32 +- src/utils/module.c | 100 +- src/utils/module_wrap.h | 2 +- src/utils/os_config_init.c | 600 +- src/utils/os_divers.c | 200 +- src/utils/os_file.c | 290 +- src/utils/os_module.c | 9 +- src/utils/os_net.c | 113 +- src/utils/os_thread.c | 19 +- src/utils/path2d.c | 18 +- src/utils/path2d_stroker.c | 2 +- src/utils/sha1.c | 35 +- src/utils/symbian_net.cpp | 8 +- src/utils/url.c | 61 +- src/utils/utf.c | 127 +- src/utils/xml_parser.c | 235 +- static.mak | 8 +- 576 files changed, 155195 insertions(+), 45400 deletions(-) delete mode 100644 Clean.bat create mode 100644 SECURITY.md delete mode 100644 applications/mp4box/wrapper.c delete mode 100644 include/gpac/atsc.h create mode 100644 include/gpac/route.h create mode 100644 manifest.rc create mode 100644 modules/test_filter/Makefile create mode 100644 modules/test_filter/test_filter.c create mode 100644 modules/test_filter/test_filter.vcxproj create mode 100644 share/doc/idl/dash_algo.idl create mode 100644 share/doc/idl/nodejs.idl create mode 100644 share/gpac.desktop create mode 100644 share/nodejs/binding.gyp create mode 100644 share/nodejs/index.js create mode 100644 share/nodejs/package.json create mode 100644 share/nodejs/src/gpac_napi.c create mode 100644 share/nodejs/src/gpac_napi.h create mode 100644 share/nodejs/test/gpac.js create mode 100644 share/python/libgpac.py create mode 100755 share/res/gpac_highres.png create mode 100644 share/scripts/custom_dash.js create mode 100644 share/scripts/jsf/avgen/init.js create mode 100644 share/scripts/jsf/avgen/testcard.png create mode 100644 share/scripts/jsf/avmix/help.js create mode 100644 share/scripts/jsf/avmix/init.js create mode 100644 share/scripts/jsf/avmix/scenes/clear.js create mode 100644 share/scripts/jsf/avmix/scenes/clip.js create mode 100644 share/scripts/jsf/avmix/scenes/mask.js create mode 100644 share/scripts/jsf/avmix/scenes/shape.js create mode 100644 share/scripts/jsf/avmix/transitions/fade.js create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/Bounce.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/BowTieHorizontal.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/BowTieVertical.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/BowTieWithParameter.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/ButterflyWaveScrawler.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/CircleCrop.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/ColourDistance.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/CrazyParametricFun.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/CrossZoom.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/Directional.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/DoomScreenTransition.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/Dreamy.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/DreamyZoom.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/FilmBurn.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/GlitchDisplace.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/GlitchMemories.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/GridFlip.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/InvertedPageCurl.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/LeftRight.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/LinearBlur.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/Mosaic.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/PolkaDotsCurtain.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/Radial.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/SimpleZoom.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/StereoViewer.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/Swirl.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/TVStatic.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/TopBottom.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/WaterDrop.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/ZoomInCircles.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/angular.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/burn.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/cannabisleaf.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/circle.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/circleopen.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/colorphase.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/crosshatch.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/crosswarp.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/cube.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/directional-easing.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/directionalwarp.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/directionalwipe.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/displacement.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/doorway.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/fade.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/fadecolor.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/fadegrayscale.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/flyeye.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/heart.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/hexagonalize.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/kaleidoscope.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/luma.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/luminance_melt.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/morph.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/multiply_blend.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/perlin.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/pinwheel.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/pixelize.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/polar_function.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/randomNoisex.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/randomsquares.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/ripple.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/rotateTransition.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/rotate_scale_fade.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/squareswire.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/squeeze.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/swap.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/tangentMotionBlur.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/undulatingBurnOut.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/wind.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/windowblinds.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/windowslice.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/wipeDown.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/wipeLeft.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/wipeRight.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gl-transitions/wipeUp.glsl create mode 100644 share/scripts/jsf/avmix/transitions/gltrans.js create mode 100644 share/scripts/jsf/avmix/transitions/mix.js create mode 100644 share/scripts/jsf/avmix/transitions/swipe.js create mode 100644 share/scripts/vout.js create mode 100644 src/filters/bs_agg.c create mode 100644 src/filters/bs_split.c delete mode 100644 src/filters/in_atsc.c create mode 100644 src/filters/in_route.c create mode 100644 src/filters/io_fcryp.c create mode 100644 src/filters/out_route.c create mode 100644 src/filters/reframe_mhas.c create mode 100644 src/filters/reframe_truehd.c create mode 100644 src/filters/restamp.c create mode 100644 src/filters/rewrite_mhas.c create mode 100644 src/filters/tilesplit.c delete mode 100644 src/media_tools/atsc_dmx.c create mode 100644 src/media_tools/route_dmx.c create mode 100644 src/quickjs/quickjs-libc.c create mode 100644 src/quickjs/quickjs-libc.h diff --git a/.gitignore b/.gitignore index ba9dd27..eef1582 100644 --- a/.gitignore +++ b/.gitignore @@ -85,7 +85,6 @@ extra_lib/include/ config.mak configure-stamp gpac.pc -share/gpac.desktop tests/external_media/ tests/results/ tests/hash_refs/ diff --git a/.gitmodules b/.gitmodules index 670f16f..0daa934 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,5 @@ [submodule "testsuite"] path = testsuite url = https://github.com/gpac/testsuite.git - branch = filters + branch = master ignore = dirty diff --git a/.travis.yml b/.travis.yml index 7ec1e92..5c6b79a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ #TravisCI is only used for checking sanity of PRs. Consequently: #- OSX and mingw no longer compiled #- linux only compiled for -# - mp4box static +# - mp4box and gpac static # - release mode with mem tracking and gcov language: c @@ -26,9 +26,9 @@ install: # - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install gnu-time gnu-sed gnu-tar xz lcov ; fi # - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install faad2 sdl freetype libvorbis theora openjpeg libmad xvid libogg spidermonkey ffmpeg ; fi env: - - GPAC_CONFIGURE_OPTIONS="--prefix=build/mp4box --enable-debug --static-mp4box" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="make install" DOTRAVIS="" + - GPAC_CONFIGURE_OPTIONS="--prefix=build/mp4box --enable-debug --static-bin" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="make install" DOTRAVIS="" - GPAC_CONFIGURE_OPTIONS="--enable-debug --static-modules" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="" DOTRAVIS="" - - GPAC_CONFIGURE_OPTIONS="--enable-debug --enable-static-bin" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="" DOTRAVIS="" + - GPAC_CONFIGURE_OPTIONS="--enable-debug --static-build" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="" DOTRAVIS="" matrix: include: - os: linux @@ -39,9 +39,9 @@ matrix: env: GPAC_CONFIGURE_OPTIONS="--enable-mem-track --enable-gcov" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="sudo make install" DOTRAVIS="make travis" AUDIODEV=null # - os: linux -# env: GPAC_CONFIGURE_OPTIONS="--prefix=build/x86_64-w64-mingw32 --enable-debug --static-mp4box --use-zlib=no --target-os=mingw32 --cross-prefix=i686-w64-mingw32- --extra-ldflags=-Lbuild/x86_64-w64-mingw32/lib" GPAC_CONFIGURE_ECFLAGS="-Ibuild/x86_64-w64-mingw32/include -w -fPIC" DOINSTALL="" DOTRAVIS="" +# env: GPAC_CONFIGURE_OPTIONS="--prefix=build/x86_64-w64-mingw32 --enable-debug --static-bin --use-zlib=no --target-os=mingw32 --cross-prefix=i686-w64-mingw32- --extra-ldflags=-Lbuild/x86_64-w64-mingw32/lib" GPAC_CONFIGURE_ECFLAGS="-Ibuild/x86_64-w64-mingw32/include -w -fPIC" DOINSTALL="" DOTRAVIS="" # - os: linux -# env: GPAC_CONFIGURE_OPTIONS="--prefix=build/x86_64-w64-mingw32 --enable-debug --static-mp4box --use-zlib=no --target-os=mingw32 --cross-prefix=x86_64-w64-mingw32- --extra-ldflags=-Lbuild/x86_64-w64-mingw32/lib" GPAC_CONFIGURE_ECFLAGS="-Ibuild/x86_64-w64-mingw32/include -w -fPIC" DOINSTALL="" DOTRAVIS="" +# env: GPAC_CONFIGURE_OPTIONS="--prefix=build/x86_64-w64-mingw32 --enable-debug --static-bin --use-zlib=no --target-os=mingw32 --cross-prefix=x86_64-w64-mingw32- --extra-ldflags=-Lbuild/x86_64-w64-mingw32/lib" GPAC_CONFIGURE_ECFLAGS="-Ibuild/x86_64-w64-mingw32/include -w -fPIC" DOINSTALL="" DOTRAVIS="" # - os: linux # env: GPAC_CONFIGURE_OPTIONS="--prefix=build/all --enable-debug --disable-all" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="make install" DOTRAVIS="" # - os: linux @@ -50,8 +50,6 @@ matrix: # env: GPAC_CONFIGURE_OPTIONS="--enable-mem-track" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="sudo make install" DOTRAVIS="" AUDIODEV=null script: - ./configure --extra-cflags=''"$GPAC_CONFIGURE_ECFLAGS"'' $GPAC_CONFIGURE_OPTIONS && make && $DOINSTALL && ( if [ -n "$DOTRAVIS" ]; then xvfb-run -e /dev/stdout --auto-servernum --server-num=1 --server-args="-screen 0 1024x768x24" $DOTRAVIS ; fi ) -after_success: - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then bash <(curl -s https://codecov.io/bash) ; fi notifications: email: diff --git a/Changelog b/Changelog index a3f1d79..ac35f81 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,98 @@ -10/09/2020: GPAC 1.0.1 +22/02/2022: GPAC 2.0 + +## Adaptive Streaming +- Low Latency HLS (LL-HLS, generation and playback) +- Custom forwarding modes of DASH reader, allowing for example to encrypt/decrypt a live DASH/HLS session +- DASHing now possible using inband cues (generated by flist, dashin or dasher filters) +- Cue-generation only mode for dasher +- HLS/DASH signaling of intra-only representations +- playback improvements for SRD (HEVC tiling and independent streams) +- CMAF-compatible signaling +- PPS injection for inband parameter set modes +- Improved SmoothStreaming support +- DASH period continuity support (from playlists or reframer) +- DASH MPD Chaining support +- Text segments in native format (WebVTT, TTML) in dasher +- User tags injection for HLS master and variant playlists + +## Image File Format (HEIF) +- Grid creation and other derived images +- Encryption +- Time range in -add-image +- Item to sample data reference (no copy) +- Item to item data reference (no copy) +- Generic auxiliary image tagging +- Image replacement in HEIF collection +- AV1 (AVIF) and VVC support + +## MP4Box +- In-place editing (no file remultiplexing) +- Improved splitting, including sample-accurate split +- ISOBMFF edit lists modification through :edits and -edits options +- Track extraction from non ISOBMFF sources in MP4Box +- Most import options can now be applied on an existing ISOBMF file or track +- Multiple filter chains per source in -dash or -add modes +- Chunk interleaving dumper + +## Filters +- Simplified gpac command line (backward compatible syntax) avoiding links directives for common cases +- Added avmix, a playlist-based audio video mixer/compositor with GPU or software rendering +- Python bindings for filter session +- NodeJS bindings for filter session +- Custom HAS adaptation algorithms (JS, Python and NodeJS) +- Custom Remotery callbacks (JS, Python and NodeJS) +- Added avgen, a simple counter generation +- Splicing support in playlists: raw and compressed domain, vod and live splicing +- Tile splitting now available as a filter +- Added restamp, a stream timestamp rewriter filter +- Added bssplit and bsagg, compressed bitstream splitter and aggregator filters +- Aspect ratio support in rescaler (ffsws) +- Raw (uncompressed) modes for flist and reframer +- Flip and rotate in vout +- Simple UI for vout to test seeking and speed modes +- Improved color space support in rendering (OpenGL only) +- Improved round-trip audio decode +- Improved audio resampler +- Added back old arch compositor features (TEMI support, HEVC tiling JS monitoring, MPEG-4 SegmentDescriptor) +- Reading back frame interface data (GPU, decoder mem) in JS or Python sink filters +- Memory storage in httpout server file sink +- FileIO wrapper available in QJS, Python and NodeJS + +## Protocols +- HTTP/2 (client and server) through nghttp2 +- ROUTE multiplexer and low-latency ROUTE (mux and demux) + +## Media Formats +- Improved MPEG-H audio mux/demux/dashing +- VVC parsing, inspecting, mux/demux (ISOBMFF, M2TS), RTP, DASH and encryption +- VUI color info rewrite for AVC, HEVC and VVC (mp4box and bsrw filter) +- Dolby TrueHD +- DolbyVision muxing +- Improved multichannel AAC (>=8) support +- Improved raw video in ISOBMFF support +- Bitstream dumping for inspect analyze mode +- Improved TTML support: metrics, image embedding (IMSC1), TTML sample merging while exporting, subtitle zero in TTML +- YouTube VR meta-data +- yuv4mpeg format read/write +- Extended NHML syntax for properties, reconfiguration, subsamples and sample auxiliary data + +## Encryption +- Multi-key per sample encryption +- HLS full segment encryption and decryption +- Per-segment or per-period key roll +- Master/leaf key schemes + +## Misc +- Improved HTTP rate limiter and chunk-transfer rate estimator +- Cleanup of mod-dirs and js-dirs usage, JS filters can now be included in the default available filters +- Support for windows long path +- Moved to latest QuickJS (2021-03-27) +- Added QJS-libc modules, support for exec/waitpid/kill and Workers on most platforms +- Support for FFmpeg 4.4 + +- many bug fixes, improvements and security patches + + +# 10/09/2020: GPAC 1.0.1 This release fixes build and installation issues in 1.0.0, as well as various bugs introduced during the migration to the filters architecture. It also adds several small features: @@ -11,7 +105,7 @@ It also adds several small features: - core tools exposed as JS module (file io, bitstream, etc ...) - android fixes -16/06/2020: GPAC 1.0 +# 16/06/2020: GPAC 1.0 - Complete rewrite of GPAC streaming core: * addition of a filter-based architecture, used by MP4Client and MP4Box. * moving all decoders and demuxer plugins of MP4Client and most of MP4Box import/export code as filters for this new architecture, @@ -34,7 +128,7 @@ It also adds several small features: * HTTP output (client and server), supporting low latency DASH access * Ad-hoc stream format called GSF to allow serialization to file, pipe or socket of a session (for distributed filter chains), supporting AES-128 CBC encryption. - Raw audio (PCM) and video (RGB, YUV) reframers and exporters -- HEVC tile spliting and merging filters +- HEVC tile splitting and merging filters - Compositor is a standalone filter (SVG/BIFS/VRML graphics in a filter chain) - Image encoding support through libjpg and libpng - Full FFMPEG support: @@ -176,7 +270,7 @@ It also adds several small features: * Moved dektec output to matrix API, added SDI clipping * Added temi periodic toggle and manual toggle in MP42TS -26/04/2017: GPAC 0.7.1 +# 26/04/2017: GPAC 0.7.1 - Full changelog at https://github.com/gpac/gpac/wiki/GPAC-0.7.0 - Many security fixes (static compile and fuzzing through [AFL](http://lcamtuf.coredump.cx/afl/), always ongoing) - Colorized log. @@ -207,10 +301,10 @@ It also adds several small features: - Android: new File Manager. - Import of TTML via NHML according to MPEG-4 part 30 improved. -19/02/2016: GPAC 0.6.0 +# 19/02/2016: GPAC 0.6.0 Many things added, improved and fixed - see https://github.com/gpac/gpac/releases/tag/v0.6.0 -25/05/2012: GPAC 0.5.0 +# 25/05/2012: GPAC 0.5.0 - MPEG-DASH and Apple HLS support in GPAC Clients - MPEG-DASH segmenter for ISO files and MPEG-2 TS in MP4Box - MP42TS generator now supports HLS output @@ -228,7 +322,7 @@ It also adds several small features: - more work on GUI - and many many fixes and improvements in players and MP4Box -02/12/08: GPAC 0.4.5 +# 02/12/08: GPAC 0.4.5 - Support for AC3 in ISO Media, AC3 decoder (liba52) RTP hinting - Support for MediaAccessEvent (spec still under development ??) - Added support for user extensions (global class only) in JS through modules - cf gpac_js for sample code. @@ -284,7 +378,7 @@ It also adds several small features: - committed patch fixing VobSub extraction bug - added support for http playback in ffmpeg demuxer -31/05/07: GPAC 0.4.4 +# 31/05/07: GPAC 0.4.4 - Added support for XMLHttpRequest for both VRML/MPEG-4 and SVG. All methods should be supported, but only GET/HEAD have been tested - Added a basic subset of DOM Core for xml doc (XMLHttpRequest, SVG) and moved the uDOM implementation in it. - Added support for SVG focus & navigation in 2D renderer @@ -338,7 +432,7 @@ It also adds several small features: - major speed improvements in MPEG-4/VRML scripts and SVG uDOM regarding node creation - and a lot more bug fixes... -21/07/06: GPAC 0.4.2 +# 21/07/06: GPAC 0.4.2 - commit of GPAX (GPAC ActiveX) - controller only works in IE and ActiveX control tester for now. - API changes to Osmozilla to keep in sync with GPAX. Sample html file can be found in applications/GPAX. - both plugin now support browser navigation (ie link to html within MPEG-4 content) @@ -374,7 +468,7 @@ It also adds several small features: - cf configuration.html or man gpac for more info on progressive loading control - added 'define' support in BT - to use it just do: #define symbol blab labl a - and reuse the symbol in the BT text. This may be quite buggy, but it can be usefull + and reuse the symbol in the BT text. This may be quite buggy, but it can be useful - support for Scene Carousel in hinters, core and rtp reassembler. Currently only BIFS and BIFS+AV can be use the scene carousel, carouseling of static data (eg images) is not supported. The OD data must be embedded in the IOD a la ISMA. - added FPS and size info dumping for MPEG and AVI file import (MP4Box -info file.mpg) @@ -402,7 +496,7 @@ It also adds several small features: - basic conditional processing (switch) - SMIL anim events (begin, end, restart) - added PAR modification support to MP4Box (import time and file based) - - improved precision of IsoMedia file spliting + - improved precision of IsoMedia file splitting - added NHML import/export. NHML is an XML representation of the NHNT file, with add-ons and a more flexible way of integrating media. Doc to come on web site - clean-up of 2D direct rendering mode: * no more bounds tracking for less memory usage @@ -461,7 +555,7 @@ It also adds several small features: - fixes for gpac compilation on 64 bits platforms - fixed bugs related to cache in file downloader -03/08/05: GPAC 0.4.0 RC2 +# 03/08/05: GPAC 0.4.0 RC2 - fixed Invalid versioning of previous release (was still 0.4.0-DEV...) - fixed MinGW compilation - fixed MP4Box handling of full MSDOS paths (C:\) @@ -471,7 +565,7 @@ It also adds several small features: - fixed MP4A-LATM support at client side - fixed X11 module in embedded mode (should work well with both Osmo4/wx and Osmozilla) -28/07/05: GPAC 0.4.0 release +# 28/07/05: GPAC 0.4.0 release ** GPAC is now licensed under LGPL. ** Massive code rewrite and repository reorganization in order to comply to some base coding style (cf gpac/doc/CODING_STYLE) have taken place since previous release. Documentation is still a work in progress. @@ -499,8 +593,8 @@ It also adds several small features: - misc fixes in MP4Box option parsing, in RTP multicast setup - Osmozilla should now be much more stable on Win32 - Linux version to come. - -20/06/05: GPAC 0.3.0 release + +# 20/06/05: GPAC 0.3.0 release - fixed bug in 4GB file writing in interleaving mode - fixed bug in absolute path usage in MP4Box - added -cat file*.mpg syntax support @@ -517,7 +611,7 @@ It also adds several small features: - misc fixes in ffmpeg decoder and MP4Box ISMA for PAR - this is disabled by default due to some unsolved crashes, cf gpac/doc/configuration.html or man gpac.s - misc updates in MP4Box meta handling for item extraction. - fixed MPEG-2 aac importing and info dumping - - fixed 3GPP text display bug when stoping and changing an animationStream using a 3GPP text object. + - fixed 3GPP text display bug when stopping and changing an animationStream using a 3GPP text object. - fixed AVC/H264 HP parsing - added BIFS track visual size info at BT/XMT encoding stage - MOVED FFMPEG INCLUDE FILES TO LATEST CVS VERSION to support AVC/H264 HP decoding @@ -533,7 +627,7 @@ It also adds several small features: FROM THIS DAY ON, ALL WORK ADDED TO GPAC IS COPYLEFT ENST -15/05/05: +# 15/05/05: - Updated makefiles and configure for MacOSX support - commit of GPAC fixed-point version - may not be completely stable yet :) - changed all project files location for soon-to-come EVC4 and Visual .NET support @@ -565,7 +659,7 @@ It also adds several small features: ** Streams with different sample descriptions are imported as distinct tracks ** - fixed bugs in OD and IPMPX parsers (ipmpDescrPtr and IPMP_ToolID) -30/03/05: GPAC 0.2.4 release +# 30/03/05: GPAC 0.2.4 release - Added TeXML import (QT XML format for 3GPP text) - Added SRT extraction for text tracks. - Added SUB subtitles support (SUB->3GPP text, SUB->BIFS) @@ -611,7 +705,7 @@ It also adds several small features: - fixed raw aac export bug - fixed DIV5 import issues with PLs -05/01/05: GPAC 0.2.3 release +# 05/01/05: GPAC 0.2.3 release - new regression tests (X3D and some other features) - MPEG-4 playback from BT/XMT now supports proper startTime/stopTime behaviour - found a port of XVID for WinCE/ARM, removed OpenDivX from distribution (seemed no longer maintained). This XviD port is BTW much faster & more reliable than old OpenDivx @@ -662,7 +756,7 @@ It also adds several small features: Need some more testing before filing a request to mp4ra.org. Streaming possible as MPEG-4 streams, Vorbis RTP packetizer still to be done. -09/11/04: GPAC 0.2.2 release +# 09/11/04: GPAC 0.2.2 release - Xiph OGG demuxer: supports file, http download (not tested) and icecast servers. - Xiph Vorbis decoder - Xiph Theora support (should work with fluendo but I can't get any data from the server...) @@ -701,7 +795,7 @@ It also adds several small features: - plethora of bug fixes -15/10/04: GPAC 0.2.1 release +# 15/10/04: GPAC 0.2.1 release - massive fixes in javascript (assignment was only 50% working), new faster, less memory-hungry implementation (and Othello reg test now passes!!) - CreateVrmlFromScript support for VRML content. - collision detection @@ -752,7 +846,7 @@ It also adds several small features: - BT parser supports basic VRML (uncompressed .WRL should now be imported fine) - plethora of bug fixes -02/09/04: GPAC 0.2.0 release +# 02/09/04: GPAC 0.2.0 release - updated cfg file doc man pages & makefiles - massive re-arch of renderer(s) to be able to load at run-time either 2D or 3D renderer, instead of static linking - new 2D and 3D renderers @@ -791,10 +885,10 @@ It also adds several small features: * updated 2D and 3D renderer accordingly - added support for rectangular textures in GL (most graphic cards support this, at least on win32) - added frustum culling - - added SFTime->SFString formating in valuator (current MPEG-4 COR) + - added SFTime->SFString formatting in valuator (current MPEG-4 COR) - plethora of bug fixes -11/05/04: JLF: dev version 0.1.9 +# 11/05/04: JLF: dev version 0.1.9 - changed source code architecture: rendering code is now in a dedicated static link outside libm4systems - intergated draft 3D renderer: - Most 2D features have been ported to the new renderer (missing: viewport, colorTransform and gradients) @@ -812,7 +906,7 @@ It also adds several small features: - uploaded ultra basic SWF convertor (so that it doesn't get lost on my hard drive:) - plethora of bug fixes -28/04/04: GPAC Release 0.1.4 +# 28/04/04: GPAC Release 0.1.4 - MP4Box avi import fixes (key frames, VOL removal, n-VOP handling) - Fixed MP4 and NHNT importers (visual tracks sizes) - MP4Box avi extractor for visual tracks @@ -828,7 +922,7 @@ It also adds several small features: - better "end of presentation" support - plethora of bug fixes -18/04/04: JLF: GPAC Release 0.1.3 rc2 +# 18/04/04: JLF: GPAC Release 0.1.3 rc2 - MP4Box default hinting is now QT compatible - b-frame hinting support - DecodingBuffer and CompositionMemory occupancey in ODInfo - layout text splitting (word boundaries only) @@ -852,7 +946,7 @@ It also adds several small features: - moved all windowing architecture to the video output plugins (keyboard and mouse events, WM messages) in order to support SDL, moved old input functions to new event model - modified jconfig.h to support both win32 and MinGW. - updated V4Studio to work with new event/windowing architecture (work with SDL and DX) - - UDP autoconfig option (if no UDP traffic is recieved, restart with TCP) + - UDP autoconfig option (if no UDP traffic is received, restart with TCP) - moved to FAAD2.1 (CVS), fixed faad2 compil on MinGW & winCE - cleaned up install docs - added support for SDL with software YUV->RGB and software stretching @@ -865,7 +959,7 @@ It also adds several small features: - added support for xvid 1.0.0 - plethora of bug fixes -28/01/04: GPAC Release 0.1.2 +# 28/01/04: GPAC Release 0.1.2 - codec selection in Osmo4 GUI - PocketPC installer - OpenDivx plugin @@ -900,7 +994,7 @@ It also adds several small features: - AMR NB support (payload parsing and 3GP codec plugin) - plethora of bug fixes -20/11/03: GPAC Release 0.1.1 +# 20/11/03: GPAC Release 0.1.1 - 3GP rtsp streaming support - GPAC uses latest stable extra libs: faad2 2.0rc3, FreeType 2.1.5 and mad 0.15.0b, and dev version (20031117) of xvid - support for MediaSegment ranges ("#seg+" and "#seg1-seg2") in MediaControl/MediaSensor @@ -937,5 +1031,5 @@ It also adds several small features: - InputSensor (keySensor, Mouse and StringSensor) - plethora of bug fixes -version 0.1.0: +# version 0.1.0: initial release diff --git a/Clean.bat b/Clean.bat deleted file mode 100644 index e619504..0000000 --- a/Clean.bat +++ /dev/null @@ -1,23 +0,0 @@ -cd src -DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph -cd .. - -cd modules -DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph -cd .. - -cd build -DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph -cd .. - -cd applications -DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.dll *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph -cd .. - -cd bin -DEL /S *.obj *.lib *.pch *.pdb *.idb *.exp *.plg *.res *.plg *.ncb *.opt *.APS *.ilk *.SUP *.sbr *.map *.vcl *.o *.exe *.a *.NCB *.OPT *.vcb *.vco *.bsc *.HLP *.hm *.LOG *.ph -cd .. - - - - diff --git a/Makefile b/Makefile index 303a413..9a09be6 100644 --- a/Makefile +++ b/Makefile @@ -12,13 +12,14 @@ vpath %.c $(SRC_PATH) all: version $(MAKE) -C src all $(MAKE) -C applications all -ifneq ($(MP4BOX_STATIC),yes) +ifneq ($(STATIC_BINARY),yes) $(MAKE) -C modules all endif config.mak: - ./configure + @echo "running default configure" + @./configure GITREV_PATH:=$(SRC_PATH)/include/gpac/revision.h @@ -116,13 +117,15 @@ install: $(MAKE) install-lib $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/gpac$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" + if [ -f bin/gcc/MP4Box$(EXE_SUFFIX) ] ; then \ + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/gpac$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" ; \ + fi ifeq ($(DISABLE_ISOFF),no) if [ -f bin/gcc/MP4Box$(EXE_SUFFIX) ] ; then \ $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Box$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" ; \ fi endif -ifneq ($(MP4BOX_STATIC),yes) +ifneq ($(STATIC_BINARY),yes) ifeq ($(DISABLE_PLAYER),no) if [ -f bin/gcc/MP4Client$(EXE_SUFFIX) ] ; then \ $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Client$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" ; \ @@ -130,7 +133,7 @@ ifeq ($(DISABLE_PLAYER),no) endif endif $(INSTALL) -d "$(DESTDIR)$(prefix)/$(lib_dir)/$(moddir)" -ifneq ($(MP4BOX_STATIC),yes) +ifneq ($(STATIC_BINARY),yes) $(INSTALL) bin/gcc/gm_*$(DYN_LIB_SUFFIX) "$(DESTDIR)$(prefix)/$(lib_dir)/$(moddir)" || true $(INSTALL) bin/gcc/gf_*$(DYN_LIB_SUFFIX) "$(DESTDIR)$(prefix)/$(lib_dir)/$(moddir)" || true ifeq ($(CONFIG_OPENHEVC),yes) @@ -151,34 +154,39 @@ endif $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui/extensions" $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/shaders" $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/scripts" - $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/res/gpac.mp4 $(DESTDIR)$(prefix)/share/gpac/res/ - $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/res/gpac_cfg_test.mp4 $(DESTDIR)$(prefix)/share/gpac/res/ - $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/res/gpac.png $(DESTDIR)$(prefix)/share/gpac/res/ + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/python" + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/vis" $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/default.cfg $(DESTDIR)$(prefix)/share/gpac/ ifneq ($(CONFIG_DARWIN),yes) - $(INSTALL) -d "$(DESTDIR)$(prefix)/share/pixmaps" + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/icons/hicolor/128x128/apps" $(INSTALL) -d "$(DESTDIR)$(prefix)/share/applications" - $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/res/gpac.png "$(DESTDIR)$(prefix)/share/pixmaps/" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/res/gpac.png "$(DESTDIR)$(prefix)/share/icons/hicolor/128x128/apps/" $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/gpac.desktop "$(DESTDIR)$(prefix)/share/applications/" endif $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/gui/gui.bt "$(DESTDIR)$(prefix)/share/gpac/gui/" $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/gui/gui.js "$(DESTDIR)$(prefix)/share/gpac/gui/" $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/gui/gwlib.js "$(DESTDIR)$(prefix)/share/gpac/gui/" - $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/scripts/webvtt-renderer.js "$(DESTDIR)$(prefix)/share/gpac/scripts/" - $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/share/scripts/ttml-renderer.js "$(DESTDIR)$(prefix)/share/gpac/scripts/" ifeq ($(CONFIG_DARWIN),yes) cp $(SRC_PATH)/share/gui/icons/* "$(DESTDIR)$(prefix)/share/gpac/gui/icons/" cp -R $(SRC_PATH)/share/gui/extensions/* "$(DESTDIR)$(prefix)/share/gpac/gui/extensions/" cp $(SRC_PATH)/share/shaders/* "$(DESTDIR)$(prefix)/share/gpac/shaders/" + cp -R $(SRC_PATH)/share/scripts/* "$(DESTDIR)$(prefix)/share/gpac/scripts/" + cp -R $(SRC_PATH)/share/python/* "$(DESTDIR)$(prefix)/share/gpac/python/" + cp $(SRC_PATH)/share/res/* "$(DESTDIR)$(prefix)/share/gpac/res/" + cp -R $(SRC_PATH)/share/vis/* "$(DESTDIR)$(prefix)/share/gpac/vis/" else cp --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/gui/icons/* $(DESTDIR)$(prefix)/share/gpac/gui/icons/ cp -R --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/gui/extensions/* $(DESTDIR)$(prefix)/share/gpac/gui/extensions/ cp --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/shaders/* $(DESTDIR)$(prefix)/share/gpac/shaders/ + cp -R --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/scripts/* $(DESTDIR)$(prefix)/share/gpac/scripts/ + cp -R --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/python/* $(DESTDIR)$(prefix)/share/gpac/python/ + cp --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/res/* $(DESTDIR)$(prefix)/share/gpac/res/ + cp -R --no-preserve=mode,ownership,timestamp $(SRC_PATH)/share/vis/* $(DESTDIR)$(prefix)/share/gpac/vis/ endif lninstall: @@ -189,7 +197,7 @@ lninstall: ifeq ($(DISABLE_ISOFF),no) ln -sf $(BUILD_PATH)/bin/gcc/MP4Box$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Box$(EXE_SUFFIX) endif -ifneq ($(MP4BOX_STATIC),yes) +ifneq ($(STATIC_BINARY),yes) ifeq ($(DISABLE_PLAYER),no) ln -sf $(BUILD_PATH)/bin/gcc/MP4Client$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Client$(EXE_SUFFIX) endif @@ -198,13 +206,17 @@ ifeq ($(CONFIG_DARWIN),yes) ln -s $(BUILD_PATH)/bin/gcc/libgpac$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(lib_dir)/libgpac.$(VERSION_SONAME)$(DYN_LIB_SUFFIX) ln -sf $(DESTDIR)$(prefix)/$(lib_dir)/libgpac.$(VERSION_SONAME)$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(lib_dir)/libgpac.$(VERSION_MAJOR)$(DYN_LIB_SUFFIX) ln -sf $(DESTDIR)$(prefix)/$(lib_dir)/libgpac.$(VERSION_SONAME)$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(lib_dir)/libgpac$(DYN_LIB_SUFFIX) + + ln -s $(BUILD_PATH)/bin/gcc/ $(DESTDIR)$(prefix)/$(lib_dir)/gpac + ln -s $(SRC_PATH)/share/ $(DESTDIR)$(prefix)/share/gpac else ln -s $(BUILD_PATH)/bin/gcc/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(lib_dir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) ln -sf $(DESTDIR)$(prefix)/$(lib_dir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(lib_dir)/libgpac.so.$(VERSION_MAJOR) ln -sf $(DESTDIR)$(prefix)/$(lib_dir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(lib_dir)/libgpac.so + ln -s $(BUILD_PATH)/bin/gcc/ $(DESTDIR)$(prefix)/$(lib_dir)/gpac ln -s $(SRC_PATH)/share/ $(DESTDIR)$(prefix)/share/gpac - ln -sf $(DESTDIR)$(prefix)/share/gpac/res/gpac.png $(DESTDIR)/usr/share/pixmaps/gpac.png + ln -sf $(DESTDIR)$(prefix)/share/gpac/res/gpac.png $(DESTDIR)/usr/share/icons/hicolor/128x128/apps/gpac.png ln -sf $(SRC_PATH)/share/gpac.desktop $(DESTDIR)/usr/share/applications/ ifeq ($(DESTDIR)$(prefix),$(prefix)) @@ -225,16 +237,18 @@ uninstall: rm -rf $(DESTDIR)$(prefix)/$(man_dir)/man1/gpac.1 rm -rf $(DESTDIR)$(prefix)/$(man_dir)/man1/gpac-filters.1 rm -rf $(DESTDIR)$(prefix)/share/gpac - rm -rf $(DESTDIR)$(prefix)/share/pixmaps/gpac.png + rm -rf $(DESTDIR)$(prefix)/share/icons/hicolor/128x128/apps/gpac.png rm -rf $(DESTDIR)$(prefix)/share/applications/gpac.desktop installdylib: -ifneq ($(MP4BOX_STATIC),yes) +ifneq ($(STATIC_BINARY),yes) $(INSTALL) -d "$(DESTDIR)$(prefix)/$(lib_dir)" ifeq ($(CONFIG_WIN32),yes) + $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll.a $(DESTDIR)$(prefix)/$(lib_dir) $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll $(DESTDIR)$(prefix)/bin else diff --git a/README.md b/README.md index b9c4a4a..48326b6 100644 --- a/README.md +++ b/README.md @@ -24,25 +24,26 @@ # GPAC Introduction -Current version: 1.0.1 +Latest Release: 2.0 GPAC is an open-source multimedia framework focused on modularity and standards compliance. -GPAC provides tools to process, inspect, package, stream playback and interact with media content. Such content can be any combination of audio, video, subtitles, metadata, scalable graphics, encrypted media, 2D/3D graphics and ECMAScript. -GPAC is best-known for its wide MP4 capabilities and is popular among video enthusiasts, academic researchers, standardization bodies, and professional broadcasters. +GPAC provides tools to process, inspect, package, stream, playback and interact with media content. Such content can be any combination of audio, video, subtitles, metadata, scalable graphics, encrypted media, 2D/3D graphics and ECMAScript. +GPAC is best-known for its wide MP4/ISOBMFF capabilities and is popular among video enthusiasts, academic researchers, standardization bodies, and professional broadcasters. For more information, visit [GPAC website](http://gpac.io) GPAC is distributed under the LGPL v2.1 or later, and is also available, for most of it, under a [commercial license](https://www.gpac-licensing.com). -Please cite our work in your research: -- GPAC Filters: https://doi.org/10.1145/3339825.3394929 -- GPAC: https://doi.org/10.1145/1291233.1291452 +Please ! _cite_ ! our work in your research: +- "GPAC Filters" (https://doi.org/10.1145/3339825.3394929) for recent versions (0.9 or above) +- "GPAC: open source multimedia framework" (https://doi.org/10.1145/1291233.1291452) for older versions. + # Features GPAC can process, analyse, package, stream, encode, decode and playback a wide variety of contents. Selected feature list: - Audio: MPEG audio (mp1/2/3, aac), AC3, E-AC3, Opus, FLAC, … -- Video: MPEG 1 / 2 / 4 (H264/AVC) / H (HEVC), AV1, VP9, Theora, ... +- Video: MPEG 1 / 2 / 4 (H264/AVC) / H (HEVC), VVC, AV1, VP9, Theora, ... - Subtitles: WebVTT, TTML (full, EBU-TTD, …), 3GPP/Apple Timed Text, … - Encryption: CENC, PIFF, ISMA, OMA, ... - Containers: MP4/fMP4/CMAF/Quicktime MOV/ProRes MOV, AVI, MPG, OGG, MKV, ... @@ -53,27 +54,31 @@ GPAC can process, analyse, package, stream, encode, decode and playback a wide v - 3D support (360 videos, WebGL JS filters…) - Inputs: microphone, camera, desktop grabbing - Highly configurable media processing pipeline +- Python and NodeJS bindings Features are encapsulated in processing modules called filters: - to get the full list of available features, you can run the command line `gpac -h filters` or check [filters' wiki](https://github.com/gpac/gpac/wiki/Filters). -- to get the full list of playback features, check [our wiki](https://github.com/gpac/gpac/wiki/Player-Features). +- to get the full list of playback features, check [the dedicated wiki page](https://github.com/gpac/gpac/wiki/Player-Features). # Tools ## MP4Box -MP4Box is a multi-purpose MP4 file manipulation for the prompt, featuring media importing and extracting, file inspection, DASH segmentation, RTP hinting, ... See `MP4Box -h`, `man MP4Box` or [our wiki](https://wiki.gpac.io/MP4Box-Introduction). +MP4Box is a multi-purpose MP4 file manipulation for the prompt, featuring media importing and extracting, file inspection, DASH segmentation, RTP hinting, ... See `MP4Box -h`, `man MP4Box` or [our wiki](https://wiki.gpac.io/MP4Box). ## gpac -As of version 0.9.0, GPAC includes a filter engine in charge of stream management and used by most applications in GPAC - [read this post](https://wiki.gpac.io/Rearchitecture) for more dicussion on how this impacts MP4Box and MP4Client. +GPAC includes a filter engine in charge of stream management and used by most applications in GPAC - [read this post](https://wiki.gpac.io/Rearchitecture) for more discussion on how this impacts MP4Box and MP4Client. The gpac application is a direct interface to the filter engine of GPAC, allowing any combinaison of filters not enabled by other applications. See `gpac -h`, `man gpac`, `man gpac-filters` or [our wiki](https://wiki.gpac.io/Filters) for more details. -## MP4Client +## MP4Client (deprecated) MP4Client is a media player built upon libgpac, featuring a rich media interactive composition engine with MPEG-4 BIFS, SVG, VRML/X3D support. For GPAC configuration instruction, check `MP4Client -h` , `man MP4Client` or [our wiki](https://wiki.gpac.io/mp4client). - +__Warning__ +MP4Client is deprecated and will be removed in the next release. Start modifying your scripts: +- replace `MP4Client URL` with `gpac -play URL` (audio/video playback only) or `gpac -mp4c URL` (if compositor is needed) +- replace `MP4Client -gui URL` with `gpac -gui URL`. # Getting started ## Download @@ -84,33 +89,30 @@ If you want to compile GPAC yourself, please follow the instructions in the [bui ## Documentation The general GPAC framework documentation is available on [wiki.gpac.io](https://wiki.gpac.io), including [HowTos](https://github.com/gpac/gpac/wiki/Howtos). -GPAC tools are mostly wrappers around an underlying library called libgpac which can easily be embedded in your projects. The libgpac developer documentation is available at [doxygen.gpac.io](https://doxygen.gpac.io), including documentation of [JS APIs](https://doxygen.gpac.io/group__jsapi__grp.html). +GPAC tools are mostly wrappers around an underlying library called libgpac which can easily be embedded in your projects. The libgpac developer documentation is available at [doxygen.gpac.io](https://doxygen.gpac.io), including documentation of [JS APIs](https://doxygen.gpac.io/group__jsapi__grp.html), [Python APIs](https://doxygen.gpac.io/group__pyapi__grp.html) and [NodeJS APIs](https://doxygen.gpac.io/group__nodejs__grp.html). ## Testing -GPAC has a test suite exercicing most features of the framework. The test suite is in a separate repository [https://github.com/gpac/testsuite/](https://github.com/gpac/testsuite/), but is available as a submodule of the GPAC main repository. To initialize the testsuite submodule, do `git submodule update --init`. +GPAC has a test suite exercising most features of the framework. The test suite is in a separate repository [https://github.com/gpac/testsuite/](https://github.com/gpac/testsuite/), but is available as a submodule of the GPAC main repository. To initialize the testsuite submodule, do `git submodule update --init`. For more details on the test suite, read [this page](https://github.com/gpac/gpac/wiki/GPAC_tests) and check the [testsuite readme](https://github.com/gpac/testsuite). Per-commit [build](https://buildbot.gpac.io/) and [tests results](https://tests.gpac.io) are available. -## Support +## Support, ongoing tasks and bugs + Please use [github](https://github.com/gpac/gpac/issues) for feature requests and bug reports. When filing a request there, please tag it as _feature-request_. ## Contributing A complex project like GPAC wouldn’t exist and persist without the support of its community. Please contribute: a nice message, supporting us in our communication, reporting issues when you see them… any gesture, even the smallest ones, counts. -If you use GPAC in your published research, ! _please cite_ ! using -- [this paper](https://dl.acm.org/doi/abs/10.1145/3339825.3394929) for recent versions (0.9 or above) -- [this paper](https://dl.acm.org/doi/abs/10.1145/1291233.1291452) for legacy versions (0.8 or below). - -If you want to contribute to GPAC, you can find ideas at [GSoC page](https://gpac.wp.imt.fr/jobs/google-summer-of-code-ideas/) or look for ‘good first issue’ on [github](https://github.com/gpac/gpac/issues). In any doubt please feel free to [contact us](mailto:contact@gpac.io). +If you want to contribute to GPAC, you can find ideas at [GSoC page](https://gpac.wp.imt.fr/jobs/google-summer-of-code-ideas/) or look for a [good first issue](https://github.com/gpac/gpac/labels/good%20first%20issue). In any doubt please feel free to [contact us](mailto:contact@gpac.io). # Team GPAC is brought to you by an experienced team of developers with a wide track-record on media processing. -The project is mainly developed at [Telecom Paris](https://www.telecom-paris.fr/), in the [MultiMedia group](http://www.tsi.telecom-paristech.fr/mm/), with the help of many [great contributors](https://github.com/gpac/gpac/graphs/contributors) +The project is mainly developed in the MultiMedia group of [Telecom Paris](https://www.telecom-paris.fr/) with the help of many [great contributors](https://github.com/gpac/gpac/graphs/contributors). GPAC has a peculiar story: started as a startup in NYC, GPAC gained traction from research and a nascent multimedia community as it was open-sourced in 2003. Since then we have never stopped transforming GPAC into a useful and up-to-date project, with many industrial R&D collaborations and a community of tens of thousands of users. This makes GPAC one of the few open-source multimedia projects that gathers so much diversity. @@ -118,17 +120,15 @@ GPAC has a peculiar story: started as a startup in NYC, GPAC gained traction fro # Roadmap Users are encouraged to use the latest tag or the master branch. -The previous v0.8.X release (the last one using the legacy architecture) is LTS until 30/06/2021. Important bug fixes will be backported but new features won’t. API compatibility between both versions should make the migration easy. If not please [file a bug](https://github.com/gpac/gpac/issues). +The v0.8.X release (the last one using the legacy architecture) is officially deprecated. -## Ongoing tasks and bugs -Please use [github](https://github.com/gpac/gpac/issues) for feature requests and bug reports. When filing a request there, please tag it as feature-request. - -## V1.1.0 +## V2.X Targets: -- [ ] add kvazaar/other encoders support? -- [ ] improve remotery support -- [ ] more JS filters -- [ ] filters scriptable through other languages (python) ? -- [ ] move input sensors to filter ? -- [ ] fixed features disabled during rearchitecture or drop them (FILTER_FIXME macro) -- [ ] move Android client to filters +- [ ] drop MP4Client and GF_Terminal API +- [ ] User authentication for HTTP and RTSP servers +- [ ] DASH event support +- [ ] Web integration (emscripten, Remotery UI) +- [ ] GUI cleanup ? + + + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..be18292 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## Email Contact + +security@gpac.io + +## Supported Versions + +GPAC is under constant development using a continuous integration and deployment process. As a consequence the `HEAD` of the `master` branch is always considered as the _current version_ at any point. + +Thus only reports that are confirmed reproducible on the current `HEAD` of the `master` branch will receive a patch. + + +## Reporting a Vulnerability + +Vulnerabilities (as well as other bugs) should be reported directly using the [Github issue trakcer](https://github.com/gpac/gpac/issues). + +Please include all information needed to reproduce the issue, including a sample file. + +Sample files can be joined directly via github (preferred way) or uploaded to the [GPAC file drop](https://www.mediafire.com/filedrop/filedrop_hosted.php?drop=eec9e058a9486fe4e99c33021481d9e1826ca9dbc242a6cfaab0fe95da5e5d95). + +However if public disclosure seems unreasonable, or if confidential information needs to be shared, you can contact security@gpac.io for private disclosure. diff --git a/applications/Makefile b/applications/Makefile index 935e231..195d362 100644 --- a/applications/Makefile +++ b/applications/Makefile @@ -2,7 +2,7 @@ include ../config.mak APPDIRS=gpac -ifeq ($(MP4BOX_STATIC),yes) +ifeq ($(STATIC_BINARY),yes) APPDIRS+=mp4box else @@ -30,7 +30,7 @@ ifeq ($(USE_WXWIDGETS),yes) #INSTDIRS+=osmo4_wx endif -#MP4BOX_STATIC +#STATIC_BINARY endif ALLDIRS=$(APPDIRS) diff --git a/applications/generators/MPEG4/main.c b/applications/generators/MPEG4/main.c index ef7ab5f..390bdd5 100644 --- a/applications/generators/MPEG4/main.c +++ b/applications/generators/MPEG4/main.c @@ -128,7 +128,7 @@ u32 GetNextToken(char *token, char *sep) if (*CurrentLine == '\n') return 0; } - //copy token untill next blank + //copy token until next blank i=0; while (1) { //bad line diff --git a/applications/generators/MPEG4/templates5.txt b/applications/generators/MPEG4/templates5.txt index 21bbdd2..3d626c0 100644 --- a/applications/generators/MPEG4/templates5.txt +++ b/applications/generators/MPEG4/templates5.txt @@ -406,8 +406,8 @@ exposedField SFBool solid FALSE ]{} PROTO SBBone [ #%NDT=SFWorldNode,SF2DNode,SF3DNode,SFSBBoneNode %COD=N -eventIn SF3DNode addChildren -eventIn SF3DNode removeChildren +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren exposedField SFInt32 boneID 0 #%b=[0,1023] #%q=13 10 exposedField SFVec3f center 0 0 0 #%q=1 #%a=1 exposedField MF3DNode children [] diff --git a/applications/generators/MPEG4/templates9.txt b/applications/generators/MPEG4/templates9.txt index 16f86b4..a88813b 100644 --- a/applications/generators/MPEG4/templates9.txt +++ b/applications/generators/MPEG4/templates9.txt @@ -58,8 +58,8 @@ exposedField MFGeometryNode FacadeCellsArray [] PROTO Shadow [#%NDT=SFWorldNode,SF3DNode,SFGeometryNode %COD=N -eventIn SF3DNode addChildren -eventIn SF3DNode removeChildren +eventIn MF3DNode addChildren +eventIn MF3DNode removeChildren exposedField MF3DNode children [] exposedField SFBool enabled TRUE exposedField SFBool cast TRUE diff --git a/applications/generators/SVG/main.c b/applications/generators/SVG/main.c index acc0725..1db4d83 100644 --- a/applications/generators/SVG/main.c +++ b/applications/generators/SVG/main.c @@ -557,7 +557,7 @@ void setAttributeType(SVGGenAttribute *att) *tmp='_'; tmp++; } - tmp = att->impl_type;; + tmp = att->impl_type; if ( (tmp = strstr(tmp, "datatype")) ) { tmp--; *tmp = 0; diff --git a/applications/generators/X3D/main.c b/applications/generators/X3D/main.c index 0e788a8..5abda6c 100644 --- a/applications/generators/X3D/main.c +++ b/applications/generators/X3D/main.c @@ -102,7 +102,7 @@ u32 GetNextToken(char *token, char *sep) if (*CurrentLine == '\n') return 0; } - //copy token untill next blank + //copy token until next blank i=0; while (1) { //bad line diff --git a/applications/gpac/Makefile b/applications/gpac/Makefile index a1bb8db..2e60896 100644 --- a/applications/gpac/Makefile +++ b/applications/gpac/Makefile @@ -45,6 +45,11 @@ OBJS= main.o SRCS := $(OBJS:.o=.c) +ifeq ($(CONFIG_WIN32),yes) +OBJS+=$(SRC_PATH)/manifest.o +endif + + all: $(PROG) $(PROG): $(OBJS) diff --git a/applications/gpac/main.c b/applications/gpac/main.c index 936b1b1..d9eb0e0 100644 --- a/applications/gpac/main.c +++ b/applications/gpac/main.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2017-2020 + * Copyright (c) Telecom ParisTech 2017-2022 * All rights reserved * * This file is part of GPAC / gpac application @@ -25,34 +25,41 @@ #include #include +#include static GF_SystemRTInfo rti; static GF_FilterSession *session=NULL; static u32 list_filters = 0; static Bool dump_stats = GF_FALSE; static Bool dump_graph = GF_FALSE; -static Bool print_filter_info = GF_FALSE; +static u32 print_filter_info = 0; static Bool print_meta_filters = GF_FALSE; static Bool load_test_filters = GF_FALSE; static s32 nb_loops = 0; static s32 runfor = 0; -Bool runfor_exit = GF_FALSE; -Bool enable_prompt = GF_FALSE; -u32 enable_reports = 0; -char *report_filter = NULL; -Bool do_unit_tests = GF_FALSE; +static Bool runfor_exit = GF_FALSE; +static u32 exit_mode = 0; +static Bool enable_prompt = GF_FALSE; +static u32 enable_reports = 0; +static char *report_filter = NULL; +static Bool do_unit_tests = GF_FALSE; +static Bool use_step_mode = GF_FALSE; static int alias_argc = 0; static char **alias_argv = NULL; static GF_List *args_used = NULL; static GF_List *args_alloc = NULL; static u32 gen_doc = 0; static u32 help_flags = 0; +static u32 loops_done = 0; //coverage for FileIO static const char *make_fileio(const char *inargs, const char **out_arg, Bool is_input, GF_Err *e); static void cleanup_file_io(); -FILE *sidebar_md=NULL; +//coverage for custom filters +static GF_Filter *load_custom_filter(GF_FilterSession *sess, char *opts, GF_Err *e); + +static FILE *sidebar_md=NULL; static FILE *helpout = NULL; static const char *auto_gen_md_warning = "\n"; @@ -67,8 +74,9 @@ static char separator_set[7] = GF_FS_DEFAULT_SEPS; #define SEP_LIST 3 static Bool print_filters(int argc, char **argv, GF_FilterSession *session, GF_SysArgMode argmode); -static void dump_all_props(void); +static void dump_all_props(char *pname); static void dump_all_colors(void); +static void dump_all_audio_cicp(void); static void dump_all_codec(GF_FilterSession *session); static void write_filters_options(GF_FilterSession *fsess); static void write_core_options(); @@ -85,66 +93,63 @@ static Bool revert_cache_file(void *cbck, char *item_name, char *item_path, GF_F const char *gpac_doc = "# General\n" "Filters are configurable processing units consuming and producing data packets. These packets are carried " -"between filters through a data channel called __pid__. A PID is in charge of allocating/tracking data packets, " +"between filters through a data channel called __PID__. A PID is in charge of allocating/tracking data packets, " "and passing the packets to the destination filter(s). A filter output PID may be connected to zero or more filters. " "This fan-out is handled internally by GPAC (no such thing as a tee filter in GPAC).\n" "Note: When a PID cannot be connected to any filter, a warning is thrown and all packets dispatched on " "this PID will be destroyed. The session may however still run, unless [-full-link](CORE) is set.\n" -" \nEach output PID carries a set of properties describing the data it delivers (eg __width__, __height__, __codec__, ...). Properties " -"can be built-in (identified by a 4 character code **abcd**, see [properties (-h props)](filters_properties) ), or user-defined (identified by a string). Each PID tracks " +" \nEach output PID carries a set of properties describing the data it delivers (e.g. __width__, __height__, __codec__, ...). Properties " +"can be built-in (see [gpac -h props](filters_properties) ), or user-defined. Each PID tracks " "its properties changes and triggers filter reconfiguration during packet processing. This allows the filter chain to be " -"reconfigured at run time, potentially reloading part of the chain (eg unload a video decoder when switching from compressed " +"reconfigured at run time, potentially reloading part of the chain (e.g. unload a video decoder when switching from compressed " "to uncompressed sources).\n" -" \nEach filter exposes one or more sets of capabilities, called __capability bundle__, which are property type and values " -"that must be matched or excluded by connecting PIDs.\n" -" \nEach filter exposes a set of argument to configure itself, using property types and values described as strings formated with " +" \nEach filter exposes a set of argument to configure itself, using property types and values described as strings formatted with " "separators. This help is given with default separator sets `:=#,@` to specify filters, properties and options. Use [-seps](GPAC) to change them.\n" -"# Property format\n" -"- boolean: formatted as `yes`|`true`|`1` or `no`|`false`|`0`\n" +"# Property and filter option format\n" +"- boolean: formatted as `yes`,`true`,`1` or `no`,`false`,`0`\n" "- enumeration (for filter arguments only): must use the syntax given in the argument description, otherwise value `0` (first in enum) is assumed.\n" -"- 1-dimension (numbers, floats, ints...): formatted as `value[unit]`, where `unit` can be `k`|`K` (x1000) or `m`|`M` (x1000000) or `g`|`G` (x1000000000). " -"For such properties, value `+I` means maximum possible value, `-I` minimum possible value.\n" +"- 1-dimension (numbers, floats, ints...): formatted as `value[unit]`, where `unit` can be `k`,`K` (x 1000) or `m`,`M` (x 1000000) or `g`,`G` (x 1000000000) or `sec` (x 1000) or `min` (x 60000). `+I` means max float/int/uint value, `-I` min float/int/uint value.\n" "- fraction: formatted as `num/den` or `num-den` or `num`, in which case the denominator is 1 if `num` is an integer, or 1000000 if `num` is a floating-point value.\n" -"- unsigned 32 bit integer: formated as number or hexadecimal using the format `0xAABBCCDD`.\n" +"- unsigned 32 bit integer: formatted as number or hexadecimal using the format `0xAABBCCDD`.\n" "- N-dimension (vectors): formatted as `DIM1xDIM2[xDIM3[xDIM4]]` values, without unit multiplier.\n" "- string: formatted as:\n" -" - `value`: copies value to string.\n" -" - `file@FILE`: load string from local `FILE` (opened in binary mode).\n" -" - `bxml@FILE`: binarize XML from local `FILE` and set property type to data - see https://wiki.gpac.io/NHML-Format.\n" +" - `value`: copies value to string.\n" +" - `file@FILE`: load string from local `FILE` (opened in binary mode).\n" +" - `bxml@FILE`: binarize XML from local `FILE` and set property type to data - see https://wiki.gpac.io/NHML-Format.\n" "- data: formatted as:\n" -" - `size@address`: constant data block, not internally copied; `size` gives the size of the block, `address` the data pointer.\n" -" - `0xBYTESTRING`: data block specified in hexadecimal, internally copied.\n" -" - `file@FILE`: load data from local `FILE` (opened in binary mode).\n" -" - `bxml@FILE`: binarize XML from local `FILE` - see https://wiki.gpac.io/NHML-Format.\n" -"- pointer: are formatted as `address` giving the pointer address (32 or 64 bit depending on platforms).\n" +" - `size@address`: constant data block, not internally copied; `size` gives the size of the block, `address` the data pointer.\n" +" - `0xBYTESTRING`: data block specified in hexadecimal, internally copied.\n" +" - `file@FILE`: load data from local `FILE` (opened in binary mode).\n" +" - `bxml@FILE`: binarize XML from local `FILE` - see https://wiki.gpac.io/NHML-Format.\n" +" - `b64@DATA`: load data from base-64 encoded `DATA`.\n" +"- pointer: pointer address as formatted by `%p` in C.\n" "- string lists: formatted as `val1,val2[,...]`. Each value can also use `file@FILE` syntax.\n" "- integer lists: formatted as `val1,val2[,...]`\n" "Note: The special characters in property formats (0x,/,-,+I,-I,x) cannot be configured.\n" "# Filter declaration [__FILTER__]\n" "## Generic declaration\n" "Each filter is declared by its name, with optional filter arguments appended as a list of colon-separated `name=value` pairs. Additional syntax is provided for:\n" -"- boolean: `value` can be omitted, defaulting to `true` (eg `:noedit`). Using `!` before the name negates the result (eg `:!moof_first`)\n" -"- enumerations: name can be omitted (eg `:disp=pbo` is equivalent to `:pbo`), provided that filter developers pay attention to not reuse enumeration names in the same filter.\n" +"- boolean: `value` can be omitted, defaulting to `true` (e.g. `:noedit`). Using `!` before the name negates the result (e.g. `:!moof_first`)\n" +"- enumerations: name can be omitted, e.g. `:disp=pbo` is equivalent to `:pbo`.\n" "\n \n" -"When string parameters are used (eg URLs), it is recommended to escape the string using the keyword `gpac`. \n" +"When string parameters are used (e.g. URLs), it is recommended to escape the string using the keyword `gpac`. \n" "EX filter:ARG=http://foo/bar?yes:gpac:opt=VAL\n" "This will properly extract the URL.\n" "EX filter:ARG=http://foo/bar?yes:opt=VAL\n" "This will fail to extract it and keep `:opt=VAL` as part of the URL.\n" "The escape mechanism is not needed for local source, for which file existence is probed during argument parsing. " -"It is also not needed for builtin procotol handlers (`avin://`, `video://`, `audio://`, `pipe://`)\n" +"It is also not needed for builtin protocol handlers (`avin://`, `video://`, `audio://`, `pipe://`)\n" "For `tcp://` and `udp://` protocols, the escape is not needed if a trailing `/` is appended after the port number.\n" "EX -i tcp://127.0.0.1:1234:OPT\n" "This will fail to extract the URL and options.\n" "EX -i tcp://127.0.0.1:1234/:OPT\n" "This will extract the URL and options.\n" -"Note: one trick to avoid the escape sequence is to declare the URLs option at the end, eg `f1:opt1=foo:url=http://bar`, provided you have only one URL parameter to specify on the filter.\n" +"Note: one trick to avoid the escape sequence is to declare the URLs option at the end, e.g. `f1:opt1=foo:url=http://bar`, provided you have only one URL parameter to specify on the filter.\n" "\n" -"It is possible to disable option parsing (for string options) by duplicating the seperator.\n" +"It is possible to disable option parsing (for string options) by duplicating the separator.\n" "EX filter::opt1=UDP://IP:PORT/:someopt=VAL::opt2=VAL2\n" "This will pass `UDP://IP:PORT/:someopt=VAL` to `opt1` without inspecting it, and `VAL2` to `opt2`.\n" " \n" -"A filter may be assigned a name (for inspection purposes) using `:N=name` option. This name is not used in link resolution and may be changed at runtime by the filter instance.\n" "## Source and Sink filters\n" "Source and sink filters do not need to be addressed by the filter name, specifying `src=` or `dst=` instead is enough. " "You can also use the syntax `-src URL` or `-i URL` for sources and `-dst URL` or `-o URL` for destination, this allows prompt completion in shells.\n" @@ -156,6 +161,7 @@ const char *gpac_doc = "Specific source or sink filters may also be specified using `filterName:src=URL` or `filterName:dst=URL`.\n" "\n" "The `src=` and `dst=` syntaxes can also be used in alias for dynamic argument cloning (see `gpac -hx alias`).\n" +"\n" "## Forcing specific filters\n" "There is a special option called `gfreg` which allows specifying preferred filters to use when handling URLs.\n" "EX src=file.mp4:gfreg=ffdmx,ffdec\n" @@ -164,24 +170,28 @@ const char *gpac_doc = "## Specifying encoders and decoders\n" "By default filters chain will be resolved without any decoding/encoding if the destination accepts the desired format. " "Otherwise, decoders/encoders will be dynamically loaded to perform the conversion, unless dynamic resolution is disabled. " -"There is a special shorcut filter name for encoders `enc` allowing to match a filter providing the desired encoding. " +"There is a special shortcut filter name for encoders `enc` allowing to match a filter providing the desired encoding. " "The parameters for `enc` are:\n" -"- c=NAME: identifes the desired codec. `NAME` can be the gpac codec name or the encoder instance for ffmpeg/others\n" +"- c=NAME: identifies the desired codec. `NAME` can be the GPAC codec name or the encoder instance for ffmpeg/others\n" "- b=UINT, rate=UINT, bitrate=UINT: indicates the bitrate in bits per second\n" "- g=UINT, gop=UINT: indicates the GOP size in frames\n" "- pfmt=NAME: indicates the target pixel format name (see [properties (-h props)](filters_properties) ) of the source, if supported by codec\n" "- all_intra=BOOL: indicates all frames should be intra frames, if supported by codec\n" -"\n \nOther options will be passed to the filter if it accepts generic argument parsing (as is the case for ffmpeg).\n" -"EX src=dump.yuv:size=320x240:fps=25 enc:c=avc:b=150000:g=50:cgop=true:fast=true dst=raw.264\n" +"\n" +"Other options will be passed to the filter if it accepts generic argument parsing (as is the case for ffmpeg).\n" +"The shortcut syntax `c=TYPE` (e.g. `c=aac:opts`) is also supported.\n" +"\n" +"EX gpac -i dump.yuv:size=320x240:fps=25 enc:c=avc:b=150000:g=50:cgop=true:fast=true -o raw.264\n" "This creates a 25 fps AVC at 175kbps with a gop duration of 2 seconds, using closed gop and fast encoding settings for ffmpeg.\n" "\n" "The inverse operation (forcing a decode to happen) is possible using the __reframer__ filter.\n" -"EX src=file.mp4 reframer:raw @ -o null\n" +"EX gpac -i file.mp4 reframer:raw=av -o null\n" "This will force decoding media from `file.mp4` and trash (send to `null`) the result (doing a decoder benchmark for example).\n" "\n" +"## Escaping option separators\n" "When a filter uses an option defined as a string using the same separator character as gpac, you can either " -"modify the set of separators, or escape the seperator by duplicating it. The options enclosed by duplicated " -"separator are not parsed. This is mostly used for meta filters, such as ffmpeg, to pass options to subfilters " +"modify the set of separators, or escape the separator by duplicating it. The options enclosed by duplicated " +"separator are not parsed. This is mostly used for meta filters, such as ffmpeg, to pass options to sub-filters " "such as libx264 (cf `x264opts` parameter).\n" "EX f:a=foo:b=bar\n" "This will set option `a` to `foo` and option `b` to `bar` on the filter.\n" @@ -189,42 +199,99 @@ const char *gpac_doc = "This will set option `a` to `foo:b=bar` on the filter.\n" "EX f:a=foo::b=bar:c::d=fun\n" "This will set option `a` to `foo`, `b` to `bar:c` and the option `d` to `fun` on the filter.\n" -"# Expliciting links between filters [__LINK__]\n" +"\n" +"# Filter linking [__LINK__]\n" +"\n" +"Each filter exposes one or more sets of capabilities, called __capability bundle__, which are property type and values " +"that must be matched or excluded by connecting PIDs.\n" +"To check the possible sources and destination for a filter `FNAME`, use `gpac -h links FNAME`\n" +"\n" +"The filter graph resolver uses this information together with the PID properties to link the different filters.\n" +"\n" +"Link directives, when provided, specify which source a filter can accept connections from.\n" +"__They do not specify which destination a filter can connect to.__\n" +"\n" +"## Default filter linking\n" +"When no link instructions are given (see below), the default linking strategy used is either __implicit mode__ (default in `gpac`) or __complete mode__ (if [-cl](GPAC) is set).\n" +"Each PID is checked for possible connection to all defined filters, in their declaration order.\n" +"For each filter `DST` accepting a connection from the PID, directly or with intermediate filters:\n" +"- if `DST` filter has link directives, use them to allow or reject PID connection.\n" +"- otherwise, if __complete mode__ is enabled, allow connection.\n" +"- otherwise (__implicit mode__):\n" +" - if `DST` is not a sink and is the first matching filter with no link directive, allow connection.\n" +" - otherwise, if `DST` is not a sink and is not the first matching filter with no link directive, reject connection.\n" +" - otherwise (`DST` is a sink) and no previous connections to a non-sink filter, allow connection.\n" +"\n" +"EX gpac -i file.mp4 c=avc -o output\n" +"With this setup in __implicit mode__:\n" +"- if the file has a video PID, it will connect to `enc` but not to `output`. The output PID of `enc` will connect to `output`.\n" +"- if the file has other PIDs than video, they will connect to `output`, since this `enc` filter accepts only video.\n" +"\n" +"EX gpac -cl -i file.mp4 c=avc -o output\n" +"With this setup in __complete mode__:\n" +"- if the file has a video PID, it will connect both to `enc` and to `output`, and the output PID of `enc` will connect to `output`.\n" +"- if the file has other PIDs than video, they will connect to `output`.\n" +"\n" +"Furthermore in __implicit mode__, filter connections are restricted to filters defined between the last source and the sink(s).\n" +"EX gpac -i video1 reframer:saps=1 -i video2 ffsws:osize=128x72 -o output\n" +"This will connect:\n" +"- `video1` to `reframer` then `reframer` to `output` but will prevent `reframer` to `ffsws` connection.\n" +"- `video2` to `ffsws` then `ffsws` to `output` but will prevent `video2` to `reframer` connection.\n" +"\n" +"EX gpac -i video1 -i video2 reframer:saps=1 ffsws:osize=128x72 -o output\n" +"This will connect `video1` AND `video2` to `reframer->ffsws->output`\n" +"\n" +"The __implicit mode__ allows specifying linear processing chains (no PID fan-out except for final output(s)) without link directives, simplifying command lines for common cases.\n" +"Warning: Argument order really matters in implicit mode!\n" +"\n" +"EX gpac -i file.mp4 c=avc c=aac -o output\n" +"If the file has a video PID, it will connect to `c=avc` but not to `output`. The output PID of `c=avc` will connect to `output`.\n" +"If the file has an audio PID, it will connect to `c=aac` but not to `output`. The output PID of `c=aac` will connect to `output`.\n" +"If the file has other PIDs than audio or video, they will connect to `output`.\n" +"\n" +"EX gpac -i file.mp4 ffswf=osize:128x72 c=avc resample=osr=48k c=aac -o output\n" +"This will force:\n" +"- `SRC(video)->ffsws->enc(video)->output` and prevent `SRC(video)->output`, `SRC(video)->enc(video)` and `ffsws->output` connections which would happen in __complete mode__.\n" +"- `SRC(audio)->resample->enc(audio)->output` and prevent `SRC(audio)->output`, `SRC(audio)->enc(audio)` and `resample->output` connections which would happen in __complete mode__.\n" +"\n" "## Quick links\n" -"Link between filters may be manually specified. The syntax is an `@` character optionaly followed by an integer (0 if omitted). " -"This indicates which filter previously specified at prompt should be link to the next filter listed. The optional integer is a 0-based index to the previous filter declarations, 0 indicating the previous filter declaration, 1 the one before the previous delaration, ...).\n" -"Only the last link directive occuring before a filter is used to setup links for that filter.\n" +"Link between filters may be manually specified. The syntax is an `@` character optionally followed by an integer (0 if omitted).\n" +"This indicates that the following filter specified at prompt should be linked only to a previous listed filter.\n" +"The optional integer is a 0-based index to the previous filter declarations, 0 indicating the previous filter declaration, 1 the one before the previous declaration, ...).\n" +"If `@@` is used instead of `@`, the optional integer gives the filter index starting from the first filter (index 0) specified in command line.\n" +"Several link directives can be given for a filter.\n" "EX fA fB @1 fC\n" -"This indicates to direct `fA` outputs to `fC`.\n" -"EX fA fB @1 @0 fC\n" -"This indicates to direct `fB` outputs to `fC`, `@1` is ignored.\n" -"\nIf no link directives are given, the links will be dynamically solved to fullfill as many connections as possible (__see below__).\n" -"Warning: This means that `fA fB fC` and `fA fB @ fC` will likely not give the same result.\n" +"This indicates that `fC` only accepts inputs from `fA`.\n" +"EX fA fB fC @1 @0 fD\n" +"This indicates that `fD` only accepts inputs from `fB` and `fC`.\n" +"EX fA fB fC ... @@1 fZ\n" +"This indicates that `fZ` only accepts inputs from `fB`.\n" "\n" "## Complex links\n" -"The link directive is just a quick shortcut to set the following arguments:\n" -"- FID=name, which assigns an identifier to the filter\n" -"- SID=name1[,name2...], which set a list of filter identifiers , or __sourceIDs__, restricting the list of possible inputs for a filter.\n" +"The `@` link directive is just a quick shortcut to set the following filter arguments:\n" +"- FID=name: assigns an identifier to the filter\n" +"- SID=name1[,name2...]: sets a list of filter identifiers, or __sourceIDs__, restricting the list of possible inputs for a filter.\n" "\n" "EX fA fB @1 fC\n" "This is equivalent to `fA:FID=1 fB fC:SID=1`.\n" -"Link directives specify which source a filter can accept connections from. They do not specifiy which destination a filter can connect to.\n" "EX fA:FID=1 fB fC:SID=1\n" -"This indicates that `fC` only accpets input from `fA`, but `fB` might accept inputs from `fA`.\n" +"This indicates that `fC` only accepts input from `fA`, but `fB` might accept inputs from `fA`.\n" "EX fA:FID=1 fB:FID=2 fC:SID=1 fD:SID=1,2\n" "This indicates that `fD` only accepts input from `fA` and `fB` and `fC` only from `fA`\n" "Note: A filter with sourceID set cannot get input from filters with no IDs.\n" +"\n" "A sourceID name can be further extended using fragment identifier (`#` by default):\n" "- name#PIDNAME: accepts only PID(s) with name `PIDNAME`\n" "- name#TYPE: accepts only PIDs of matching media type. TYPE can be `audio`, `video`, `scene`, `text`, `font`, `meta`\n" -"- name#TYPEN: accepts only `N`th PID of matching type from source\n" -"- name#P4CC=VAL: accepts only PIDs with property matching `VAL`.\n" +"- name#TYPEN: accepts only `N` (1-based index) PID of matching type from source (e.g. `video2` to only accept second video PID)\n" +"- name#TAG=VAL: accepts the PID if its parent filter has no tag or a tag matching `VAL`\n" +"- name#P4CC=VAL: accepts only PIDs with builtin property of type `P4CC` and value `VAL`.\n" "- name#PName=VAL: same as above, using the builtin name corresponding to the property.\n" "- name#AnyName=VAL: same as above, using the name of a non built-in property.\n" "- name#Name=OtherPropName: compares the value with the value of another property of the PID. The matching will fail if the value to compare to is not present or different from the value to check. The property to compare with shall be a built-in property.\n" "If the property is not defined on the PID, the property is matched. Otherwise, its value is checked against the given value.\n" "\n" -"The following modifiers for comparisons are allowed (for both `P4CC=`, `PName=` and `AnyName=`):\n" +"The following modifiers for comparisons are allowed (for any fragment format using `=`):\n" "- name#P4CC=!VAL: accepts only PIDs with property NOT matching `VAL`.\n" "- name#P4CC-VAL: accepts only PIDs with property strictly less than `VAL` (only for 1-dimension number properties).\n" "- name#P4CC+VAL: accepts only PIDs with property strictly greater than `VAL` (only for 1-dimension number properties).\n" @@ -235,99 +302,146 @@ const char *gpac_doc = "This indicates to match connection between `fA` and `fB` only for PIDs with a `ServiceID` property of `2`.\n" "These extensions also work with the __LINK__ `@` shortcut.\n" "EX fA fB @1#video fC\n" -"This indicates to direct `fA` video outputs to `fC`.\n" -"EX src=img.heif @#ItemID=200 vout\n" +"This indicates that `fC` only accepts inputs from `fA`, and of type video.\n" +"EX gpac -i img.heif @#ItemID=200 vout\n" "This indicates to connect to `vout` only PIDs with `ItemID` property equal to `200`.\n" -"EX src=vid.mp4 @#PID=1 vout\n" +"EX gpac -i vid.mp4 @#PID=1 vout\n" "This indicates to connect to `vout` only PIDs with `ID` property equal to `1`.\n" -"EX src=vid.mp4 @#Width=640 vout\n" +"EX gpac -i vid.mp4 @#Width=640 vout\n" "This indicates to connect to `vout` only PIDs with `Width` property equal to `640`.\n" -"EX src=vid.mp4 @#Width-640 vout\n" +"EX gpac -i vid.mp4 @#Width-640 vout\n" "This indicates to connect to `vout` only PIDs with `Width` property less than `640`\n" -"EX src=vid.mp4 @#ID=ItemID#ItemNumber=1 vout\n" +"EX gpac -i vid.mp4 @#ID=ItemID#ItemNumber=1 vout\n" "This will connect to `vout` only PID with an ID property equal to ItemID property (keep items, discard tracks) and an Item number of 1 (first item).\n" "\n" "Multiple fragment can be specified to check for multiple PID properties.\n" -"EX src=vid.mp4 @#Width=640#Height+380 vout\n" +"EX gpac -i vid.mp4 @#Width=640#Height+380 vout\n" "This indicates to connect to `vout` only PIDs with `Width` property equal to `640` and `Height` greater than `380`.\n" "\n" -"Warning: If a filter PID gets connected to a loaded filter, no further dynamic link resolution will " -"be done to connect it to other filters, unless sourceIDs are set. Link directives should be carfully setup.\n" -"EX src=file.mp4 @ reframer dst=dump.mp4\n" -"This will link src `file.mp4` PID (type __file__) to dst `dump.mp4`filter (type `file`) because dst has no sourceID and therefore will " -"accept input from src. Since the PID is connected, the filter engine will not try to solve " -"a link between src and `reframer`. The result is a direct copy of the source file, `reframer` being unused.\n" -"EX src=file.mp4 reframer @ dst=dump.mp4\n" -"This will force dst to accept only from reframer, a muxer will be loaded to solve this link, and " -"src PID will be linked to `reframer` (no source ID), loading a demuxer to solve the link. The result is a complete remux of the source file.\n" +"Warning: If a PID directly connects to one or more explicitly loaded filters, no further dynamic link resolution will " +"be done to connect it to other filters with no sourceID set. Link directives should be carefully setup.\n" +"EX fA @ reframer fB\n" +"If `fB` accepts inputs provided by `fA` but `reframer` does not, this will link `fA` PID to `fB` filter since `fB` has no sourceID.\n" +"Since the PID is connected, the filter engine will not try to solve a link between `fA` and `reframer`.\n" +"\n" +"An exception is made for local files: by default, a local file destination will force a remultiplex of input PIDs from a local file.\n" +"EX gpac -i file.mp4 -o dump.mp4\n" +"This will prevent direct connection of PID of type `file` to dst `file.mp4`, remultiplexing the file.\n" +"\n" +"The special option `nomux` is used to allow direct connections (ignored for non-sink filters).\n" +"EX gpac -i file.mp4 -o dump.mp4:nomux\n" +"This will result in a direct file copy.\n" +"\n" +"This only applies to local files destination. For pipes, sockets or other file outputs (HTTP, ROUTE):\n" +"- direct copy is enabled by default\n" +"- `nomux=0` can be used to force remultiplex\n" +"\n" +"## Sub-session tagging\n" +"Filters may be assigned to a sub-session using `:FS=N`, with `N` a positive integer.\n" +"Filters belonging to different sub-sessions may only link to each-other:\n" +"- if explicitly allowed through sourceID directives (`@` or `SID`)\n" +"- or if they have the same sub-session identifier\n" +"\n" +"This is mostly used for __implicit mode__ in `gpac`: each first source filter specified after a sink filter will trigger a new sub-session.\n" +"EX gpac -i in1.mp4 -i in2.mp4 -o out1.mp4 -o out2.mp4\n" +"This will result in both inputs multiplexed in both outputs.\n" +"EX gpac -i in1.mp4 -o out1.mp4 -i in2.mp4 -o out2.mp4\n" +"This will result in in1 mixed to out1 and in2 mixed to out2, these last two filters belonging to a different sub-session.\n" +"\n" "# Arguments inheriting\n" "Unless explicitly disabled (see [-max-chain](CORE)), the filter engine will resolve implicit or explicit (__LINK__) connections " "between filters and will allocate any filter chain required to connect the filters. " "In doing so, it loads new filters with arguments inherited from both the source and the destination.\n" -"EX src=file.mp4:OPT dst=file.aac dst=file.264\n" +"EX gpac -i file.mp4:OPT -o file.aac -o file.264\n" "This will pass the `:OPT` to all filters loaded between the source and the two destinations.\n" -"EX src=file.mp4 dst=file.aac:OPT dst=file.264\n" +"EX gpac -i file.mp4 -o file.aac:OPT -o file.264\n" "This will pass the `:OPT` to all filters loaded between the source and the file.aac destination.\n" "Note: the destination arguments inherited are the arguments placed **AFTER** the `dst=` option.\n" -"EX src=file.mp4 fout:OPTFOO:dst=file.aac:OPTBAR\n" +"EX gpac -i file.mp4 fout:OPTFOO:dst=file.aac:OPTBAR\n" "This will pass the `:OPTBAR` to all filters loaded between `file.mp4` source and `file.aac` destination, but not `OPTFOO`.\n" "Arguments inheriting can be stopped by using the keyword `gfloc`: arguments after the keyword will not be inherited.\n" -"EX src=file.mp4 dst=file.aac:OPTFOO:gfloc:OPTBAR dst=file.264\n" -"This will pass the `:OPTFOO` to all filters loaded between `file.mp4`source and `file.aac` destination, but not `OPTBAR`\n" +"EX gpac -i file.mp4 -o file.aac:OPTFOO:gfloc:OPTBAR -o file.264\n" +"This will pass `:OPTFOO` to all filters loaded between `file.mp4` source and `file.aac` destination, but not `OPTBAR`\n" "Arguments are by default tracked to check if they were used by the filter chain, and a warning is thrown if this is not the case.\n" -"It may be usefull to specify arguments which may not be consumed depending on the graph resolution; the specific keyword `gfopt` indicates that arguments after the keyword will not be tracked.\n" -"EX src=file.mp4 dst=file.aac:OPTFOO:gfopt:OPTBAR dst=file.264\n" +"It may be useful to specify arguments which may not be consumed depending on the graph resolution; the specific keyword `gfopt` indicates that arguments after the keyword will not be tracked.\n" +"EX gpac -i file.mp4 -o file.aac:OPTFOO:gfopt:OPTBAR -o file.264\n" "This will warn if `OPTFOO` is not consumed, but will not track `OPTBAR`.\n" +" \n" +"A filter may be assigned a name (for inspection purposes, not inherited) using `:N=name` option. This name is not used in link resolution and may be changed at runtime by the filter instance.\n" +" \n" +"A filter may be assigned a tag (any string) using `:TAG=name` option. This tag does not need to be unique, and can be used to exclude filter in link resolution. Tags are not inherited, therefore dynamically loaded filters never have a tag.\n" +" \n" "# URL templating\n" -"Destination URLs can be templated using the same mechanism as MPEG-DASH, where `$KEYWORD$` is replaced in the template with the " -"resolved value and `$KEYWORD%%0Nd$` is replaced in the template with the resolved integer, padded with N zeros if needed. " -"`$$` is an escape for $\n" -"`KEYWORD` is **case sensitive**, and may be present multiple times in the string. Supported `KEYWORD` are:\n" +"Destination URLs can be dynamically constructed using templates. Pattern `$KEYWORD$` is replaced in the template with the " +"resolved value and `$KEYWORD%%0Nd$` is replaced in the template with the resolved integer, padded with up to N zeros if needed.\n" +"`KEYWORD` is **case sensitive**, and may be present multiple times in the string. Supported `KEYWORD`:\n" "- num: replaced by file number if defined, 0 otherwise\n" "- PID: ID of the source PID\n" "- URL: URL of source file\n" -"- File: path on disk for source file\n" +"- File: path on disk for source file; if not found, use URL if set, or PID name otherwise\n" +"- Type: name of stream type of PID (`video`, `audio` ...)\n" "- p4cc=ABCD: uses PID property with 4CC value `ABCD`\n" "- pname=VAL: uses PID property with name `VAL`\n" "- OTHER: locates property 4CC for the given name, or property name if no 4CC matches.\n" -"\n \nTemplating can be useful when encoding several qualities in one pass.\n" -"EX src=dump.yuv:size=640x360 vcrop:wnd=0x0x320x180 enc:c=avc:b=1M @2 enc:c=avc:b=750k dst=dump_$CropOrigin$x$Width$x$Height$.264:clone\n" -"This will create a croped version of the source, encoded in AVC at 1M, and a full version of the content in AVC at 750k. " -"Outputs will be `dump_0x0x320x180.264` for the croped version and `dump_0x0x640x360.264` for the non-croped one.\n" +" \n" +"`$$` is an escape for $\n" +"\n" +"Templating can be useful when encoding several qualities in one pass.\n" +"EX gpac -i dump.yuv:size=640x360 vcrop:wnd=0x0x320x180 c=avc:b=1M @2 c=avc:b=750k -o dump_$CropOrigin$x$Width$x$Height$.264:clone\n" +"This will create a cropped version of the source, encoded in AVC at 1M, and a full version of the content in AVC at 750k. " +"Outputs will be `dump_0x0x320x180.264` for the cropped version and `dump_0x0x640x360.264` for the non-cropped one.\n" "# Cloning filters\n" "When a filter accepts a single connection and has a connected input, it is no longer available for dynamic resolution. " -"There may be cases where this behaviour is undesired. Take a HEIF file with N items and do:\n" -"EX src=img.heif dst=dump_$ItemID$.jpg\n" +"There may be cases where this behavior is undesired. Take a HEIF file with N items and do:\n" +"EX gpac -i img.heif -o dump_$ItemID$.jpg\n" "In this case, only one item (likely the first declared in the file) will connect to the destination.\n" "Other items will not be connected since the destination only accepts one input PID.\n" -"There is a special option `clone` allowing destination filters (**and only them**) to be cloned with the same arguments:\n" -"EX src=img.heif dst=dump_$ItemID$.jpg:clone\n" +"There is a special option `clone` allowing filters to be cloned with the same arguments. The cloned filters have the same ID as the original one.\n" +"EX gpac -i img.heif -o dump_$ItemID$.jpg:clone\n" "In this case, the destination will be cloned for each item, and all will be exported to different JPEGs thanks to URL templating.\n" +"EX gpac -i vid.mpd c=avc:FID=1:clone -o transcode.mpd:SID=1\n" +"In this case, the encoder will be cloned for each video PIDs in the source, and the destination will only use PIDs coming from the encoders.\n" +"\n" +"When implicit linking is enabled, all filters are by default clonable. This allows duplicating the processing for each PIDs of the same type.\n" +"EX gpac -i dual_audio resample:osr=48k c=aac -o dst\n" +"The `resampler` filter will be cloned for each audio PID, and the encoder will be cloned for each resampler output.\n" +"You can explicitly deactivate the cloning instructions:\n" +"EX gpac -i dual_audio resample:osr=48k:clone=0 c=aac -o dst\n" +"The first audio will connect to the `resample` filter, the second to the `enc` filter and the `resample` output will connect to a clone of the `enc` filter.\n" +"\n" "# Templating filter chains\n" -"There can be cases where the number of desired outputs depends on the source content, for example dumping a multiplex of N services into N files. When the destination involves multiplexing the input PIDs, the `:clone`option is not enough since the muxer will always accept the input PIDs.\n" +"There can be cases where the number of desired outputs depends on the source content, for example dumping a multiplex of N services into N files. When the destination involves multiplexing the input PIDs, the `:clone` option is not enough since the multiplexer will always accept the input PIDs.\n" "To handle this, it is possible to use a PID property name in the sourceID of a filter with the value `*` or an empty value. In this case, whenever a new PID with a new value for the property is found, the filter with such sourceID will be dynamically cloned.\n" -"Warning: This feature should only be called with a single property set to `*` per source ID, results are undefined otherwise.\n" -"EX src=source.ts dst=file_$ServiceID$.mp4:SID=*#ServiceID=*\n" -"EX src=source.ts dst=file_$ServiceID$.mp4:SID=#ServiceID=\n" +"Warning: This feature should only be called with a single property set to `*` (or empty) per source ID, results are undefined otherwise.\n" +"EX gpac -i source.ts -o file_$ServiceID$.mp4:SID=*#ServiceID=*\n" +"EX gpac -i source.ts -o file_$ServiceID$.mp4:SID=#ServiceID=\n" "In this case, each new `ServiceID` value found when connecting PIDs to the destination will create a new destination file.\n" +"\n" +"Cloning in implicit linking mode applies to output as well:\n" +"EX gpac -i dual_audio -o dst_$PID$.aac\n" +"Each audio track will be dumped to aac (potentially reencoding if needed).\n" +"\n" "# Assigning PID properties\n" "It is possible to define properties on output PIDs that will be declared by a filter. This allows tagging parts of the " "graph with different properties than other parts (for example `ServiceID`). " -"The syntax is the same as filter option, and uses the fragment separator to identify properties, eg `#Name=Value`.\n" -"This sets output PIDs property (4cc, built-in name or any name) to the given value. Value can be omitted for booleans " -"(defaults to true, eg `:#Alpha`).\n" +"The syntax is the same as filter option, and uses the fragment separator to identify properties, e.g. `#Name=Value`.\n" +"This sets output PIDs property (4cc, built-in name or any name) to the given value. Value can be omitted for boolean " +"(defaults to true, e.g. `:#Alpha`).\n" "Non built-in properties are parsed as follows:\n" "- `file@FOO` will be declared as string with a value set to the content of `FOO`.\n" "- `bxml@FOO` will be declared as data with a value set to the binarized content of `FOO`.\n" "- `FOO` will be declared as string with a value set to `FOO`.\n" "- `TYPE@FOO` will be parsed according to `TYPE`. If the type is not recognized, the entire value is copied as string. See `gpac -h props` for defined types.\n" - -"Warning: Properties are not filtered and override the properties of the filter's output PIDs, be carefull not to break " +"\n" +"User-assigned PID properties on filter `fA` will be inherited by all filters dynamically loaded to solve `fA -> fB` connection.\n" +"If `fB` also has user-assigned PID properties, these only apply starting from `fB` in the chain and are not inherited by filters between `fA` and `fB`.\n" +"\n" +"Warning: Properties are not filtered and override the properties of the filter's output PIDs, be careful not to break " "the session by overriding core properties such as width/height/samplerate/... !\n" -"EX -i v1.mp4:#ServiceID=4 -i v2.mp4:#ServiceID=2 -o dump.ts\n" -"This will mux the streams in `dump.ts`, using `ServiceID` 4 for PIDs from `v1.mp4` and `ServiceID` 2 for PIDs from `v2.mp4`.\n" +"EX gpac -i v1.mp4:#ServiceID=4 -i v2.mp4:#ServiceID=2 -o dump.ts\n" +"This will multiplex the streams in `dump.ts`, using `ServiceID` 4 for PIDs from `v1.mp4` and `ServiceID` 2 for PIDs from `v2.mp4`.\n" "\n" -"PID properties may be conditionally assigned by checking other PID properties. The syntax uses paranthesis (not configurable) after the property assignment sign:\n" +"PID properties may be conditionally assigned by checking other PID properties. The syntax uses parenthesis (not configurable) after the property assignment sign:\n" "`#Prop=(CP=CV)VAL`\n" "This will assign PID property `Prop` to `VAL` for PIDs with property `CP` equal to `CV`.\n" "`#Prop=(CP=CV)VAL,(CP2=CV2)VAL2`\n" @@ -348,28 +462,42 @@ const char *gpac_doc = "It is possible to use a file to define options of a filter, by specifying the target file name as an option without value, i.e. `:myopts.txt`.\n" "Warning: Only local files are allowed.\n" "An option file is a simple text file containing one or more options or PID properties on one or more lines.\n" -"A line begining with \"//\" is a comment and is ignored.\n" +"A line beginning with \"//\" is a comment and is ignored.\n" "Options in an option file may point to other option files, with a maximum redirection level of 5.\n" "An option file declaration (`filter:myopts.txt`) follows the same inheritance rules as regular options.\n" -"EX src=source.mp4:myopts.txt:foo=bar dst\n" +"EX gpac -i source.mp4:myopts.txt:foo=bar -o dst\n" "Any filter loaded between `source.mp4` and `dst` will inherit both `myopts.txt` and `foo` options and will resolve options and PID properties given in `myopts.txt`.\n" "# Specific filter options\n" "Some specific keywords are replaced when processing filter options.\n" "Warning: These keywords do not apply to PID properties. Multiple keywords cannot be defined for a single option.\n" "Defined keywords:\n" -"- $GSHARE: replaced by system path to GPAC shared directory (e.g. /usr/share)\n" -"- $GJS: replaced by the first path specified by global config option [-js-dirs](CORE) that contains the file name following the macro, e.g. $GJS/source.js\n" +"- $GSHARE: replaced by system path to GPAC shared directory (e.g. /usr/share/gpac)\n" +"- $GJS: replaced by the first path from global share directory and paths set through [-js-dirs](CORE) that contains the file name following the macro, e.g. $GJS/source.js\n" "- $GLANG: replaced by the global config language option [-lang](CORE)\n" "- $GUA: replaced by the global config user agent option [-user-agent](CORE)\n" "- $GINC(init_val[,inc]): replaced by `init_val` and increment `init_val` by `inc` (positive or negative number, 1 if not specified) each time a new filter using this string is created.\n" "\n" -"The $GINC construct can be used to dynamically assign numbers in filter chains:\n" +"The `$GINC` construct can be used to dynamically assign numbers in filter chains:\n" "EX gpac -i source.ts tssplit @#ServiceID= -o dump_$GINC(10,2).ts\n" "This will dump first service in dump_10.ts, second service in dump_12.ts, etc...\n" +"\n" +"As seen previously, the following options may be set on any filter, but are not visible in individual filter help:\n" +"- FID: filter identifier\n" +"- SID: filter source(s)\n" +"- N: filter name\n" +"- FS: sub-session identifier\n" +"- TAG: filter tag\n" +"- clone: filter cloning flag\n" +"- nomux: enable/disable direct file copy\n" +"- gfreg: preferred filter registry names for link solving\n" +"- gfloc: following options are local to filter declaration (not inherited)\n" +"- gfopt: following options are not tracked\n" +"- gpac: argument separator for URLs\n" +"\n" "# External filters\n" "GPAC comes with a set of built-in filters in libgpac. It may also load external filters in dynamic libraries, located in " -"folders listed in [-mod-dirs](CORE) option. The files shall be named `gf_*` and shall export" -" a single function returning a filter register - see [libgpac documentation](https://doxygen.gpac.io/) for more details.\n" +"default module folder or folders listed in [-mod-dirs](CORE) option. The files shall be named `gf_*` and shall export" +" a single function `RegisterFilter` returning a filter register - see [libgpac documentation](https://doxygen.gpac.io/) for more details.\n" "\n"; #endif @@ -457,8 +585,9 @@ const char *gpac_alias = "\n" "The specified index can be:\n" "- forward index: a strictly positive integer, 1 being the first argument after the alias\n" -"- backward index: the value 'n' (or 'N') to indicate the last argument on the command line. This can be followed by `-x` to rewind arguments (eg `@{n-1}` is the before last argument)\n" +"- backward index: the value 'n' (or 'N') to indicate the last argument on the command line. This can be followed by `-x` to rewind arguments (e.g. `@{n-1}` is the before last argument)\n" "\n" +"Before solving aliases, all option arguments are moved at the beginging of the command line. This implies that alias arguments cannot be options.\n" "Arguments not used by any aliases are kept on the command line, other ones are removed\n" "\n" "EX -alias=\"foo src=@{N} dst=test.mp4\"\n" @@ -468,7 +597,7 @@ const char *gpac_alias = "EX -alias=\"list inspect src=@{+2:N}\"\n" "The command `gpac list f1 f2 f3` expands to `gpac inspect src=f2 src=f3 f1`\n" "EX -alias=\"plist aout vout flist:srcs=@{-,N}\"\n" -"The command `gpac plist f1 f2 f3` expands to `gpac aout vout plist:srcs=\"f1,f2,f3\"` \n" +"The command `gpac plist f1 f2 f3` expands to `gpac aout vout flist:srcs=\"f1,f2,f3\"` \n" "\n" "Alias documentation can be set using `gpac -aliasdoc=\"NAME VALUE\"`, with `NAME` the alias name and `VALUE` the documentation.\n" "Alias documentation will then appear in gpac help.\n" @@ -535,7 +664,7 @@ static void gpac_core_help(GF_SysArgMode mode, Bool for_logs) gf_sys_print_core_help(helpout, help_flags, mode, mask); } -GF_GPACArg gpac_args[] = +static GF_GPACArg gpac_args[] = { #ifdef GPAC_MEMORY_TRACKING GF_DEF_ARG("mem-track", NULL, "enable memory tracker", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), @@ -545,47 +674,53 @@ GF_GPACArg gpac_args[] = GF_DEF_ARG("sloop", NULL, "loop execution of session, creating a session at each loop, mainly used for testing. If no value is given, loops forever", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), GF_DEF_ARG("runfor", NULL, "run for the given amount of milliseconds", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), GF_DEF_ARG("runforx", NULL, "run for the given amount of milliseconds and exit with no cleanup", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), + GF_DEF_ARG("runfors", NULL, "run for the given amount of milliseconds and exit with segfault (tests)", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), + GF_DEF_ARG("runforl", NULL, "run for the given amount of milliseconds and wait forever at end (tests)", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), GF_DEF_ARG("stats", NULL, "print stats after execution", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("graph", NULL, "print graph after execution", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("k", NULL, "enable keyboard interaction from command line", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), GF_DEF_ARG("r", NULL, "enable reporting\n" "- r: runtime reporting\n" - "- r=FA[,FB]: runtime reporting but only print given filters, eg `r=mp4mx`for ISOBMFF muxer only\n" + "- r=FA[,FB]: runtime reporting but only print given filters, e.g. `r=mp4mx` for ISOBMFF multiplexer only\n" "- r=: only print final report" , NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("seps", NULL, "set the default character sets used to separate various arguments\n"\ - "- the first char is used to separate argument names\n"\ - "- the second char, if present, is used to separate names and values\n"\ - "- the third char, if present, is used to separate fragments for PID sources\n"\ - "- the fourth char, if present, is used for list separators (__sourceIDs__, __gfreg__, ...)\n"\ - "- the fifth char, if present, is used for boolean negation\n"\ + GF_DEF_ARG("seps", NULL, "set the default character sets used to separate various arguments\n" + "- the first char is used to separate argument names\n" + "- the second char, if present, is used to separate names and values\n" + "- the third char, if present, is used to separate fragments for PID sources\n" + "- the fourth char, if present, is used for list separators (__sourceIDs__, __gfreg__, ...)\n" + "- the fifth char, if present, is used for boolean negation\n" "- the sixth char, if present, is used for LINK directives (see [filters help (-h doc)](filters_general))", GF_FS_DEFAULT_SEPS, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT), GF_DEF_ARG("i", "src", "specify an input file - see [filters help (-h doc)](filters_general)", NULL, NULL, GF_ARG_STRING, 0), GF_DEF_ARG("o", "dst", "specify an output file - see [filters help (-h doc)](filters_general)", NULL, NULL, GF_ARG_STRING, 0), GF_DEF_ARG("ib", NULL, "specify an input file to wrap as GF_FileIO object (testing of GF_FileIO)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT), GF_DEF_ARG("ob", NULL, "specify an output file to wrap as GF_FileIO object (testing of GF_FileIO)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("h", "help,-ha,-hx,-hh", "print help. Use `-help` or `-h` for basic options, `-ha` for advanced options, `-hx` for expert options and `-hh` for all. \nNote: The `@` character can be used in place of the `*` character. String parameter can be:\n"\ - "- empty: print command line options help\n"\ - "- doc: print the general filter info\n"\ - "- alias: print the gpac alias syntax\n"\ - "- log: print the log system help\n"\ - "- core: print the supported libgpac core options. Use -ha/-hx/-hh for advanced/expert options\n"\ - "- cfg: print the GPAC configuration help\n"\ - "- prompt: print the GPAC prompt help when running in interactive mode (see [-k](GPAC) )\n"\ - "- modules: print available modules\n"\ - "- filters: print name of all available filters\n"\ - "- filters:*: print name of all available filters, including meta filters\n"\ - "- codecs: print the supported builtin codecs\n"\ - "- props: print the supported builtin PID and packet properties\n"\ - "- colors: print the builtin color names and their values\n"\ - "- links: print possible connections between each supported filters\n"\ - "- links FNAME: print sources and sinks for filter `FNAME` (either builtin or JS filter)\n"\ + GF_DEF_ARG("cl", NULL, "force complete mode when no link directive are set - see [filters help (-h doc)](filters_general)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), + GF_DEF_ARG("step", NULL, "test step mode in non-blocking session", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), + GF_DEF_ARG("h", "help,-ha,-hx,-hh", "print help. Use `-help` or `-h` for basic options, `-ha` for advanced options, `-hx` for expert options and `-hh` for all. \nNote: The `@` character can be used in place of the `*` character. String parameter can be:\n" + "- empty: print command line options help\n" + "- doc: print the general filter info\n" + "- alias: print the gpac alias syntax\n" + "- log: print the log system help\n" + "- core: print the supported libgpac core options. Use -ha/-hx/-hh for advanced/expert options\n" + "- cfg: print the GPAC configuration help\n" + "- prompt: print the GPAC prompt help when running in interactive mode (see [-k](GPAC) )\n" + "- modules: print available modules\n" + "- filters: print name of all available filters\n" + "- filters:*: print name of all available filters, including meta filters\n" + "- codecs: print the supported builtin codecs\n" + "- props: print the supported builtin PID and packet properties\n" + "- props PNAME: print the supported builtin PID and packet properties mentioning `PNAME`\n" + "- colors: print the builtin color names and their values\n" + "- layouts: print the builtin CICP audio channel layout names and their values\n" + "- links: print possible connections between each supported filters (use -hx to view src->dst cap bundle detail)\n" + "- links FNAME: print sources and sinks for filter `FNAME` (either builtin or JS filter)\n" "- FNAME: print filter `FNAME` info (multiple FNAME can be given)\n" - " - For meta-filters, use `FNAME:INST`, eg `ffavin:avfoundation`\n" + " - For meta-filters, use `FNAME:INST`, e.g. `ffavin:avfoundation`\n" " - Use `*` to print info on all filters (__big output!__), `*:*` to print info on all filters including meta filter instances (__really big output!__)\n" - " - By default only basic filter options and description are shown. Use `-ha` to show advanced options capabilities, `-hx` for expert options, `-hh` for all options and filter capabilities including on filters disabled in this build\n"\ + " - By default only basic filter options and description are shown. Use `-ha` to show advanced options capabilities, `-hx` for expert options, `-hh` for all options and filter capabilities including on filters disabled in this build\n" "- FNAME.OPT: print option `OPT` in filter `FNAME`\n" "- OPT: look in filter names and options for `OPT` and suggest possible matches if none found. Use `-hx` to look for keyword in all option descriptions\n" , NULL, NULL, GF_ARG_STRING, 0), @@ -603,7 +738,7 @@ GF_GPACArg gpac_args[] = GF_DEF_ARG("wfx", NULL, "write all filter options and all meta filter arguments in the config file unless already set (__large config file !__)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), GF_DEF_ARG("unit-tests", NULL, "enable unit tests of some functions otherwise not covered by gpac test suite", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_HIDE), GF_DEF_ARG("genmd", NULL, "generate markdown doc", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_HIDE), - GF_DEF_ARG("xopt", NULL, "do not throw error on any unrecognized options following this option - used to pass arguments to GUI", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), + GF_DEF_ARG("xopt", NULL, "unrecognized options and filters declaration following this option are ignored - used to pass arguments to GUI", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), {0} }; @@ -616,19 +751,21 @@ static void gpac_usage(GF_SysArgMode argmode) gf_sys_format_help(helpout, help_flags, "Usage: gpac [options] FILTER [LINK] FILTER [...] \n"); gf_sys_format_help(helpout, help_flags, "gpac is GPAC's command line tool for setting up and running filter chains.\n\n" - "__FILTER__: a single filter declaration (eg, `-i file`, `-o dump`, `inspect`, ...), see %s.\n" - "__[LINK]__: a link instruction (eg, `@`, `@2`, `@2#StreamType=Visual`, ...), see %s.\n" + "__FILTER__: a single filter declaration (e.g., `-i file`, `-o dump`, `inspect`, ...), see %s.\n" + "__[LINK]__: a link instruction (e.g., `@`, `@2`, `@2#StreamType=Visual`, ...), see %s.\n" "__[options]__: one or more option strings, each starting with a `-` character.\n" " - an option using a single `-` indicates an option of gpac (see %s) or of libgpac (see %s)\n" - " - an option using `--` indicates a global filter option, for example `--block_size=1000` (see %s)\n" - " - an option using `-+` indicates a global meta-filter filter (eg FFMPEG) option, for example `-+profile=Baseline` (see %s)\n" + " - an option using `--` indicates a global filter or meta-filter (e.g. FFMPEG) option, e.g. `--block_size=1000` or `--profile=Baseline` (see %s)\n" " \n" "Filter declaration order may impact the link resolver which will try linking in declaration order. Most of the time for simple graphs, this has no impact. However, for complex graphs with no link declarations, this can lead to different results. \n" "Options do not require any specific order, and may be present anywhere, including between link statements or filter declarations. \n" "Boolean values do not need any value specified. Other types shall be formatted as `opt=val`, except [-i](), `-src`, [-o](), `-dst` and [-h]() options.\n\n" + "\n" + "The session can be interrupted at any time using `ctrl+c`, which can also be used to toggle global reporting.\n" + "\n" "The possible options for gpac are:\n\n", (gen_doc==1) ? "[gpac -h doc](filters_general#filter-declaration-filter)" : "`gpac -h doc`", - (gen_doc==1) ? "[gpac -h doc](filters_general#expliciting-links-between-filters-link)" : "`gpac -h doc`", + (gen_doc==1) ? "[gpac -h doc](filters_general#explicit-links-between-filters-link)" : "`gpac -h doc`", (gen_doc==1) ? "[gpac -hx](gpac_general#h)" : "`gpac -hx`", (gen_doc==1) ? "[gpac -hx core](core_options)" : "`gpac -hx core`", (gen_doc==1) ? "[gpac -h doc](core_config#global-filter-options)" : "`gpac -h doc`", @@ -665,7 +802,7 @@ static void gpac_usage(GF_SysArgMode argmode) } #ifndef GPAC_DISABLE_DOC -const char *gpac_config = +static const char *gpac_config = { "# Configuration file\n" "GPAC uses a configuration file to modify default options of libgpac and filters. This configuration file is located in `$HOME/.gpac/GPAC.cfg`.\n" @@ -688,7 +825,7 @@ const char *gpac_config = "Setting this in the config file is equivalent to using `-threads=2`.\n" "The options specified at prompt overrides the value of the config file.\n" "# Filter options in configuration\n" -"It is possible to alter the default value of a filter option by modifing the configuration file. Filter __foo__ options are stored in section " +"It is possible to alter the default value of a filter option by modifying the configuration file. Filter __foo__ options are stored in section " "`[filter@foo]`, using option name and value as key-value pair. Options specified through the configuration file do not take precedence over " "options specified at prompt or through alias.\n" "EX [filter@rtpin]interleave=yes\n" @@ -703,11 +840,11 @@ const char *gpac_config = "EX --buffer=100 -i file vout aout:buffer=10\n" "This is equivalent to specifying `vout:buffer=100 aout:buffer=10`.\n" "Warning: This syntax only applies to regular filter options. It cannot be used with builtin shortcuts (gfreg, enc, ...).\n" -"Meta-filter options can be set in the same way using the syntax `-+OPT_NAME=VAL`.\n" -"EX -+profile=Baseline -i file.cmp -o dump.264\n" +"Meta-filter options can be set in the same way using the syntax `--OPT_NAME=VAL`.\n" +"EX --profile=Baseline -i file.cmp -o dump.264\n" "This is equivalent to specifying `-o dump.264:profile=Baseline`.\n" " \n" -"For both syntax, it is possible to specify the filter registry name of the option, using `--FNAME@OPTNAME=VAL`.\n" +"For both syntax, it is possible to specify the filter registry name of the option, using `--FNAME:OPTNAME=VAL` or `--FNAME@OPTNAME=VAL`.\n" "In this case the option will only be set for filters which are instances of registry FNAME. This is used when several registries use same option names.\n" "EX --flist@timescale=100 -i plist1 -i plist2 -o live.mpd\n" "This will set the timescale option on the playlists filters but not on the dasher filter.\n" @@ -776,7 +913,7 @@ static void gpac_on_logs(void *cbck, GF_LOG_Level log_level, GF_LOG_Tool log_too } } -u64 last_report_clock_us = 0; +static u64 last_report_clock_us = 0; static void print_date(u64 time) { time_t gtime; @@ -791,11 +928,14 @@ static void print_date(u64 time) fprintf(stderr, "[%02d:%02d:%02d.%03dZ] ", t->tm_hour, t->tm_min, t->tm_sec, ms); } +static Bool in_sig_handler = GF_FALSE; static void gpac_print_report(GF_FilterSession *fsess, Bool is_init, Bool is_final) { u32 i, count, nb_active; u64 now; + if (in_sig_handler) return;; + if (is_init) { if (enable_reports==2) gf_sys_set_console_code(stderr, GF_CONSOLE_SAVE); @@ -907,7 +1047,7 @@ static Bool gpac_event_proc(void *opaque, GF_Event *event) } } else if (event->type==GF_EVENT_QUIT) { - gf_fs_abort(fsess, GF_TRUE); + gf_fs_abort(fsess, GF_FS_FLUSH_ALL); } return GF_FALSE; } @@ -927,7 +1067,7 @@ typedef enum GPAC_PRINT_HELP } GPAC_Command; -struct _gpac_key +static struct _gpac_key { u8 char_code; GPAC_Command cmd_type; @@ -968,8 +1108,8 @@ static void gpac_fsess_task_help() } } -char szFilter[100]; -char szCom[2048]; +static char szFilter[100]; +static char szCom[2048]; static u64 run_start_time = 0; static Bool gpac_fsess_task(GF_FilterSession *fsess, void *callback, u32 *reschedule_ms) { @@ -982,11 +1122,11 @@ static Bool gpac_fsess_task(GF_FilterSession *fsess, void *callback, u32 *resche GPAC_Command c = get_cmd(gf_prompt_get_char()); switch (c) { case GPAC_QUIT: - gf_fs_abort(fsess, GF_TRUE); + gf_fs_abort(fsess, GF_FS_FLUSH_ALL); nb_loops = 0; return GF_FALSE; case GPAC_EXIT: - gf_fs_abort(fsess, GF_FALSE); + gf_fs_abort(fsess, GF_FS_FLUSH_NONE); nb_loops = 0; return GF_FALSE; case GPAC_PRINT_STATS: @@ -1118,63 +1258,121 @@ static Bool gpac_fsess_task(GF_FilterSession *fsess, void *callback, u32 *resche } if (runfor>0) { u64 now = gf_sys_clock_high_res(); - if (!run_start_time) run_start_time = now; - else if (now - run_start_time > runfor) { - if (runfor_exit) - exit(0); - - gf_fs_abort(fsess, GF_TRUE); - nb_loops = 0; + if (!run_start_time) { + run_start_time = now; + } else if (now - run_start_time > runfor) { + //segfault requested + if (exit_mode==1) { + exit(127); + } + //deadlock requested + else if (exit_mode==2) { + while(1) { + gf_sleep(1); + } + } + if (nb_loops || loops_done) { + gf_fs_abort(fsess, runfor_exit ? GF_FS_FLUSH_NONE : GF_FS_FLUSH_ALL); + run_start_time = 0; + } else { + if (runfor_exit) + exit(0); + gf_fs_abort(fsess, GF_FS_FLUSH_ALL); + } return GF_FALSE; } } if (gf_fs_is_last_task(fsess)) return GF_FALSE; - *reschedule_ms = 500; + //check every 50 ms + *reschedule_ms = 50; return GF_TRUE; } -static Bool sigint_catched=GF_FALSE; -static Bool sigint_processed=GF_FALSE; +static Bool prev_was_cmd=GF_FALSE; +static Bool signal_catched=GF_FALSE; +static Bool signal_processed=GF_FALSE; #ifdef WIN32 #include static BOOL WINAPI gpac_sig_handler(DWORD sig) { if (sig == CTRL_C_EVENT) { + Bool is_inter = GF_TRUE; #else #include static void gpac_sig_handler(int sig) { - if (sig == SIGINT) { + if ((sig == SIGINT) || (sig == SIGTERM) || (sig == SIGABRT)) { + Bool is_inter = (sig == SIGINT) ? GF_TRUE : GF_FALSE; #endif nb_loops = 0; if (session) { char input=0; int res; - if (sigint_catched) { - if (sigint_processed) { - fprintf(stderr, "catched SIGINT twice and session not responding, forcing exit. Please report to GPAC devs https://github.com/gpac/gpac\n"); + if (signal_catched) { + if (signal_processed) { + fprintf(stderr, "catched SIGINT|SIGTERM twice and session not responding, forcing exit.\n"); } exit(1); } - sigint_catched = GF_TRUE; - fprintf(stderr, "catched SIGINT - flush session before exit ? (Y/n):\n"); - res = scanf("%c", &input); - if (res!=1) input=0; - switch (input) { - case 'Y': - case 'y': - case '\n': - sigint_processed = GF_TRUE; - gf_fs_abort(session, GF_TRUE); - break; - case 0: - break; - default: - sigint_processed = GF_TRUE; - gf_fs_abort(session, GF_FALSE); - break; + + signal_catched = GF_TRUE; + if (is_inter) { + in_sig_handler = GF_TRUE; + fprintf(stderr, "\nToggle reports (r) or flush session before exit (Y/f/n) ? \n"); +rescan: + res = scanf("%c", &input); + if (res!=1) input=0; + switch (input) { + case 'Y': + case 'y': + signal_processed = GF_TRUE; + gf_fs_abort(session, GF_FS_FLUSH_FAST); + break; + case 'F': + case 'f': + signal_processed = GF_TRUE; + gf_fs_abort(session, GF_FS_FLUSH_ALL); + break; + case 0: + break; + case '\n': + //prev was a command, flush \n + if (prev_was_cmd) { + prev_was_cmd = GF_FALSE; + goto rescan; + } + break; + + case 'R': + case 'r': + prev_was_cmd = GF_TRUE; + if (!enable_reports) { + enable_reports = 2; + report_filter = NULL; + gf_fs_set_ui_callback(session, gpac_event_proc, session); + gf_fs_enable_reporting(session, GF_TRUE); + in_sig_handler = GF_FALSE; + gpac_print_report(session, GF_TRUE, GF_FALSE); + } else { + enable_reports = 0; + gf_fs_enable_reporting(session, GF_FALSE); + gf_sys_set_console_code(stderr, GF_CONSOLE_CLEAR); + gf_sys_set_console_code(stderr, GF_CONSOLE_RESTORE); + } + signal_catched = GF_FALSE; + signal_processed = GF_FALSE; + break; + default: + signal_processed = GF_TRUE; + gf_fs_abort(session, GF_FS_FLUSH_NONE); + break; + } + in_sig_handler = GF_FALSE; + } else { + signal_processed = GF_TRUE; + gf_fs_abort(session, GF_FS_FLUSH_NONE); } } } @@ -1201,13 +1399,17 @@ static void parse_sep_set(const char *arg, Bool *override_seps) static int gpac_exit_fun(int code, char **alias_argv, int alias_argc) { u32 i; - for (i=1; i=0) { + for (i=1; iarg_name, NULL); + if ((arg->arg_type==GF_PROP_UINT) && arg->min_max_enum && strchr(arg->min_max_enum, '|')) { + gf_dynstrcat(&argn, arg->min_max_enum, "@"); + } old_val = gf_cfg_get_key(opts, "allopts", argn); if (old_val) { @@ -1353,6 +1558,19 @@ static void gpac_suggest_arg(char *aname) } } } + //look in alias + u32 nb_alias = gf_opts_get_key_count("gpac.alias"); + for (k=0; kname)) { - if (!found) { - found = GF_TRUE; - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Closest filter names: \n")); + if (gf_sys_word_match(fname, freg->name)) { + if (!first) { + first = GF_TRUE; + if (!found) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No such filter %s\n", fname)); + found = GF_TRUE; + } + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("Closest filter names: \n")); + } + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("- %s\n", freg->name)); } - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("- %s\n", freg->name)); } } - if (!found && is_help) { - const char *doc_helps[] = { - "log", "core", "modules", "doc", "alias", "props", "colors", "cfg", "prompt", "codecs", "links", "bin", "filters", "filters:*", "filters:@", NULL - }; - i=0; - while (doc_helps[i]) { - if (gf_sys_word_match(fname, doc_helps[i])) { - if (!found) { - found = GF_TRUE; - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Closest help command: \n")); + + if (is_help) { + if (!pass_exact) { + const char *doc_helps[] = { + "log", "core", "modules", "doc", "alias", "props", "colors", "layouts", "cfg", "prompt", "codecs", "links", "bin", "filters", "filters:*", "filters:@", NULL + }; + first = GF_FALSE; + i=0; + while (doc_helps[i]) { + if (gf_sys_word_match(fname, doc_helps[i])) { + if (!first) { + first = GF_TRUE; + if (!found) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No such filter %s\n", fname)); + found = GF_TRUE; + } + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("Closest help commands: \n")); + } + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("-h %s\n", doc_helps[i])); } - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("-h %s\n", doc_helps[i])); + i++; } - i++; } + if (!filter_only) { - Bool arg_found=GF_FALSE; u32 nb_alias = gf_opts_get_key_count("gpac.alias"); + first = GF_FALSE; for (i=0; iname)) { + if (!first) { + first = GF_TRUE; + if (!found) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No such filter %s\n", fname)); + found = GF_TRUE; + } + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("Closest core option: \n")); + } + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("-%s: %s\n", arg->name, arg->description)); + } + } + + //check filters + first = GF_FALSE; for (i=0; iargs[j]; if (!arg || !arg->arg_name) break; j++; + + if (pass_exact) { + if (!strcmp(fname, arg->arg_name)) { + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s.%s %s\n", reg->name, arg->arg_name, arg->arg_desc); + found = GF_TRUE; + } + continue; + } if (!gf_sys_word_match(fname, arg->arg_name)) continue; - if (!arg_found) { - GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("Closest matching filter option:\n", fname)); - arg_found = GF_TRUE; - found = GF_TRUE; + if (!first) { + first = GF_TRUE; + if (!found) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No such filter %s\n", fname)); + found = GF_TRUE; + } + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("Closest matching filter options:\n", fname)); } gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s.%s \n", reg->name, arg->arg_name); } @@ -1424,9 +1710,14 @@ static void gpac_suggest_filter(char *fname, Bool is_help, Bool filter_only) } } if (!found) { - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No filter %swith similar name found, see gpac -h filters%s\n", - is_help ? "or help command " : "", - is_help ? " or gpac -h" : "" + if (pass_exact) { + pass_exact = GF_FALSE; + goto redo_pass; + } + + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No filter%swith similar name found, see gpac -h filters%s\n", + is_help ? ", option or help command " : " ", + is_help ? ", gpac -h or search all help using gpac -hx" : "" )); } } @@ -1460,14 +1751,33 @@ static void gpac_suggest_filter_arg(GF_Config *opts, char *argname, u32 atype) count = gf_cfg_get_key_count(opts, "allopts"); for (i=0; i2*len) continue; + if (alen>2*len) { + if (sep) sep[0] = '@'; + continue; + } for (j=0; j=2) || print_meta_filters || dump_codecs || print_filter_info) sflags |= GF_FS_FLAG_LOAD_META; if (view_filter_conn || list_filters || (print_filter_info && (argmode == GF_ARGMODE_ALL)) ) gf_opts_set_key("temp", "gendoc", "yes"); + if (list_filters || print_filter_info) + gf_opts_set_key("temp", "helponly", "yes"); restart: + prev_filter_is_sink = 0; + current_subsession_id = 0; + prev_filter_is_not_source = 0; + current_source_id = 0; + + if (view_conn_for_filter && argmode>=GF_ARGMODE_EXPERT) + sflags |= GF_FS_FLAG_PRINT_CONNECTIONS; session = gf_fs_new_defaults(sflags); @@ -1957,6 +2319,7 @@ restart: //all good to go, load filters has_xopt = GF_FALSE; + links_directive = gf_list_new(); loaded_filters = gf_list_new(); for (i=1; i1) { - link_prev_filter = atoi(arg+1); - if (link_prev_filter<0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Wrong filter index %d, must be positive\n", link_prev_filter)); - e = GF_BAD_PARAM; - goto exit; - } - } - - if (ext) ext[0] = separator_set[SEP_FRAG]; + gf_list_add(links_directive, arg); continue; } @@ -2051,6 +2403,8 @@ restart: } if (!filter) { + if (has_xopt) + continue; if (!e) e = GF_FILTER_NOT_FOUND; if (e!=GF_FILTER_NOT_FOUND) { @@ -2059,25 +2413,80 @@ restart: GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to find filter%s \"%s\"\n", is_simple ? "" : " for", arg)); gpac_suggest_filter(arg, GF_FALSE, GF_TRUE); + nb_filters=0; } - nb_filters=0; goto exit; } nb_filters++; - if (link_prev_filter>=0) { - GF_Filter *link_from = gf_list_get(loaded_filters, gf_list_count(loaded_filters)-1-link_prev_filter); + if (!(sflags & GF_FS_FLAG_NO_IMPLICIT)) + gf_filter_tag_subsession(filter, current_subsession_id, current_source_id); + + while (gf_list_count(links_directive)) { + char *link_prev_filter_ext = NULL; + GF_Filter *link_from; + Bool reverse_order = GF_FALSE; + s32 link_filter_idx = -1; + char *link = gf_list_pop_front(links_directive); + char *ext = strchr(link, separator_set[SEP_FRAG]); + if (ext) { + ext[0] = 0; + link_prev_filter_ext = ext+1; + } + if (strlen(link)>1) { + if (link[1] == separator_set[SEP_LINK] ) { + reverse_order = GF_TRUE; + link++; + } + link_filter_idx = atoi(link+1); + if (link_filter_idx < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Wrong filter index %d, must be positive\n", link_filter_idx)); + e = GF_BAD_PARAM; + goto exit; + } + } else { + link_filter_idx = 0; + } + if (ext) ext[0] = separator_set[SEP_FRAG]; + + if (reverse_order) + link_from = gf_list_get(loaded_filters, link_filter_idx); + else + link_from = gf_list_get(loaded_filters, gf_list_count(loaded_filters)-1-link_filter_idx); + if (!link_from) { - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Wrong filter index @%d\n", link_prev_filter)); + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Wrong filter index @%d\n", link_filter_idx)); e = GF_BAD_PARAM; goto exit; } - link_prev_filter = -1; gf_filter_set_source(filter, link_from, link_prev_filter_ext); - link_prev_filter_ext = NULL; } gf_list_add(loaded_filters, filter); + + //implicit mode, check changes of source and sinks + if (!(sflags & GF_FS_FLAG_NO_IMPLICIT)) { + if (gf_filter_is_source(filter)) { + if (prev_filter_is_not_source) { + current_source_id++; + gf_filter_tag_subsession(filter, current_subsession_id, current_source_id); + } + prev_filter_is_not_source = 0; + } else { + prev_filter_is_not_source = 1; + } + + if (gf_filter_is_sink(filter)) { + prev_filter_is_sink = GF_TRUE; + } + else if (prev_filter_is_sink && gf_filter_is_source(filter)) { + prev_filter_is_sink = GF_FALSE; + current_subsession_id++; + current_source_id=0; + prev_filter_is_not_source = 0; + gf_filter_tag_subsession(filter, current_subsession_id, current_source_id); + } + } } if (!gf_list_count(loaded_filters) && !session_js) { if (nothing_to_do && !gen_doc) { @@ -2094,9 +2503,17 @@ restart: gf_fs_enable_reporting(session, GF_TRUE); } + if (gf_list_count(links_directive)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("Link separators specified but no following filter, ignoring links ")); + while (gf_list_count(links_directive)) { + const char *ld = gf_list_pop_front(links_directive); + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("\"%s\"", ld)); + } + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("\n")); + } if (enable_prompt || (runfor>0)) { - if (enable_prompt) { + if (enable_prompt && !loops_done) { GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Running session, press 'h' for help\n")); } gf_fs_post_user_task(session, gpac_fsess_task, NULL, "gpac_fsess_task"); @@ -2106,6 +2523,7 @@ restart: SetConsoleCtrlHandler((PHANDLER_ROUTINE)gpac_sig_handler, TRUE); #else signal(SIGINT, gpac_sig_handler); + signal(SIGTERM, gpac_sig_handler); #endif } @@ -2113,8 +2531,39 @@ restart: gpac_print_report(session, GF_TRUE, GF_FALSE); } - e = gf_fs_run(session); - if (e>0) e = GF_OK; + if (!session_js) { + u32 j; + Bool has_vout = GF_FALSE; + Bool has_compositor = GF_FALSE; + for (j=0; j0) e = GF_OK; + } if (e) { fprintf(stderr, "session error %s\n", gf_error_to_string(e) ); @@ -2135,6 +2584,7 @@ restart: } gpac_print_report(session, GF_FALSE, GF_TRUE); } + gf_fs_print_non_connected_ex(session, alias_is_play); exit: if (enable_reports==2) { @@ -2154,6 +2604,7 @@ exit: session = NULL; gf_fs_del(tmp_sess); if (loaded_filters) gf_list_del(loaded_filters); + if (links_directive) gf_list_del(links_directive); cleanup_file_io(); @@ -2161,10 +2612,18 @@ exit: if (nb_loops>0) nb_loops--; loops_done++; fprintf(stderr, "session done, restarting (loop %d)\n", loops_done); + fflush(stderr); gf_log_reset_file(); goto restart; } +#ifdef GPAC_HAS_QJS + if (loops_done) { + void gf_js_delete_runtime(); + gf_js_delete_runtime(); + } +#endif + gpac_exit(e<0 ? 1 : 0); } @@ -2201,7 +2660,7 @@ static void dump_caps(u32 nb_caps, const GF_FilterCapability *caps) //dump some interesting predefined ones which are not mapped to types if (cap->code==GF_PROP_PID_STREAM_TYPE) szVal = gf_stream_type_name(cap->val.value.uint); else if (cap->code==GF_PROP_PID_CODECID) szVal = (const char *) gf_codecid_name(cap->val.value.uint); - else szVal = gf_props_dump_val(&cap->val, szDump, GF_FALSE, NULL); + else szVal = gf_props_dump_val(&cap->val, szDump, GF_PROP_DUMP_DATA_NONE, NULL); gf_sys_format_help(helpout, help_flags, " %s=\"%s\"", szName, szVal); if (cap->priority) gf_sys_format_help(helpout, help_flags, ", priority=%d", cap->priority); @@ -2242,7 +2701,12 @@ static void print_filter_arg(const GF_FilterArgs *a, u32 gen_doc) } if (a->flags & GF_FS_ARG_UPDATE) gf_sys_format_help(helpout, help_flags, ", updatable"); // if (a->flags & GF_FS_ARG_META) gf_sys_format_help(helpout, help_flags, ", meta"); - gf_sys_format_help(helpout, help_flags | GF_PRINTARG_OPT_DESC, "): %s\n", a->arg_desc); + + if (is_enum && a->arg_desc && !strchr(a->arg_desc, '\n')) { + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_OPT_DESC, "): %s (%s)\n", a->arg_desc, a->min_max_enum); + } else { + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_OPT_DESC, "): %s\n", a->arg_desc); + } //check syntax if (gen_doc) { @@ -2256,6 +2720,8 @@ static void print_filter_arg(const GF_FilterArgs *a, u32 gen_doc) if (a->min_max_enum && strchr(a->min_max_enum, '|')) gf_sys_format_help(helpout, help_flags, "\n"); + else if (!a->min_max_enum && a->arg_desc && strstr(a->arg_desc, "\n- ")) + gf_sys_format_help(helpout, help_flags, "\n"); } static void print_filter_single_opt(const GF_FilterRegister *reg, char *optname, GF_Filter *filter_inst) @@ -2263,8 +2729,10 @@ static void print_filter_single_opt(const GF_FilterRegister *reg, char *optname, u32 idx=0; Bool found = GF_FALSE; const GF_FilterArgs *args = NULL; - if (filter_inst) args = gf_filter_get_args(filter_inst); - else args = reg->args; + if (filter_inst) + args = gf_filter_get_args(filter_inst); + else if (reg) + args = reg->args; if (!args) return; @@ -2300,17 +2768,44 @@ static void print_filter_single_opt(const GF_FilterRegister *reg, char *optname, fprintf(stderr, "No such option %s for filter %s\n", optname, filter_inst ? gf_filter_get_name(filter_inst) : reg->name); } -static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF_Filter *filter_inst) +static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF_Filter *filter_inst, char *inst_name) { + u32 idx=0; const GF_FilterArgs *args = NULL; + const char *reg_name, *reg_desc; +#ifndef GPAC_DISABLE_DOC + const char *reg_help; +#endif + Bool jsmod_help = (argmode>GF_ARGMODE_ALL) ? GF_TRUE : GF_FALSE; + + if (filter_inst) { + reg_name = inst_name; + reg_desc = gf_filter_get_description(filter_inst); +#ifndef GPAC_DISABLE_DOC + reg_help = gf_filter_get_help(filter_inst); +#endif + } else if (reg) { + reg_name = reg->name; + reg_desc = reg->description; +#ifndef GPAC_DISABLE_DOC + reg_help = reg->help; +#endif + } else { + return; + } + + //happens on some meta filter or JS filters + if (!reg_desc) { + reg_desc = "No description available"; + } if (gen_doc==1) { char szName[1024]; - sprintf(szName, "%s.md", reg->name); + sprintf(szName, "%s.md", reg_name); if (gen_doc==1) { gf_fclose(helpout); helpout = gf_fopen(szName, "w"); - fprintf(helpout, "[**HOME**](Home) » [**Filters**](Filters) » %s\n", reg->description); + fprintf(helpout, "[**HOME**](Home) » [**Filters**](Filters) » %s\n", reg_desc); fprintf(helpout, "%s", auto_gen_md_warning); if (!sidebar_md) { @@ -2343,49 +2838,44 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF gf_free(sbbuf); } } + fprintf(sidebar_md, "[[%s (%s)|%s]] \n", reg_desc, reg_name, reg_name); #ifndef GPAC_DISABLE_DOC - if (reg->description) { - fprintf(sidebar_md, "[[%s (%s)|%s]] \n", reg->description, reg->name, reg->name); - } else { - fprintf(sidebar_md, "[[%s|%s]] \n", reg->name, reg->name); - } - if (!reg->help) { - fprintf(stderr, "filter %s without help, forbidden\n", reg->name); - exit(1); - } - if (!reg->description) { - fprintf(stderr, "filter %s without description, forbidden\n", reg->name); + + if (!reg_help) { + fprintf(stderr, "filter %s without help, forbidden\n", reg_name); exit(1); } #endif } #ifndef GPAC_DISABLE_DOC - gf_sys_format_help(helpout, help_flags, "# %s\n", reg->description); + gf_sys_format_help(helpout, help_flags, "# %s\n", reg_desc); #endif - gf_sys_format_help(helpout, help_flags, "Register name used to load filter: **%s**\n", reg->name); - if (reg->flags & GF_FS_REG_EXPLICIT_ONLY) { - gf_sys_format_help(helpout, help_flags, "This filter is not checked during graph resolution and needs explicit loading.\n"); + gf_sys_format_help(helpout, help_flags, "Register name used to load filter: **%s**\n", reg_name); + if (filter_inst) { + gf_sys_format_help(helpout, help_flags, "This is a JavaScript filter, not checked during graph resolution and needs explicit loading.\n"); } else { - gf_sys_format_help(helpout, help_flags, "This filter may be automatically loaded during graph resolution.\n"); - } - if (reg->flags & GF_FS_REG_REQUIRES_RESOLVER) { - gf_sys_format_help(helpout, help_flags, "This filter requires the graph resolver to be activated.\n"); - } - } else { - gf_sys_format_help(helpout, help_flags, "# %s\n", filter_inst ? gf_filter_get_name(filter_inst) : reg->name); - if (filter_inst) - gf_sys_format_help(helpout, help_flags, "Description: %s\n", gf_filter_get_description(filter_inst) ); - else { -#ifndef GPAC_DISABLE_DOC - if (reg->description) gf_sys_format_help(helpout, help_flags, "Description: %s\n", reg->description); -#endif - + if (reg->flags & GF_FS_REG_EXPLICIT_ONLY) { + gf_sys_format_help(helpout, help_flags, "This filter is not checked during graph resolution and needs explicit loading.\n"); + } else { + gf_sys_format_help(helpout, help_flags, "This filter may be automatically loaded during graph resolution.\n"); + } + if (reg->flags & GF_FS_REG_REQUIRES_RESOLVER) { + gf_sys_format_help(helpout, help_flags, "This filter requires the graph resolver to be activated.\n"); + } + if (reg->flags & GF_FS_REG_ALLOW_CYCLIC) { + gf_sys_format_help(helpout, help_flags, "Filters of this class can connect to each-other.\n"); + } } - - if (filter_inst) - gf_sys_format_help(helpout, help_flags, "Version: %s\n", gf_filter_get_version(filter_inst) ); - else { + } else if (!jsmod_help) { + gf_sys_format_help(helpout, help_flags, "# %s\n", reg_name); + gf_sys_format_help(helpout, help_flags, "Description: %s\n", reg_desc ); + + if (filter_inst) { + const char *version = gf_filter_get_version(filter_inst); + if (version) + gf_sys_format_help(helpout, help_flags, "Version: %s\n", version ); + } else { if (reg->version) { if (!strncmp(reg->version, "! ", 2)) { if (!gen_doc) @@ -2398,11 +2888,26 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF } if (filter_inst) { - gf_sys_format_help(helpout, help_flags, "Author: %s\n", gf_filter_get_author(filter_inst) ); - gf_sys_format_help(helpout, help_flags, "\n%s\n\n", gf_filter_get_help(filter_inst) ); - } else { + const char *str; + if (!jsmod_help) { + str = gf_filter_get_author(filter_inst); + if (str) + gf_sys_format_help(helpout, help_flags, "%s: %s\n", (str[0]=='-') ? "Configuration" : "Author", str ); + } + str = gf_filter_get_help(filter_inst); + if (str) + gf_sys_format_help(helpout, help_flags, "\n%s\n\n", str); + } else if (reg) { #ifndef GPAC_DISABLE_DOC - if (reg->author) gf_sys_format_help(helpout, help_flags, "Author: %s\n", reg->author); + if (reg->author) { + if (reg->author[0]=='-') { + if (! (help_flags & (GF_PRINTARG_MD|GF_PRINTARG_MAN))) { + gf_sys_format_help(helpout, help_flags, "Configuration: %s\n", reg->author); + } + } else { + gf_sys_format_help(helpout, help_flags, "Author: %s\n", reg->author); + } + } if (reg->help) { u32 hf = help_flags; if (gen_doc==1) hf |= GF_PRINTARG_ESCAPE_XML; @@ -2413,7 +2918,7 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF #endif } - if (argmode==GF_ARGMODE_EXPERT) { + if (reg && (argmode==GF_ARGMODE_EXPERT)) { if (reg->max_extra_pids==(u32) -1) gf_sys_format_help(helpout, help_flags, "Max Input PIDs: any\n"); else gf_sys_format_help(helpout, help_flags, "Max Input PIDs: %d\n", 1 + reg->max_extra_pids); @@ -2423,7 +2928,7 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF if (reg->flags & GF_FS_REG_CONFIGURE_MAIN_THREAD) gf_sys_format_help(helpout, help_flags, " ConfigureMainThread"); if (reg->flags & GF_FS_REG_HIDE_WEIGHT) gf_sys_format_help(helpout, help_flags, " HideWeight"); if (reg->flags & GF_FS_REG_REQUIRES_RESOLVER) gf_sys_format_help(helpout, help_flags, " RequireResolver"); - if (reg->flags & GF_FS_REG_DYNLIB) gf_sys_format_help(helpout, help_flags, " DynamicLib"); + if (reg->flags & GF_FS_REG_ALLOW_CYCLIC) gf_sys_format_help(helpout, help_flags, " CyclicAllowed"); if (reg->probe_url) gf_sys_format_help(helpout, help_flags, " URLMimeProber"); if (reg->probe_data) gf_sys_format_help(helpout, help_flags, " DataProber"); if (reg->reconfigure_output) gf_sys_format_help(helpout, help_flags, " ReconfigurableOutput"); @@ -2436,8 +2941,20 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF if (filter_inst) args = gf_filter_get_args(filter_inst); else args = reg->args; - if (args) { - u32 idx=0; + u32 nb_opts=0; + idx=0; + while (1) { + const GF_FilterArgs *a = & args[idx]; + if (!a || !a->arg_name) break; + idx++; + if (a->flags & GF_FS_ARG_HINT_HIDE) continue; + nb_opts++; + } + if (!nb_opts) + args = NULL; + + if (args && !jsmod_help) { + idx=0; if (gen_doc==1) { gf_sys_format_help(helpout, help_flags, "# Options \n"); } else { @@ -2485,8 +3002,9 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF u32 j=0; char szArg[100]; sprintf(szArg, " %s ", a->arg_name); - if (reg->help && strstr(reg->help, szArg)) { - fprintf(stderr, "\nWARNING: filter %s bad help, uses arg %s without link\n", reg->name, a->arg_name); + char *quoted = reg_help ? strstr(reg_help, szArg) : NULL; + if (quoted) { + fprintf(stderr, "\nWARNING: filter %s bad help, uses arg %s without link: \"... %s\"\n", reg_name, a->arg_name, quoted); exit(1); } while (1) { @@ -2494,25 +3012,45 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF if (!anarg || !anarg->arg_name) break; j++; if (a == anarg) continue; - if (reg->help && strstr(reg->help, szArg)) { - fprintf(stderr, "\nWARNING: filter %s bad description for argument %s, uses arg %s without link\n", reg->name, anarg->arg_name, a->arg_name); + if (reg_help && strstr(reg_help, szArg)) { + fprintf(stderr, "\nWARNING: filter %s bad description for argument %s, uses arg %s without link\n", reg_name, anarg->arg_name, a->arg_name); exit(1); } } - + if (a->min_max_enum) { //check format - if ((a->arg_type!=GF_PROP_UINT_LIST) && !(a->flags&GF_FS_ARG_META) && strchr(a->min_max_enum, '|') ) { - if (!strstr(a->arg_desc, "- ")) { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, missing list bullet \"- \"\n", reg->name, a->arg_name); + if ((a->arg_type!=GF_PROP_UINT_LIST) && !(a->flags&GF_FS_ARG_META) && strchr(a->min_max_enum, '|') && (!a->arg_default_val || strcmp(a->arg_default_val, "-1")) ) { + const char *a_val = a->min_max_enum; + while (a_val[0] == '|') a_val++; + if (strstr(a->arg_desc, "see filter ")) + a_val = NULL; + while (a_val) { + char szName[100]; + const char *a_sep = strchr(a_val, '|'); + u32 len = a_sep ? (u32)(a_sep - a_val) : (u32)strlen(a_val); + strcpy(szName, "- "); + strncat(szName, a_val, MIN(sizeof(szName)-3,len)); + szName[2+len]=0; + strcat(szName, ": "); + + if (!strstr(a->arg_desc, szName)) { + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, missing list bullet \"%s\"\n", reg_name, a->arg_name, szName); + exit(1); + } + if (!a_sep) break; + a_val = a_sep+1; + } + if (a_val && !strstr(a->arg_desc, "- ")) { + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, missing list bullet \"- \"\n", reg_name, a->arg_name); exit(1); } - if (strstr(a->arg_desc, ":\n")) { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should not use \":\\n\"\n", reg->name, a->arg_name); + if (a_val && strstr(a->arg_desc, ":\n")) { + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should not use \":\\n\"\n", reg_name, a->arg_name); exit(1); } } else if (!(a->flags&GF_FS_ARG_META) && strchr(a->arg_desc, '\n')) { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should not contain \"\\n\"\n", reg->name, a->arg_name); + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should not contain \"\\n\"\n", reg_name, a->arg_name); exit(1); } } @@ -2521,7 +3059,7 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF achar = a->arg_desc[strlen(a->arg_desc)-1]; if (achar == '\n') { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should not end with \"\\n\"\n", reg->name, a->arg_name); + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should not end with \"\\n\"\n", reg_name, a->arg_name); exit(1); } @@ -2529,29 +3067,33 @@ static void print_filter(const GF_FilterRegister *reg, GF_SysArgMode argmode, GF if ((achar >= 'A') && (achar <= 'Z')) { achar = a->arg_desc[1]; if ((achar < 'A') || (achar > 'Z')) { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should start with lowercase\n", reg->name, a->arg_name); + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, should start with lowercase\n", reg_name, a->arg_name); exit(1); } } if (a->arg_desc[0] == ' ') { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, first character should not be space\n", reg->name, a->arg_name); + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, first character should not be space\n", reg_name, a->arg_name); exit(1); } sep = strchr(a->arg_desc+1, ' '); if (sep) sep--; if (sep && (sep[0] == 's') && (sep[-1] != 's')) { - fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, first word should be infinitive\n", reg->name, a->arg_name); + fprintf(stderr, "\nWARNING: filter %s bad description format for arg %s, first word should be infinitive\n", reg_name, a->arg_name); exit(1); } } #endif } - } else { + } else if (!args) { gf_sys_format_help(helpout, help_flags, "No options\n"); } - if (reg->nb_caps) { - if (!gen_doc && (argmode==GF_ARGMODE_ALL)) { + if (!gen_doc && (argmode==GF_ARGMODE_ALL)) { + if (filter_inst) { + u32 nb_caps = 0; + const GF_FilterCapability *caps = gf_filter_get_caps(filter_inst, &nb_caps); + dump_caps(nb_caps, caps); + } else if (reg->nb_caps) { dump_caps(reg->nb_caps, reg->caps); } } @@ -2574,95 +3116,209 @@ static Bool strstr_nocase(const char *text, const char *subtext, u32 subtext_len return GF_FALSE; } +struct __jsenum_info +{ + GF_FilterSession *session; + GF_SysArgMode argmode; + Bool print_filter_info; + const char *path; + char *js_dir; +}; + +static Bool jsinfo_enum(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) +{ + struct __jsenum_info *jsi = (struct __jsenum_info *)cbck; + GF_Filter *f; + if (jsi->js_dir && strcmp(item_name, "init.js")) { + return GF_FALSE; + } + f = gf_fs_load_filter(jsi->session, item_path, NULL); + if (f) { + char szPath[GF_MAX_PATH]; + char *ext; + if (jsi->js_dir) { + strcpy(szPath, jsi->js_dir); + } else { + strcpy(szPath, item_name); + } + ext = gf_file_ext_start(szPath); + if (ext) ext[0] = 0; + if (jsi->print_filter_info || gen_doc) + print_filter(NULL, jsi->argmode, f, szPath); + else + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s: %s\n", szPath, gf_filter_get_description(f)); + } + return GF_FALSE; +} +static Bool jsinfo_dir_enum(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) +{ + char szPath[GF_MAX_PATH]; + struct __jsenum_info *jsi = (struct __jsenum_info *)cbck; + jsi->js_dir = item_name; + + strcpy(szPath, jsi->path); + strcat(szPath, item_name); + strcat(szPath, "/"); + gf_enum_directory(szPath, GF_FALSE, jsinfo_enum, jsi, ".js"); + jsi->js_dir = NULL; + return GF_FALSE; +} + static Bool print_filters(int argc, char **argv, GF_FilterSession *session, GF_SysArgMode argmode) { Bool found = GF_FALSE; + Bool print_all = GF_FALSE; char *fname = NULL; char *l_fname = NULL; u32 lf_len = 0; u32 i, count = gf_fs_filters_registers_count(session); if (!gen_doc && list_filters) gf_sys_format_help(helpout, help_flags, "Listing %d supported filters%s:\n", count, (list_filters==2) ? " including meta-filters" : ""); - for (i=0; iname, reg->description); +#else + gf_sys_format_help(helpout, help_flags, "%s (compiled without built-in doc)\n", reg->name); +#endif + } + } + found = GF_TRUE; + } + //print a specific filter info, browse args + else { + u32 k; + //all good to go, load filters + for (k=1; k<(u32) argc; k++) { + char *arg = argv[k]; + char *sepe; + Bool found_freg = GF_FALSE; + char *optname = NULL; + if (arg[0]=='-') continue; + + sepe = gf_file_basename(arg); + if (sepe) sepe = strchr(sepe, '.'); + if (sepe) { + if (!strncmp(sepe, ".js.", 4)) sepe = strchr(sepe+1, '.'); + else if (!strcmp(sepe, ".js")) sepe = NULL; if (sepe) { - if (!strncmp(sepe, ".js.", 4)) sepe = strchr(sepe+1, '.'); - else if (!strcmp(sepe, ".js")) sepe = NULL; - if (sepe) { - sepe[0] = 0; - optname = sepe+1; - } + sepe[0] = 0; + optname = sepe+1; } - fname = arg; - + } + fname = arg; + for (i=0; iname) ) { if (optname) print_filter_single_opt(reg, optname, NULL); else - print_filter(reg, argmode, NULL); - found = GF_TRUE; - } else { + print_filter(reg, argmode, NULL, NULL); + found_freg = GF_TRUE; + } + //search for name:*, also accept *:* + else { char *sepo = strchr(arg, ':'); - char *sepd = strchr(reg->name, ':'); - Bool patch_meta = GF_FALSE; - if (sepo && sepd) { - char *subf = strstr(reg->name, sepo+1); - if (subf) { - u32 slen = (u32) strlen(sepo+1); - if ((subf[slen]==0) || (subf[slen]==',')) - patch_meta = GF_TRUE; - } - } + if (!strcmp(arg, "*:*") || !strcmp(arg, "@:@") || (!sepo && (!strcmp(arg, "*") || !strcmp(arg, "@")) ) - || (sepo && (!strcmp(sepo, ":*") || !strcmp(sepo, ":@")) && !strncmp(reg->name, arg, 1+sepo - arg) ) - || patch_meta + || (sepo && (!strcmp(sepo, ":*") || !strcmp(sepo, ":@")) && !strncmp(reg->name, arg, 1+sepo - arg) ) ) { if (optname) print_filter_single_opt(reg, optname, NULL); else - print_filter(reg, argmode, NULL); - found = GF_TRUE; - break; + print_filter(reg, argmode, NULL, NULL); + found_freg = GF_TRUE; + if (!strcmp(arg, "*")) print_all = GF_TRUE; } - //quick shortcuts - else if (!strcmp(reg->name, "jsf") && (!strncmp(arg, "jsf:", 4) || strstr(arg, ".js")) ) { - GF_Filter *f = gf_fs_load_filter(session, arg, NULL); - if (f) { - if (optname) - print_filter_single_opt(reg, optname, f); - else - print_filter(reg, argmode, f); - found = GF_TRUE; - } + } + } + if (found_freg) { + found = GF_TRUE; + } else /*if (!strchr(arg, ':')) */ { + GF_SysArgMode _argmode = argmode; + char *js_opt = strchr(arg, ':'); + if (js_opt) { + js_opt[0] = 0; + gf_opts_set_key("temp", "gpac-js-help", js_opt+1); + _argmode = GF_ARGMODE_ALL+1; + } + //try to load the filter (JS) + GF_Filter *f = gf_fs_load_filter(session, arg, NULL); + const GF_FilterRegister *reg = f ? gf_filter_get_register(f) : NULL; + if (!reg || !(reg->flags & GF_FS_REG_SCRIPT)) + f = NULL; + + if (f) { + char *ext; + char szPath[GF_MAX_PATH]; + strcpy(szPath, gf_file_basename(arg) ); + ext = gf_file_ext_start(szPath); + if (ext) ext[0] = 0; + if (optname) { + print_filter_single_opt(NULL, optname, f); + } else { + print_filter(NULL, _argmode, f, szPath); } + found = GF_TRUE; + } + if (js_opt) { + js_opt[0] = ':'; + gf_opts_set_key("temp", "gpac-js-help", NULL); } - if (sepe) sepe[0] = '.'; } - } else { -#ifndef GPAC_DISABLE_DOC - gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s: %s\n", reg->name, reg->description); -#else - gf_sys_format_help(helpout, help_flags, "%s (compiled without built-in doc)\n", reg->name); -#endif - found = GF_TRUE; + if (sepe) sepe[0] = '.'; + } + } + + if (print_all || !print_filter_info || gen_doc) { + const char *js_dirs = gf_opts_get_key("core", "js-dirs"); + char szPath[GF_MAX_PATH]; + struct __jsenum_info jsi; + jsi.argmode = argmode; + jsi.session = session; + jsi.print_filter_info = print_filter_info; + + gf_log_set_tools_levels("console@error", GF_FALSE); + if (gf_opts_default_shared_directory(szPath)) { + strcat(szPath, "/scripts/jsf/"); + jsi.path = szPath; + gf_enum_directory(szPath, GF_FALSE, jsinfo_enum, &jsi, ".js"); + gf_enum_directory(szPath, GF_TRUE, jsinfo_dir_enum, &jsi, NULL); } + while (js_dirs && js_dirs[0]) { + char *sep = strchr(js_dirs, ','); + if (sep) { + u32 cplen = (u32) (sep-js_dirs); + if (cplen>=GF_MAX_PATH) cplen = GF_MAX_PATH-1; + strncpy(szPath, js_dirs, cplen); + szPath[cplen]=0; + js_dirs = sep+1; + } else { + strcpy(szPath, js_dirs); + } + //pre 1.1, $GJS was inserted by default + if (strcmp(szPath, "$GJS")) { + u32 len = (u32) strlen(szPath); + if (len && (szPath[len-1]!='/') && (szPath[len-1]!='\\')) + strcat(szPath, "/"); + gf_enum_directory(szPath, GF_FALSE, jsinfo_enum, &jsi, ".js"); + } + if (!sep) break; + } + return GF_TRUE; } + + if (found) return GF_TRUE; if (!fname) return GF_FALSE; if (!print_filter_info) return GF_FALSE; @@ -2685,7 +3341,7 @@ static Bool print_filters(int argc, char **argv, GF_FilterSession *session, GF_S if (argmode==GF_ARGMODE_EXPERT) { if (!arg->arg_desc || !strstr_nocase(arg->arg_desc, l_fname, lf_len)) continue; if (!found) { - GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("\"%s\" is mentionned in the following filters options:\n", fname)); + GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("\"%s\" is mentioned in the following filters options:\n", fname)); found = GF_TRUE; } gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s.%s \n", reg->name, arg->arg_name); @@ -2707,14 +3363,13 @@ static Bool print_filters(int argc, char **argv, GF_FilterSession *session, GF_S if (found) return GF_TRUE; - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("No such filter \"%s\"\n", fname)); gpac_suggest_filter(fname, GF_TRUE, GF_FALSE); return GF_FALSE; } -static void dump_all_props(void) +static void dump_all_props(char *pname) { - u32 i=0; + u32 i=0, pname_len = pname ? (u32) strlen(pname) : 0; const GF_BuiltInProperty *prop_info; if (gen_doc==1) { @@ -2726,22 +3381,26 @@ static void dump_all_props(void) for (i=GF_PROP_FORBIDEN+1; i=GF_PROP_LAST_NON_ENUM) && (i=GF_PROP_LAST_NON_ENUM) && (iname, pname)) {} + else if (gf_strnistr(prop_info->description, pname, pname_len)) {} + else continue; + } szFlags[0]=0; if (prop_info->flags & GF_PROP_FLAG_GSF_REM) strcat(szFlags, "D"); if (prop_info->flags & GF_PROP_FLAG_PCK) strcat(szFlags, "P"); @@ -2789,8 +3454,8 @@ static void dump_all_props(void) } ptype = gf_props_get_type_name(prop_info->data_type); gf_sys_format_help(helpout, help_flags, " (%s %s %s):", gf_4cc_to_str(prop_info->type), ptype, szFlags); - len = (u32) strlen(ptype); - while (len<6) { + len += (u32) strlen(ptype) + (u32) strlen(szFlags); + while (len<24) { gf_sys_format_help(helpout, help_flags, " "); len++; } @@ -2801,20 +3466,27 @@ static void dump_all_props(void) gf_sys_format_help(helpout, help_flags, "\n\tNames: %s\n\tFile extensions: %s", gf_pixel_fmt_all_names(), gf_pixel_fmt_all_shortnames() ); } else if (prop_info->data_type==GF_PROP_PCMFMT) { gf_sys_format_help(helpout, help_flags, "\n\tNames: %s\n\tFile extensions: %s", gf_audio_fmt_all_names(), gf_audio_fmt_all_shortnames() ); - } else if (prop_info->type==GF_PROP_PID_STREAM_TYPE) { - gf_sys_format_help(helpout, help_flags, "\n\tNames: %s\n\t", gf_stream_type_all_names() ); + } else if (gf_props_type_is_enum(prop_info->data_type)) { + gf_sys_format_help(helpout, help_flags, "\n\tNames: %s\n\t", gf_props_enum_all_names(prop_info->data_type) ); } gf_sys_format_help(helpout, help_flags, "\n"); } } if (gen_doc==1) { u32 idx=0; + u32 cicp; + u64 layout; + GF_PixelFormat pfmt; const char *name, *fileext, *desc; gf_sys_format_help(helpout, help_flags, "# Pixel formats\n"); - gf_sys_format_help(helpout, help_flags, "Name | File extensions | Description \n"); - gf_sys_format_help(helpout, help_flags, " --- | --- | --- \n"); - while ( gf_pixel_fmt_enum(&idx, &name, &fileext, &desc)) { - gf_sys_format_help(helpout, help_flags | GF_PRINTARG_NL_TO_BR, "%s | %s | %s \n", name, fileext, desc); + gf_sys_format_help(helpout, help_flags, "Name | File extensions | QT 4CC | Description \n"); + gf_sys_format_help(helpout, help_flags, " --- | --- | --- | --- \n"); + while ( (pfmt = gf_pixel_fmt_enum(&idx, &name, &fileext, &desc) )) { + const char *qtname = ""; + u32 qt_code = gf_pixel_fmt_to_qt_type(pfmt); + if (qt_code) qtname = gf_4cc_to_str(qt_code); + + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_NL_TO_BR, "%s | %s | %s | %s \n", name, fileext, qtname, desc); } idx=0; @@ -2845,8 +3517,19 @@ static void dump_all_props(void) idx++; } + + idx=0; + gf_sys_format_help(helpout, help_flags, "# CICP code points for audio channel layout\n"); + gf_sys_format_help(helpout, help_flags, " Name | Integer value | ChannelMask \n"); + gf_sys_format_help(helpout, help_flags, " --- | --- | --- \n"); + while ( (cicp = gf_audio_fmt_cicp_enum(idx, &name, &layout)) ) { + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_NL_TO_BR, "%s | %d | 0x%016"LLX_SUF" \n", name, cicp, layout); + idx++; + } + } else if (gen_doc==2) { - u32 idx=0; + u32 idx=0, cicp; + u64 layout; const char *name, *fileext, *desc; gf_sys_format_help(helpout, help_flags, "# Pixel formats\n"); while ( gf_pixel_fmt_enum(&idx, &name, &fileext, &desc)) { @@ -2871,6 +3554,13 @@ static void dump_all_props(void) gf_sys_format_help(helpout, help_flags | GF_PRINTARG_NL_TO_BR, ".TP\n.B %s\n%s\n", name, desc); idx++; } + + idx=0; + gf_sys_format_help(helpout, help_flags, "# Stream types\n"); + while ( (cicp = gf_audio_fmt_cicp_enum(idx, &name, &layout)) ) { + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_NL_TO_BR, ".TP\n.B %s (int %d)\nLayout 0x%016"LLX_SUF"\n", name, cicp, layout); + idx++; + } } } #include @@ -2884,6 +3574,18 @@ static void dump_all_colors(void) } } +static void dump_all_audio_cicp(void) +{ + u32 i=0, cicp; + const char *name; + u64 layout; + + while ((cicp = gf_audio_fmt_cicp_enum(i, &name, &layout)) ) { + gf_sys_format_help(helpout, help_flags|GF_PRINTARG_HIGHLIGHT_FIRST, "%s (%d): 0x%016"LLX_SUF"\n", name, cicp, layout); + i++; + } +} + static void dump_all_codec(GF_FilterSession *session) { GF_PropertyValue rawp, filep, stp; @@ -2893,8 +3595,8 @@ static void dump_all_codec(GF_FilterSession *session) u32 count = gf_fs_filters_registers_count(session); gf_sys_format_help(helpout, help_flags, "Codec support in filters, listed as `built_in_name[|variant] [FLAGS]: full_name (mime)` with possible FLAGS values:\n"); - gf_sys_format_help(helpout, help_flags, " - I: Raw format input (demux) support\n"); - gf_sys_format_help(helpout, help_flags, " - O: Raw format output (mux) support\n"); + gf_sys_format_help(helpout, help_flags, " - I: Raw format input (demultiplexer) support\n"); + gf_sys_format_help(helpout, help_flags, " - O: Raw format output (multiplexer) support\n"); gf_sys_format_help(helpout, help_flags, " - D: Decoder support\n"); gf_sys_format_help(helpout, help_flags, " - E: Encoder support\n"); gf_sys_format_help(helpout, help_flags, "\nNote: Raw output may still be possible even when no output serializer is given\n\n"); @@ -2921,7 +3623,7 @@ static void dump_all_codec(GF_FilterSession *session) cp.value.uint = gf_codecid_enum(cidx, &sname, &lname); cidx++; if (cp.value.uint == GF_CODECID_NONE) break; - if (cp.value.uint == GF_CODECID_RAW) continue; +// if (cp.value.uint == GF_CODECID_RAW) continue; if (!sname) break; stp.value.uint = gf_codecid_type(cp.value.uint); @@ -3203,7 +3905,7 @@ static Bool check_param_extension(char *szArg, int arg_idx, int argc, char **arg static Bool gpac_expand_alias_arg(char *param, char *prefix, char *suffix, int arg_idx, int argc, char **argv) { - char szArg[1024]; + char *alias_arg=NULL; char szSepList[2]; char *oparam = param; szSepList[0] = separator_set[SEP_LIST]; @@ -3213,7 +3915,8 @@ static Bool gpac_expand_alias_arg(char *param, char *prefix, char *suffix, int a Bool is_expand = param[0]=='+'; if (is_list || is_expand) param++; - strcpy(szArg, prefix); + + gf_dynstrcat(&alias_arg, prefix, NULL); while (param) { u32 idx=0; u32 last_idx=0; @@ -3227,6 +3930,7 @@ static Bool gpac_expand_alias_arg(char *param, char *prefix, char *suffix, int a if (diff>=idx) { if (sep) sep[0]=','; fprintf(stderr, "Bad usage for alias parameter %s: not enough parameters\n", oparam); + gf_free(alias_arg); return GF_FALSE; } idx -= diff; @@ -3248,6 +3952,7 @@ static Bool gpac_expand_alias_arg(char *param, char *prefix, char *suffix, int a u32 diff = atoi(lsep+3); if (diff>=last_idx) { fprintf(stderr, "Bad usage for alias parameter %s: not enough parameters\n", oparam); + gf_free(alias_arg); return GF_FALSE; } last_idx -= diff; @@ -3262,11 +3967,13 @@ static Bool gpac_expand_alias_arg(char *param, char *prefix, char *suffix, int a if (!idx) { if (sep) sep[0]=','; fprintf(stderr, "Bad format for alias parameter %s: cannot extract argument index\n", oparam); + gf_free(alias_arg); return GF_FALSE; } if ((int) idx + arg_idx >= argc) { if (sep) sep[0]=','; - fprintf(stderr, "Bad format for alias parameter %s: argment out of bounds (not enough paramteters?)\n", oparam); + fprintf(stderr, "Bad format for alias parameter %s: argument out of bounds (not enough paramteters?)\n", oparam); + gf_free(alias_arg); return GF_FALSE; } @@ -3278,19 +3985,22 @@ static Bool gpac_expand_alias_arg(char *param, char *prefix, char *suffix, int a gf_list_add(args_used, an_arg); if (is_expand) { - strcpy(szArg, prefix); - strcat(szArg, an_arg); - strcat(szArg, suffix); + gf_free(alias_arg); + alias_arg = NULL; + gf_dynstrcat(&alias_arg, prefix, NULL); + gf_dynstrcat(&alias_arg, an_arg, NULL); + gf_dynstrcat(&alias_arg, suffix, NULL); - Bool ok = check_param_extension(szArg, arg_idx, argc, argv); + Bool ok = check_param_extension(alias_arg, arg_idx, argc, argv); if (!ok) { if (sep) sep[0]=','; + gf_free(alias_arg); return GF_FALSE; } } else { - strcat(szArg, an_arg); + gf_dynstrcat(&alias_arg, an_arg, NULL); if (is_list && (idx #include #include +#include #include #include #include @@ -3358,6 +4103,7 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) { #ifdef GPAC_ENABLE_COVERAGE u32 ucs4_buf[4]; + u32 i; u8 utf8_buf[7]; void *mem = gf_calloc(4, sizeof(u32)); @@ -3368,6 +4114,14 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gpac_fsess_task_help(); //for coverage gf_dm_sess_last_error(NULL); gf_log_use_color(); + gf_4cc_parse("abcd"); + gf_gpac_abi_micro(); + gf_audio_fmt_get_layout_from_name("3/2.1"); + gf_audio_fmt_get_dolby_chanmap(4); + gf_itags_get_id3tag(1); + i=0; + gf_itags_enum_tags(&i, NULL, NULL, NULL); + GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[CoreUnitTests] performing tests\n")); utf8_buf[0] = 'a'; @@ -3503,6 +4257,7 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_lang_get_count(); gf_lang_get_2cc(2); GF_Blob b; + memset(&b, 0, sizeof(GF_Blob)); b.data = (u8 *) "test"; b.size = 5; char url[100]; @@ -3512,7 +4267,7 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_sys_profiler_set_callback(NULL, NULL); - gf_blob_get_data(url, &data, &size); + gf_blob_get(url, &data, &size, NULL); if (!data || strcmp((char *)data, "test")) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[CoreUnitTests] blob url parsing fail\n")); return 1; @@ -3525,12 +4280,13 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_sys_is_quiet(); gf_sys_get_argv(); gf_mx_get_num_locks(NULL); - sigint_catched = GF_TRUE; + signal_catched = GF_TRUE; #ifdef WIN32 gpac_sig_handler(CTRL_C_EVENT); #else gpac_sig_handler(SIGINT); + gpac_sig_handler(SIGTERM); #endif gf_mkdir("testdir"); @@ -3545,7 +4301,7 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_file_modification_time(url); gf_m2ts_probe_file(url); - gf_cleanup_dir("testdir"); + gf_dir_cleanup("testdir"); gf_rmdir("testdir"); //math.c not covered yet by our sample files @@ -3620,7 +4376,7 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_path_add_quadratic_to(path, 5, 5, 10, 0); gf_path_point_over(path, 4, 0); gf_path_del(path); - + //xml dom - to update once we find a way to integrate atsc demux in tests GF_DOMParser *dom = gf_xml_dom_new(); gf_xml_dom_parse_string(dom, "test"); @@ -3636,11 +4392,6 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_dm_set_data_rate(dm, 0); gf_dm_get_data_rate(dm); gf_dm_set_localcache_provider(dm, NULL, NULL); - - const DownloadedCacheEntry ent = gf_dm_add_cache_entry(dm, "http://localhost/test.dummy", "test", 4, 0, 0, "application/octet-string", GF_FALSE, 1); - - gf_dm_force_headers(dm, ent, "x-GPAC: test\r\n"); - gf_dm_sess_enum_headers(NULL, NULL, NULL, NULL);//this one is deactivated in test mode in httpin because of Date: header gf_dm_sess_abort(NULL); gf_dm_del(dm); @@ -3674,7 +4425,6 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_filter_post_task(NULL,NULL,NULL,NULL); - gf_filter_get_num_events_queued(NULL); gf_filter_get_arg_str(NULL, NULL, NULL); gf_filter_all_sinks_done(NULL); @@ -3700,6 +4450,7 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_filter_get_max_extra_input_pids(NULL); gf_filter_remove(NULL); gf_filter_reconnect_output(NULL); + gf_filter_pid_get_udta_flags(NULL); gf_audio_fmt_get_cicp_layout(2, 1, 1); gf_audio_fmt_get_layout_from_cicp(3); @@ -3714,9 +4465,9 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_odf_desc_del((GF_Descriptor *) txtc); //stuff only used by vtbdec - gf_media_hevc_read_pps_bs(NULL, NULL); - gf_media_hevc_read_sps_bs(NULL, NULL); - gf_media_hevc_read_vps_bs(NULL, NULL); + gf_hevc_read_pps_bs(NULL, NULL); + gf_hevc_read_sps_bs(NULL, NULL); + gf_hevc_read_vps_bs(NULL, NULL); gf_mpegv12_get_config(NULL, 0, NULL); //hinting stuff @@ -3739,6 +4490,17 @@ static u32 gpac_unit_tests(GF_MemTrackerType mem_track) gf_isom_get_media_time(NULL, 0, 0, NULL); gf_isom_get_sample_description_index(NULL, 0, 0); + gf_sg_has_scripting(); + gf_node_get_proto_root(NULL); + gf_node_proto_is_grouping(NULL); + gf_sg_proto_get_id(NULL); + gf_sg_proto_instance_set_ised(NULL, 0, NULL, 0); + + gf_audio_fmt_to_isobmf(0); + gf_pixel_fmt_probe(0, NULL); + gf_net_ntp_to_utc(0); + gf_sys_profiler_sampling_enabled(); + #endif return 0; @@ -3756,7 +4518,7 @@ static Bool revert_cache_file(void *cbck, char *item_name, char *item_path, GF_F u32 i, len, dir_len=0, k=0; char *dst_name; char *sep; - + sep = strstr(item_path, "gpac_cache_"); if (sep) { sep[0] = 0; @@ -3986,7 +4748,7 @@ static const char *make_fileio(const char *inargs, const char **out_arg, Bool is { FileIOCtx *ioctx; GF_FileIO *fio; - char *sep = (char *) gf_url_colon_suffix(inargs); + char *sep = (char *) gf_url_colon_suffix(inargs, separator_set[1]); *out_arg = NULL; if (sep) sep[0] = 0; @@ -4025,7 +4787,7 @@ static void cleanup_file_io() GF_FileIO *gfio = gf_list_pop_back(all_gfio_defined); FileIOCtx *ioctx = gf_fileio_get_udta(gfio); gf_fileio_del(gfio); - + if (ioctx->filep) { fprintf(stderr, "Warning: file IO for %s still opened!\n", ioctx->path); gf_fclose(ioctx->filep); @@ -4037,3 +4799,49 @@ static void cleanup_file_io() all_gfio_defined = NULL; } +static GF_Err cust_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) +{ + GF_FilterEvent evt; + if (is_remove) return GF_OK; + + GF_FEVT_INIT(evt, GF_FEVT_PLAY, pid); + gf_filter_pid_send_event(pid, &evt); + gf_filter_pid_set_framing_mode(pid, GF_TRUE); + return GF_OK; +} +static GF_Err cust_process(GF_Filter *filter) +{ + u32 i; + for (i=0; i +#include +#include + extern u32 swf_flags; extern Float swf_flatten_angle; extern GF_FileType get_file_type_by_ext(char *inName); extern u32 fs_dump_flags; +extern Bool dump_check_xml; void scene_coding_log(void *cbk, GF_LOG_Level log_level, GF_LOG_Tool log_tool, const char *fmt, va_list vlist); -void PrintLanguages() + +#ifdef GPAC_DISABLE_LOG +void mp4box_log(const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + vfprintf(stderr, fmt, vlist); + fflush(stderr); + va_end(vl); +} +#endif + + +u32 PrintLanguages(char *val, u32 opt) { u32 i=0, count = gf_lang_get_count(); fprintf(stderr, "Supported ISO 639 languages and codes:\n\n"); @@ -71,6 +88,7 @@ void PrintLanguages() fprintf(stderr, "%s (%s - %s)\n", gf_lang_get_name(i), gf_lang_get_3cc(i), gf_lang_get_2cc(i)); } } + return 1; } static const char *GetLanguage(char *lcode) @@ -88,7 +106,7 @@ GF_Err dump_isom_cover_art(GF_ISOFile *file, char *inName, Bool is_final_name) GF_Err e = gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_COVER_ART, &tag, &tag_len); if (e!=GF_OK) { if (e==GF_URL_ERROR) { - fprintf(stderr, "No cover art found\n"); + M4_LOG(GF_LOG_WARNING, ("No cover art found\n")); return GF_OK; } return e; @@ -103,7 +121,7 @@ GF_Err dump_isom_cover_art(GF_ISOFile *file, char *inName, Bool is_final_name) } t = gf_fopen(szName, "wb"); if (!t) { - fprintf(stderr, "Failed to open %s for dumping\n", szName); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szName)); return GF_IO_ERR; } } else { @@ -144,7 +162,7 @@ GF_Err dump_isom_scene(char *file, char *inName, Bool is_final_name, GF_SceneDum load.isom = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL); if (!load.isom) { e = gf_isom_last_error(NULL); - fprintf(stderr, "Error opening file: %s\n", gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Error opening file: %s\n", gf_error_to_string(e))); gf_sm_del(ctx); gf_sg_del(sg); return e; @@ -157,15 +175,15 @@ GF_Err dump_isom_scene(char *file, char *inName, Bool is_final_name, GF_SceneDum #ifndef GPAC_DISABLE_MEDIA_IMPORT if (load.isom) { GF_Fraction _frac = {0,0}; - e = import_file(load.isom, file, 0, _frac, 0, NULL, NULL, 0); + e = import_file(load.isom, file, 0, _frac, 0, NULL, NULL, NULL, 0); } else #else - fprintf(stderr, "Warning: GPAC was compiled without Media Import support\n"); + M4_LOG(GF_LOG_WARNING, ("Warning: GPAC was compiled without Media Import support\n")); #endif e = gf_isom_last_error(NULL); if (e) { - fprintf(stderr, "Error importing file: %s\n", gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Error importing file: %s\n", gf_error_to_string(e))); gf_sm_del(ctx); gf_sg_del(sg); if (load.isom) gf_isom_delete(load.isom); @@ -201,7 +219,7 @@ GF_Err dump_isom_scene(char *file, char *inName, Bool is_final_name, GF_SceneDum gf_sm_del(ctx); gf_sg_del(sg); - if (e) fprintf(stderr, "Error loading scene: %s\n", gf_error_to_string(e)); + if (e) M4_LOG(GF_LOG_ERROR, ("Error loading scene: %s\n", gf_error_to_string(e))); if (load.isom) gf_isom_delete(load.isom); return e; } @@ -359,7 +377,7 @@ void dump_isom_scene_stats(char *file, char *inName, Bool is_final_name, u32 sta if (get_file_type_by_ext(file) == 1) { load.isom = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL); if (!load.isom) { - fprintf(stderr, "Cannot open file: %s\n", gf_error_to_string(gf_isom_last_error(NULL))); + M4_LOG(GF_LOG_ERROR, ("Cannot open file: %s\n", gf_error_to_string(gf_isom_last_error(NULL)))); gf_sm_del(ctx); gf_sg_del(scene_graph); return; @@ -376,7 +394,7 @@ void dump_isom_scene_stats(char *file, char *inName, Bool is_final_name, u32 sta if (!is_final_name) strcat(szBuf, "_stat.xml"); dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szBuf)); return; } close = 1; @@ -460,7 +478,7 @@ exit: gf_sg_del(scene_graph); if (load.isom) gf_isom_delete(load.isom); if (e) { - fprintf(stderr, "%s\n", gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Stats error: %s\n", gf_error_to_string(e))); } else { fprintf(dump, "\n"); } @@ -544,7 +562,7 @@ static void do_print_node(GF_Node *node, GF_SceneGraph *sg, const char *name, u3 char szField[1024]; u32 tfirst, tlast; if (gf_node_get_field_by_name(node, szField, &f) != GF_OK) { - fprintf(stderr, "Field %s is not a member of node %s\n", szField, name); + M4_LOG(GF_LOG_ERROR, ("Field %s is not a member of node %s\n", szField, name)); return; } fprintf(stderr, "Allowed nodes in %s.%s:\n", name, szField); @@ -645,11 +663,11 @@ static void do_print_node(GF_Node *node, GF_SceneGraph *sg, const char *name, u3 #endif -void PrintNode(const char *name, u32 graph_type) +u32 PrintNode(const char *name, u32 graph_type) { #ifdef GPAC_DISABLE_VRML - fprintf(stderr, "VRML/MPEG-4/X3D scene graph is disabled in this build of GPAC\n"); - return; + M4_LOG(GF_LOG_ERROR, ("VRML/MPEG-4/X3D scene graph is disabled in this build of GPAC\n")); + return 2; #else const char *std_name; GF_Node *node; @@ -670,16 +688,16 @@ void PrintNode(const char *name, u32 graph_type) tag = gf_node_x3d_type_by_class_name(name); std_name = "X3D"; #else - fprintf(stderr, "X3D node printing is not supported (X3D support disabled)\n"); - return; + M4_LOG(GF_LOG_ERROR, ("X3D node printing is not supported (X3D support disabled)\n")); + return 2; #endif } else { tag = gf_node_mpeg4_type_by_class_name(name); std_name = "MPEG4"; } if (!tag) { - fprintf(stderr, "Unknown %s node %s\n", std_name, name); - return; + M4_LOG(GF_LOG_ERROR, ("Unknown %s node %s\n", std_name, name)); + return 2; } sg = gf_sg_new(); @@ -687,42 +705,49 @@ void PrintNode(const char *name, u32 graph_type) gf_node_register(node, NULL); name = gf_node_get_class_name(node); if (!node) { - fprintf(stderr, "Node %s not supported in current built\n", name); - return; + M4_LOG(GF_LOG_ERROR, ("Node %s not supported in current built\n", name)); + return 2; } do_print_node(node, sg, name, graph_type, is_nodefield, GF_FALSE); gf_node_unregister(node, NULL); gf_sg_del(sg); #endif /*GPAC_DISABLE_VRML*/ + return 1; } -void PrintBuiltInNodes(u32 graph_type, Bool dump_nodes) +u32 PrintBuiltInNodes(char *arg_val, u32 dump_type) { #if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_SVG) GF_SceneGraph *sg; u32 i, nb_in, nb_not_in, start_tag, end_tag; + u32 graph_type; + Bool dump_nodes = ((dump_type==1) || (dump_type==3)) ? 1 : 0; + + if (dump_type==4) graph_type = 2; + else if ((dump_type==2) || (dump_type==3)) graph_type = 1; + else graph_type = 0; if (graph_type==1) { #if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) start_tag = GF_NODE_RANGE_FIRST_X3D; end_tag = TAG_LastImplementedX3D; #else - fprintf(stderr, "X3D scene graph disabled in this build of GPAC\n"); - return; + M4_LOG(GF_LOG_ERROR, ("X3D scene graph disabled in this build of GPAC\n")); + return 2; #endif } else if (graph_type==2) { #ifdef GPAC_DISABLE_SVG - fprintf(stderr, "SVG scene graph disabled in this build of GPAC\n"); - return; + M4_LOG(GF_LOG_ERROR, ("SVG scene graph disabled in this build of GPAC\n")); + return 2; #else start_tag = GF_NODE_RANGE_FIRST_SVG; end_tag = GF_NODE_RANGE_LAST_SVG; #endif } else { #ifdef GPAC_DISABLE_VRML - fprintf(stderr, "VRML/MPEG-4 scene graph disabled in this build of GPAC\n"); - return; + M4_LOG(GF_LOG_ERROR, ("VRML/MPEG-4 scene graph disabled in this build of GPAC\n")); + return 2; #else start_tag = GF_NODE_RANGE_FIRST_MPEG4; end_tag = TAG_LastImplementedMPEG4; @@ -765,19 +790,24 @@ void PrintBuiltInNodes(u32 graph_type, Bool dump_nodes) if (dump_nodes) { for (i=GF_SG_VRML_SFBOOL; i\n"); //index 0 is our internal unknown box handler for (i=1; i\n"); + return 1; } #if !defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_ISOM_DUMP) @@ -810,7 +841,7 @@ void dump_isom_rtp(GF_ISOFile *file, char *inName, Bool is_final_name) if (!is_final_name) strcat(szBuf, "_rtp.xml"); dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s\n", szBuf)); return; } } else { @@ -862,7 +893,7 @@ void dump_isom_timestamps(GF_ISOFile *file, char *inName, Bool is_final_name, u3 if (!is_final_name) strcat(szBuf, "_ts.txt"); dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s\n", szBuf)); return; } } else { @@ -961,7 +992,9 @@ void dump_isom_timestamps(GF_ISOFile *file, char *inName, Bool is_final_name, u3 if (timings) gf_free(timings); if (inName) gf_fclose(dump); - if (has_ctts_error) fprintf(stderr, "\tFile has CTTS table errors\n"); + if (has_ctts_error) { + M4_LOG(GF_LOG_ERROR, ("\tFile has CTTS table errors\n")); + } } @@ -980,33 +1013,32 @@ static u32 read_nal_size_hdr(u8 *ptr, u32 nalh_size) } #ifndef GPAC_DISABLE_AV_PARSERS -void gf_inspect_dump_nalu(FILE *dump, u8 *ptr, u32 ptr_size, Bool is_svc, HEVCState *hevc, AVCState *avc, u32 nalh_size, Bool dump_crc, Bool is_encrypted); +void gf_inspect_dump_nalu(FILE *dump, u8 *ptr, u32 ptr_size, Bool is_svc, HEVCState *hevc, AVCState *avc, VVCState *vvc, u32 nalh_size, Bool dump_crc, Bool is_encrypted); #endif -static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, u32 dump_flags) +static GF_Err dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, u32 dump_flags) { u32 i, j, count, nb_descs, track, nalh_size, timescale, cur_extract_mode; + GF_Err e=GF_OK; s32 countRef; Bool is_adobe_protected = GF_FALSE; Bool is_cenc_protected = GF_FALSE; Bool is_hevc = GF_FALSE; + Bool is_vvc = GF_FALSE; #ifndef GPAC_DISABLE_AV_PARSERS - AVCState avc; - HEVCState hevc; + AVCState *avc_state = NULL; + HEVCState *hevc_state = NULL; + VVCState *vvc_state = NULL; #endif GF_AVCConfig *avccfg, *svccfg; GF_HEVCConfig *hevccfg, *lhvccfg; - GF_AVCConfigSlot *slc; + GF_VVCConfig *vvccfg; + GF_NALUFFParam *slc; Bool has_svcc = GF_FALSE; track = gf_isom_get_track_by_id(file, trackID); -#ifndef GPAC_DISABLE_AV_PARSERS - memset(&avc, 0, sizeof(AVCState)); - memset(&hevc, 0, sizeof(HEVCState)); -#endif - count = gf_isom_get_sample_count(file, track); timescale = gf_isom_get_media_timescale(file, track); @@ -1015,8 +1047,8 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump nb_descs = gf_isom_get_sample_description_count(file, track); if (!nb_descs) { - fprintf(stderr, "Error: Track #%d has no sample description so is likely not NALU-based!\n", trackID); - return; + M4_LOG(GF_LOG_ERROR, ("Error: Track #%d has no sample description so is likely not NALU-based!\n", trackID)); + return GF_BAD_PARAM; } fprintf(dump, "\n", trackID, count, timescale); @@ -1029,8 +1061,7 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump for (i=0; isize);\ - gf_inspect_dump_nalu(dump, (u8 *) slc->data, slc->size, _is_svc, is_hevc ? &hevc : NULL, &avc, nalh_size, (dump_flags&1) ? GF_TRUE : GF_FALSE, GF_FALSE);\ - fprintf(dump, "/>\n");\ + gf_inspect_dump_nalu(dump, (u8 *) slc->data, slc->size, _is_svc, is_hevc ? hevc_state : NULL, avc_state, is_vvc ? vvc_state : NULL, nalh_size, (dump_flags&1) ? GF_TRUE : GF_FALSE, GF_FALSE);\ }\ fprintf(dump, " \n", name);\ }\ @@ -1061,9 +1092,27 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump mvccfg = gf_isom_mvc_config_get(file, track, j+1); hevccfg = gf_isom_hevc_config_get(file, track, j+1); lhvccfg = gf_isom_lhvc_config_get(file, track, j+1); + vvccfg = gf_isom_vvc_config_get(file, track, j+1); is_svc = (svccfg!=NULL) ? 1:0; + if (hevccfg || lhvccfg) { + is_hevc = 1; +#ifndef GPAC_DISABLE_AV_PARSERS + GF_SAFEALLOC(hevc_state, HEVCState) +#endif + } else if (vvccfg) { + is_vvc = 1; +#ifndef GPAC_DISABLE_AV_PARSERS + GF_SAFEALLOC(vvc_state, VVCState) +#endif + } else if (avccfg || svccfg || mvccfg) { +#ifndef GPAC_DISABLE_AV_PARSERS + GF_SAFEALLOC(avc_state, AVCState) +#endif + } + + //for tile tracks the hvcC is stored in the 'tbas' track if (!hevccfg && gf_isom_get_reference_count(file, track, GF_ISOM_REF_TBAS)) { u32 tk = 0; @@ -1073,9 +1122,9 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump fprintf(dump, " \n"); - if (!avccfg && !svccfg && !hevccfg && !lhvccfg) { - fprintf(stderr, "Error: Track #%d is not NALU-based!\n", trackID); - return; + if (!avccfg && !svccfg && !hevccfg && !lhvccfg && !vvccfg) { + M4_LOG(GF_LOG_ERROR, ("Error: Track #%d is not NALU or OBU based!\n", trackID)); + return GF_BAD_PARAM; } if (avccfg) { @@ -1098,9 +1147,8 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump if (hevccfg) { u32 idx; nalh_size = hevccfg->nal_unit_size; - is_hevc = 1; for (idx=0; idxparam_array); idx++) { - GF_HEVCParamArray *ar = gf_list_get(hevccfg->param_array, idx); + GF_NALUFFParamArray *ar = gf_list_get(hevccfg->param_array, idx); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { DUMP_ARRAY(ar->nalus, "HEVCSPS", "hvcC", 0) } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { @@ -1112,12 +1160,27 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump } } } + if (vvccfg) { + u32 idx; + nalh_size = vvccfg->nal_unit_size; + for (idx=0; idxparam_array); idx++) { + GF_NALUFFParamArray *ar = gf_list_get(vvccfg->param_array, idx); + if (ar->type==GF_VVC_NALU_SEQ_PARAM) { + DUMP_ARRAY(ar->nalus, "VVCSPS", "vvcC", 0) + } else if (ar->type==GF_VVC_NALU_PIC_PARAM) { + DUMP_ARRAY(ar->nalus, "VVCPPS", "vvcC", 0) + } else if (ar->type==GF_VVC_NALU_VID_PARAM) { + DUMP_ARRAY(ar->nalus, "VVCVPS", "vvcC", 0) + } else { + DUMP_ARRAY(ar->nalus, "VVCUnknownPS", "vvcC", 0) + } + } + } if (lhvccfg) { u32 idx; nalh_size = lhvccfg->nal_unit_size; - is_hevc = 1; for (idx=0; idxparam_array); idx++) { - GF_HEVCParamArray *ar = gf_list_get(lhvccfg->param_array, idx); + GF_NALUFFParamArray *ar = gf_list_get(lhvccfg->param_array, idx); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { DUMP_ARRAY(ar->nalus, "HEVCSPS", "lhcC", 0) } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { @@ -1137,6 +1200,7 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump has_svcc = GF_TRUE; } if (hevccfg) gf_odf_hevc_cfg_del(hevccfg); + if (vvccfg) gf_odf_vvc_cfg_del(vvccfg); if (lhvccfg) gf_odf_hevc_cfg_del(lhvccfg); } @@ -1169,8 +1233,8 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump u8 *ptr; GF_ISOSample *samp = gf_isom_get_sample(file, track, i+1, &di); if (!samp) { - fprintf(dump, "\n", i+1); - continue; + e = gf_isom_last_error(file); + break; } dts = samp->DTS; cts = dts + (s32) samp->CTS_Offset; @@ -1204,6 +1268,10 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump } } while (size) { + if (size\n", idx, nal_size, size); + break; + } nal_size = read_nal_size_hdr(ptr, nalh_size); ptr += nalh_size; @@ -1215,15 +1283,16 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump #ifndef GPAC_DISABLE_AV_PARSERS Bool is_encrypted = 0; if (is_cenc_protected) { - GF_Err e = gf_isom_get_sample_cenc_info(file, track, i + 1, &is_encrypted, NULL, NULL, NULL, NULL, NULL, NULL); + GF_Err e = gf_isom_get_sample_cenc_info(file, track, i + 1, &is_encrypted, NULL, NULL, NULL, NULL); if (e != GF_OK) { fprintf(dump, "dump_msg=\"Error %s while fetching encryption info for sample, assuming sample is encrypted\" ", gf_error_to_string(e) ); is_encrypted = GF_TRUE; } } - gf_inspect_dump_nalu(dump, ptr, nal_size, has_svcc ? 1 : 0, is_hevc ? &hevc : NULL, &avc, nalh_size, dump_flags, is_encrypted); -#endif + gf_inspect_dump_nalu(dump, ptr, nal_size, has_svcc ? 1 : 0, hevc_state, avc_state, vvc_state, nalh_size, dump_flags, is_encrypted); +#else fprintf(dump, "/>\n"); +#endif } idx++; ptr+=nal_size; @@ -1239,22 +1308,30 @@ static void dump_isom_nal_ex(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump fprintf(dump, "\n"); gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode); + +#ifndef GPAC_DISABLE_AV_PARSERS + if (hevc_state) gf_free(hevc_state); + if (vvc_state) gf_free(vvc_state); + if (avc_state) gf_free(avc_state); +#endif + + return e; } -static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, Bool dump_crc); -static void dump_qt_prores(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, Bool dump_crc); +static GF_Err dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, Bool dump_crc); +static GF_Err dump_qt_prores(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, Bool dump_crc); -void dump_isom_nal(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, Bool is_final_name, u32 dump_flags) +GF_Err dump_isom_nal(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, Bool is_final_name, u32 dump_flags) { + char szFileName[GF_MAX_PATH]; Bool is_av1 = GF_FALSE; Bool is_prores = GF_FALSE; FILE *dump; if (inName) { GF_ESD* esd; - char szBuf[GF_MAX_PATH]; - strcpy(szBuf, inName); + strcpy(szFileName, inName); u32 track = gf_isom_get_track_by_id(file, trackID); esd = gf_isom_get_esd(file, track, 1); @@ -1279,38 +1356,54 @@ void dump_isom_nal(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, Bool i } if (esd) gf_odf_desc_del((GF_Descriptor*)esd); - if (!is_final_name) sprintf(szBuf, "%s_%d_%s.xml", inName, trackID, is_av1 ? "obu" : "nalu"); - dump = gf_fopen(szBuf, "wt"); + if (!is_final_name) sprintf(szFileName, "%s_%d_%s.xml", inName, trackID, is_av1 ? "obu" : "nalu"); + dump = gf_fopen(szFileName, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s for dumping\n", szBuf); - return; + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szFileName)); + return GF_URL_ERROR; } } else { dump = stdout; } + GF_Err e = GF_OK; if (is_av1) - dump_isom_obu(file, trackID, dump, dump_flags); + e = dump_isom_obu(file, trackID, dump, dump_flags); else if (is_prores) - dump_qt_prores(file, trackID, dump, dump_flags); + e = dump_qt_prores(file, trackID, dump, dump_flags); else - dump_isom_nal_ex(file, trackID, dump, dump_flags); + e = dump_isom_nal_ex(file, trackID, dump, dump_flags); if (inName) gf_fclose(dump); + + if (!e && dump_check_xml) { + if (inName) { + GF_DOMParser *xml_parser = gf_xml_dom_new(); + GF_Err e = gf_xml_dom_parse(xml_parser, szFileName, NULL, NULL); + if (e) { + fprintf(stderr, "Failed to parse XML dump %s: line %d: %s\n", szFileName, gf_xml_dom_get_line(xml_parser), gf_xml_dom_get_error(xml_parser) ); + } + gf_xml_dom_del(xml_parser); + } else { + fprintf(stderr, "Cannot check XML for dump on stdout\n"); + } + } + return e; } #ifndef GPAC_DISABLE_AV_PARSERS void gf_inspect_dump_obu(FILE *dump, AV1State *av1, u8 *obu, u64 obu_length, ObuType obu_type, u64 obu_size, u32 hdr_size, Bool dump_crc); #endif -static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, Bool dump_crc) +static GF_Err dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, Bool dump_crc) { + GF_Err e = GF_OK; #ifndef GPAC_DISABLE_AV_PARSERS u32 i, count, track, timescale; AV1State av1; - ObuType obu_type; - u64 obu_size; - u32 hdr_size; + ObuType obu_type = 0; + u64 obu_size = 0; + u32 hdr_size = 0; GF_BitStream *bs; u32 idx; @@ -1319,8 +1412,8 @@ static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, B gf_av1_init_state(&av1); av1.config = gf_isom_av1_config_get(file, track, 1); if (!av1.config) { - fprintf(stderr, "Error: Track #%d is not AV1!\n", trackID); - return; + M4_LOG(GF_LOG_ERROR, ("Error: Track #%d is not AV1!\n", trackID)); + return GF_ISOM_INVALID_FILE; } count = gf_isom_get_sample_count(file, track); @@ -1333,7 +1426,12 @@ static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, B for (i=0; iobu_array); i++) { GF_AV1_OBUArrayEntry *obu = gf_list_get(av1.config->obu_array, i); bs = gf_bs_new(obu->obu, (u32) obu->obu_length, GF_BITSTREAM_READ); - gf_media_aom_av1_parse_obu(bs, &obu_type, &obu_size, &hdr_size, &av1); + e = gf_av1_parse_obu(bs, &obu_type, &obu_size, &hdr_size, &av1); + if (eobu, obu->obu_length, obu_type, obu_size, hdr_size, dump_crc); gf_bs_del(bs); } @@ -1341,14 +1439,15 @@ static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, B fprintf(dump, " \n"); + e = GF_OK; for (i=0; i\n", i+1); - continue; + e = gf_isom_last_error(file); + break; } dts = samp->DTS; cts = dts + (s32) samp->CTS_Offset; @@ -1362,7 +1461,9 @@ static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, B bs = gf_bs_new(ptr, size, GF_BITSTREAM_READ); while (size) { - gf_media_aom_av1_parse_obu(bs, &obu_type, &obu_size, &hdr_size, &av1); + e = gf_av1_parse_obu(bs, &obu_type, &obu_size, &hdr_size, &av1); + if (e size) { fprintf(dump, " \n", idx, (u32) obu_size, size); break; @@ -1377,6 +1478,8 @@ static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, B gf_isom_sample_del(&samp); fprintf(dump, "\n"); + + if (e\n"); @@ -1385,10 +1488,12 @@ static void dump_isom_obu(GF_ISOFile *file, GF_ISOTrackID trackID, FILE *dump, B if (av1.config) gf_odf_av1_cfg_del(av1.config); gf_av1_reset_state(&av1, GF_TRUE); #endif + return e; } -static void dump_qt_prores(GF_ISOFile *file, u32 trackID, FILE *dump, Bool dump_crc) +static GF_Err dump_qt_prores(GF_ISOFile *file, u32 trackID, FILE *dump, Bool dump_crc) { + GF_Err e = GF_OK; #ifndef GPAC_DISABLE_AV_PARSERS u32 i, count, track, timescale; @@ -1404,8 +1509,8 @@ static void dump_qt_prores(GF_ISOFile *file, u32 trackID, FILE *dump, Bool dump_ u64 dts, cts; GF_ISOSample *samp = gf_isom_get_sample(file, track, i+1, NULL); if (!samp) { - fprintf(dump, "\n", i+1); - continue; + e = gf_isom_last_error(file); + break; } dts = samp->DTS; cts = dts + (s32) samp->CTS_Offset; @@ -1425,6 +1530,7 @@ static void dump_qt_prores(GF_ISOFile *file, u32 trackID, FILE *dump, Bool dump_ } fprintf(dump, "\n"); #endif + return e; } void dump_isom_saps(GF_ISOFile *file, GF_ISOTrackID trackID, u32 dump_saps_mode, char *inName, Bool is_final_name) @@ -1440,7 +1546,7 @@ void dump_isom_saps(GF_ISOFile *file, GF_ISOTrackID trackID, u32 dump_saps_mode, if (!is_final_name) sprintf(szBuf, "%s_%d_cues.xml", inName, trackID); dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szBuf)); return; } } else { @@ -1507,6 +1613,179 @@ void dump_isom_saps(GF_ISOFile *file, GF_ISOTrackID trackID, u32 dump_saps_mode, if (inName) gf_fclose(dump); } + +typedef struct +{ + u32 track_num; + u32 chunk_num; + u32 first_sample_num; + u32 timescale; + u32 sample_per_chunk; + u64 chunk_offset; + u64 size; +} ChunkInfo; + +static s32 sort_chunk(const void* e1, const void* e2) +{ + const ChunkInfo *p1 = e1; + const ChunkInfo *p2 = e2; + + if (p1->chunk_offset < p2->chunk_offset) return -1; + if (p1->chunk_offset > p2->chunk_offset) return 1; + return 0; +} + +void dump_isom_chunks(GF_ISOFile *file, char *inName, Bool is_final_name) +{ + u32 i, count, nb_chunks_total, cur; + FILE *dump; + Bool dump_stsd = 0; + u32 dump_hm = 0; + u64 prev_time = 0; + u64 unused_space = 0; + u64 prev_chunk_end = 0; + Bool do_prog=GF_TRUE; + ChunkInfo *all_chunks; + + if (inName) { + char szBuf[1024]; + strcpy(szBuf, inName); + if (!is_final_name) strcat(szBuf, "_chunks.txt"); + dump = gf_fopen(szBuf, "wt"); + if (!dump) { + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szBuf)); + return; + } + } else { + dump = stdout; + do_prog = GF_FALSE; + } + + count = gf_isom_get_track_count(file); + nb_chunks_total = 0; + for (i=0; i 3600 * ts) dump_hm = 2; + else if (dur > 60 * ts) dump_hm = 1; + + if (nb_chunks>1) { + csize = gf_isom_get_constant_sample_size(file, i+1); + if (csize) { + gf_isom_enable_raw_pack(file, i+1, 1024); + csize = gf_isom_get_constant_sample_size(file, i+1); + } + } + c1 = c2 = 0; + for (j=0; jtrack_num = i+1; + ci->chunk_num = j+1; + ci->chunk_offset = offset; + ci->first_sample_num = sample_num; + ci->timescale = ts; + ci->sample_per_chunk = spc; + + if (csize) { + ci->size += csize * spc; + } else { + for (k=0; ksize += gf_isom_get_sample_size(file, i+1, sample_num+k); + } + } + + if (di>1) dump_stsd=1; + + if (do_prog) + gf_set_progress("Analysing chunks", cur+1, nb_chunks_total); + cur++; + } + } + + qsort(all_chunks, nb_chunks_total, sizeof(ChunkInfo), sort_chunk); + + fprintf(stderr, "Dumping chunk info - diff_prev_ms is the diff in ms between start time of current and prev chunk\n"); + + if (dump_stsd) + fprintf(dump, "ChunkNum\tOffset\tTkNum\tChkNbInTk\tChkSize\tSamp/Chunk\tFirstSample\tDescIdx\tSAP\tTime\tCTS\tdiff_prev_ms\n"); + else + fprintf(dump, "ChunkNum\tOffset\tTkNum\tChkNbInTk\tChkSize\tSamp/Chunk\tFirstSample\tSAP\tTime\tCTS\tdiff_prev_ms\n"); + + for (i=0; itrack_num, ci->first_sample_num, &di, NULL); + if (samp) { + u32 h, m, s, ms, secs; + u64 time = samp->DTS+samp->CTS_Offset; + s64 diff; + time *= 1000; + time /= ci->timescale; + + secs = (u32) (time/1000); + h = secs / 3600; + m = (secs - 3600 * h) / 60; + s = (secs - 3600 * h - 60 * m); + ms = (u32) (time - secs*1000); + + diff = time; + diff -= prev_time; + prev_time = time; + + fprintf(dump, "%d\t"LLU"\t%d\t%d\t"LLU"\t%d\t%d\t", i+1, ci->chunk_offset, ci->track_num, ci->chunk_num, ci->size, ci->sample_per_chunk, ci->first_sample_num); + if (dump_stsd) fprintf(dump, "%d\t", di); + fprintf(dump, "%d\t", samp->IsRAP); + if (dump_hm==2) + fprintf(dump, "%02d:", h); + if (dump_hm>=1) + fprintf(dump, "%02d:", m); + fprintf(dump, "%02d.%03d\t"LLD"\t"LLD"\n", s, ms, samp->DTS+samp->CTS_Offset, diff); + gf_isom_sample_del(&samp); + } else { + fprintf(dump, "%d\t"LLU"\t%d\t%d\t%d\tN/A\tN/A\tN/A\tN/A\n", i+1, ci->chunk_offset, ci->track_num, ci->chunk_num, ci->first_sample_num); + } + //we assume single mdat ... + if (!prev_chunk_end) { + prev_chunk_end = gf_isom_get_first_mdat_start(file); + } + + if (ci->chunk_offset > prev_chunk_end) + unused_space += ci->chunk_offset - prev_chunk_end; + + prev_chunk_end = ci->chunk_offset + ci->size; + + if (do_prog) + gf_set_progress("Dumping chunks", i+1, nb_chunks_total); + } + gf_free(all_chunks); + if (inName) + gf_fclose(dump); + + prev_chunk_end = gf_isom_get_unused_box_bytes(file); + if (prev_chunk_end) + fprintf(stderr, "Unused bytes in box structure: "LLU"\n", prev_chunk_end); + if (unused_space) + fprintf(stderr, "Unused bytes in mdat: "LLU"\n", unused_space); +} + #ifndef GPAC_DISABLE_ISOM_DUMP void dump_isom_ismacryp(GF_ISOFile *file, char *inName, Bool is_final_name) @@ -1520,7 +1799,7 @@ void dump_isom_ismacryp(GF_ISOFile *file, char *inName, Bool is_final_name) if (!is_final_name) strcat(szBuf, "_ismacryp.xml"); dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szBuf)); return; } } else { @@ -1556,7 +1835,7 @@ void dump_isom_timed_text(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, track = gf_isom_get_track_by_id(file, trackID); if (!track) { - fprintf(stderr, "Cannot find track ID %d\n", trackID); + M4_LOG(GF_LOG_ERROR, ("Cannot find track ID %d\n", trackID)); return; } @@ -1565,7 +1844,7 @@ void dump_isom_timed_text(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, case GF_ISOM_MEDIA_SUBT: break; default: - fprintf(stderr, "Track ID %d is not a 3GPP text track\n", trackID); + M4_LOG(GF_LOG_ERROR, ("Track ID %d is not a 3GPP text track\n", trackID)); return; } @@ -1582,7 +1861,7 @@ void dump_isom_timed_text(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szBuf)); return; } } else { @@ -1591,8 +1870,11 @@ void dump_isom_timed_text(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, e = gf_isom_text_dump(file, track, dump, dump_type); if (inName) gf_fclose(dump); - if (e) fprintf(stderr, "Conversion failed (%s)\n", gf_error_to_string(e)); - else fprintf(stderr, "Conversion done\n"); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Conversion failed (%s)\n", gf_error_to_string(e))); + } else { + fprintf(stderr, "Conversion done\n"); + } } #endif /*GPAC_DISABLE_ISOM_DUMP*/ @@ -1615,12 +1897,12 @@ void dump_isom_sdp(GF_ISOFile *file, char *inName, Bool is_final_name) } dump = gf_fopen(szBuf, "wt"); if (!dump) { - fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + M4_LOG(GF_LOG_ERROR, ("Failed to open %s for dumping\n", szBuf)); return; } } else { dump = stdout; - fprintf(dump, "* File SDP content *\n\n"); + fprintf(dump, "# File SDP content \n\n"); } //get the movie SDP gf_isom_sdp_get(file, &sdp, &size); @@ -1632,7 +1914,8 @@ void dump_isom_sdp(GF_ISOFile *file, char *inName, Bool is_final_name) for (i=0; i\n"); } if (do_close) gf_fclose(dump); + + if (!e && dump_check_xml) { + if (do_close) { + GF_DOMParser *xml_parser = gf_xml_dom_new(); + e = gf_xml_dom_parse(xml_parser, szFileName, NULL, NULL); + if (e) { + fprintf(stderr, "Failed to parse XML dump %s: line %d: %s\n", szFileName, gf_xml_dom_get_line(xml_parser), gf_xml_dom_get_error(xml_parser) ); + } + gf_xml_dom_del(xml_parser); + } else { + fprintf(stderr, "Cannot check XML for dump on stdout\n"); + } + } return e; } #endif @@ -1793,20 +2110,53 @@ static char *format_date(u64 time, char *szTime) return szTime; } -void print_udta(GF_ISOFile *file, u32 track_number) +void print_udta(GF_ISOFile *file, u32 track_number, Bool has_itags) { u32 i, count; count = gf_isom_get_udta_count(file, track_number); if (!count) return; + if (has_itags) { + for (i=0; i1) + fprintf(stderr, "%d", k+1); + fprintf(stderr, " "); + for (j=0; j<16; j++) fprintf(stderr, "%02X", key_info[kpos+1+j]); + kpos+=17; + if (!iv_size && is_protected) { + constant_iv_size = key_info[1]; + kpos += 1 + constant_iv_size; + } + fprintf(stderr, " - %sIV size %d \n", constant_iv_size ? "const " : "", constant_iv_size ? constant_iv_size : iv_size); + } +} + static void DumpMetaItem(GF_ISOFile *file, Bool root_meta, u32 tk_num, char *name) { - u32 i, count, brand, primary_id; - brand = gf_isom_get_meta_type(file, root_meta, tk_num); - if (!brand) return; + char szInd[2]; + u32 i, count, primary_id; + u32 meta_type = gf_isom_get_meta_type(file, root_meta, tk_num); + if (name[0]=='\t') { + szInd[0] = '\t'; + szInd[1] = 0; + } else { + szInd[0] = 0; + } count = gf_isom_get_meta_item_count(file, root_meta, tk_num); + if (!count && !meta_type) return; + primary_id = gf_isom_get_meta_primary_item_id(file, root_meta, tk_num); - fprintf(stderr, "%s type: \"%s\" - %d resource item(s)\n", name, gf_4cc_to_str(brand), (count+(primary_id>0))); + fprintf(stderr, "%s type: \"%s\" - %d resource item(s)\n", name, meta_type ? gf_4cc_to_str(meta_type) : "undefined", (count+(primary_id>0))); switch (gf_isom_has_meta_xml(file, root_meta, tk_num)) { case 1: - fprintf(stderr, "Meta has XML resource\n"); + fprintf(stderr, "%sMeta has XML resource\n", szInd); break; case 2: - fprintf(stderr, "Meta has BinaryXML resource\n"); + fprintf(stderr, "%sMeta has BinaryXML resource\n", szInd); break; } if (primary_id) { - fprintf(stderr, "Primary Item - ID %d\n", primary_id); + fprintf(stderr, "%sPrimary Item - ID %d\n", szInd, primary_id); } for (i=0; i1) ? "s" : ""); + for (j=1; jdata, slc->size, hash); fprintf(stderr, "\t%s#%d hash: ", szName, i+1); for (j=0; j<20; j++) fprintf(stderr, "%02X", hash[j]); @@ -2010,7 +2455,7 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg fprintf(stderr, "\n"); fprintf(stderr, "\tParameter Sets: "); for (k=0; kparam_array); k++) { - GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + GF_NALUFFParamArray *ar=gf_list_get(hevccfg->param_array, k); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { fprintf(stderr, "%d SPS ", gf_list_count(ar->nalus)); } @@ -2022,8 +2467,8 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg #if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC) for (idx=0; idxnalus); idx++) { - GF_AVCConfigSlot *vps = gf_list_get(ar->nalus, idx); - s32 ps_idx=gf_media_hevc_read_vps(vps->data, vps->size, hevc_state); + GF_NALUFFParam *vps = gf_list_get(ar->nalus, idx); + s32 ps_idx=gf_hevc_read_vps(vps->data, vps->size, hevc_state); if (hevccfg->is_lhvc && (ps_idx>=0)) { non_hevc_base_layer = ! hevc_state->vps[ps_idx].base_layer_internal_flag; } @@ -2036,14 +2481,14 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg fprintf(stderr, "\n"); #if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC) for (k=0; kparam_array); k++) { - GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + GF_NALUFFParamArray *ar=gf_list_get(hevccfg->param_array, k); u32 width, height; s32 par_n, par_d; if (ar->type !=GF_HEVC_NALU_SEQ_PARAM) continue; for (idx=0; idxnalus); idx++) { GF_Err e; - GF_AVCConfigSlot *sps = gf_list_get(ar->nalus, idx); + GF_NALUFFParam *sps = gf_list_get(ar->nalus, idx); par_n = par_d = -1; e = gf_hevc_get_sps_info_with_state(hevc_state, sps->data, sps->size, NULL, &width, &height, &par_n, &par_d); if (e==GF_OK) { @@ -2055,7 +2500,7 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg } fprintf(stderr, "\n"); } else { - fprintf(stderr, "\nFailed to read SPS: %s\n\n", gf_error_to_string((e) )); + M4_LOG(GF_LOG_ERROR, ("Failed to read SPS: %s\n\n", gf_error_to_string(e) )); } } } @@ -2069,19 +2514,105 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg } for (k=0; kparam_array); k++) { - GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + GF_NALUFFParamArray *ar=gf_list_get(hevccfg->param_array, k); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) print_config_hash(ar->nalus, "SPS"); else if (ar->type==GF_HEVC_NALU_PIC_PARAM) print_config_hash(ar->nalus, "PPS"); else if (ar->type==GF_HEVC_NALU_VID_PARAM) print_config_hash(ar->nalus, "VPS"); } } +void dump_vvc_track_info(GF_ISOFile *file, u32 trackNum, GF_VVCConfig *vvccfg +#if !defined(GPAC_DISABLE_AV_PARSERS) + , VVCState *vvc_state +#endif /*GPAC_DISABLE_AV_PARSERS && defined(GPAC_DISABLE_HEVC)*/ + ) +{ +#if !defined(GPAC_DISABLE_AV_PARSERS) + u32 idx; +#endif + u32 k; + fprintf(stderr, "\tNAL Unit length bits: %d", 8*vvccfg->nal_unit_size); + if (vvccfg->ptl_present) { + fprintf(stderr, " Profile %d @ Level %d - Chroma Format %s", vvccfg->general_profile_idc, vvccfg->general_level_idc, gf_avc_hevc_get_chroma_format_name(vvccfg->chroma_format)); + if (vvccfg->general_constraint_info && vvccfg->num_constraint_info && vvccfg->general_constraint_info[0]) { + fprintf(stderr, " - general constraint info 0x"); + for (idx=0; idxnum_constraint_info; idx++) { + fprintf(stderr, "%02X", vvccfg->general_constraint_info[idx]); + } + } + fprintf(stderr, "\n"); + fprintf(stderr, "\tBit Depth %d - %d temporal layers\n", vvccfg->bit_depth, vvccfg->numTemporalLayers); + } + + fprintf(stderr, "\tParameter Sets: "); + for (k=0; kparam_array); k++) { + GF_NALUFFParamArray *ar=gf_list_get(vvccfg->param_array, k); + if (ar->type==GF_VVC_NALU_SEQ_PARAM) { + fprintf(stderr, "%d SPS ", gf_list_count(ar->nalus)); + } + if (ar->type==GF_VVC_NALU_PIC_PARAM) { + fprintf(stderr, "%d PPS ", gf_list_count(ar->nalus)); + } + if (ar->type==GF_VVC_NALU_VID_PARAM) { + fprintf(stderr, "%d VPS ", gf_list_count(ar->nalus)); -void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool is_track_num) +#if !defined(GPAC_DISABLE_AV_PARSERS) && 0 //TODO + for (idx=0; idxnalus); idx++) { + GF_NALUFFParam *vps = gf_list_get(ar->nalus, idx); + s32 ps_idx=gf_hevc_read_vps(vps->data, vps->size, hevc_state); + if (hevccfg->is_lhvc && (ps_idx>=0)) { + non_hevc_base_layer = ! hevc_state->vps[ps_idx].base_layer_internal_flag; + } + } +#endif + + } + } + + fprintf(stderr, "\n"); +#if !defined(GPAC_DISABLE_AV_PARSERS) + for (k=0; kparam_array); k++) { + GF_NALUFFParamArray *ar=gf_list_get(vvccfg->param_array, k); + u32 width, height; + s32 par_n, par_d; + + if (ar->type !=GF_VVC_NALU_SEQ_PARAM) continue; + for (idx=0; idxnalus); idx++) { + GF_Err e; + GF_NALUFFParam *sps = gf_list_get(ar->nalus, idx); + par_n = par_d = -1; + e = gf_vvc_get_sps_info(sps->data, sps->size, NULL, &width, &height, &par_n, &par_d); + if (e==GF_OK) { + fprintf(stderr, "\tSPS resolution %dx%d", width, height); + if ((par_n>0) && (par_d>0)) { + u32 tw, th; + gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL); + fprintf(stderr, " - Pixel Aspect Ratio %d:%d - Indicated track size %d x %d", par_n, par_d, tw, th); + } + fprintf(stderr, "\n"); + } else { + M4_LOG(GF_LOG_ERROR, ("\nFailed to read SPS: %s\n\n", gf_error_to_string(e) )); + } + } + } +#endif + + for (k=0; kparam_array); k++) { + GF_NALUFFParamArray *ar=gf_list_get(vvccfg->param_array, k); + if (ar->type==GF_VVC_NALU_SEQ_PARAM) print_config_hash(ar->nalus, "SPS"); + else if (ar->type==GF_VVC_NALU_PIC_PARAM) print_config_hash(ar->nalus, "PPS"); + else if (ar->type==GF_VVC_NALU_VID_PARAM) print_config_hash(ar->nalus, "VPS"); + } +} + +void gf_inspect_format_timecode(const u8 *data, u32 size, u32 tmcd_flags, u32 tc_num, u32 tc_den, u32 tmcd_fpt, char szFmt[100]); + +void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool is_track_num, Bool dump_m4sys) { - Float scale; + char szCodec[RFC6381_CODEC_NAME_SIZE_MAX]; + Double scale, max_rate, rate; Bool is_od_track = 0; - u32 trackNum, i, j, max_rate, rate, ts, mtype, msub_type, timescale, sr, nb_ch, count, alt_group, nb_groups, nb_edits, cdur, csize, bps; + u32 trackNum, i, j, ts, mtype, msub_type, timescale, sr, nb_ch, count, alt_group, nb_groups, nb_edits, cdur, csize, bps, pfmt, codecid; u64 time_slice, dur, size; s32 cts_shift; GF_ESD *esd; @@ -2095,29 +2626,43 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool trackID = gf_isom_get_track_id(file, trackNum); } if (!trackNum) { - fprintf(stderr, "No track with ID %d found\n", trackID); + M4_LOG(GF_LOG_ERROR, ("No track with ID %d found\n", trackID)); return; } timescale = gf_isom_get_media_timescale(file, trackNum); - fprintf(stderr, "Track # %d Info - TrackID %d - TimeScale %d\n", trackNum, trackID, timescale); - fprintf(stderr, "Media Duration %s - ", format_duration(gf_isom_get_media_duration(file, trackNum), timescale, szDur)); - fprintf(stderr, "Indicated Duration %s\n", format_duration(gf_isom_get_media_original_duration(file, trackNum), timescale, szDur)); + fprintf(stderr, "# Track %d Info - ID %d - TimeScale %d\n", trackNum, trackID, timescale); + + dur = gf_isom_get_media_original_duration(file, trackNum); + size = gf_isom_get_media_duration(file, trackNum); + fprintf(stderr, "Media Duration %s ", format_duration(dur, timescale, szDur)); + if (dur != size) + fprintf(stderr, " (recomputed %s)", format_duration(size, timescale, szDur)); + fprintf(stderr, "\n"); if (gf_isom_check_data_reference(file, trackNum, 1) != GF_OK) { - fprintf(stderr, "Track uses external data reference not supported by GPAC!\n"); + M4_LOG(GF_LOG_WARNING, ("Track uses external data reference not supported by GPAC!\n")); } nb_edits = gf_isom_get_edits_count(file, trackNum); if (nb_edits) - fprintf(stderr, "Track has %d edit lists: track duration is %s\n", nb_edits, format_duration(gf_isom_get_track_duration(file, trackNum), gf_isom_get_timescale(file), szDur)); + fprintf(stderr, "Track has %d edits: track duration is %s\n", nb_edits, format_duration(gf_isom_get_track_duration(file, trackNum), gf_isom_get_timescale(file), szDur)); cts_shift = gf_isom_get_composition_offset_shift(file, trackNum); if (cts_shift) fprintf(stderr, "Track composition offset shift (negative CTS offset): %d\n", cts_shift); if (gf_isom_is_track_in_root_od(file, trackNum) ) fprintf(stderr, "Track is present in Root OD\n"); - if (!gf_isom_is_track_enabled(file, trackNum)) fprintf(stderr, "Track is disabled\n"); + + u32 tk_flags = gf_isom_get_track_flags(file, trackNum); + fprintf(stderr, "Track flags:"); + if (tk_flags & GF_ISOM_TK_ENABLED) fprintf(stderr, " Enabled"); + else fprintf(stderr, " Disabled"); + if (tk_flags & GF_ISOM_TK_IN_MOVIE) fprintf(stderr, " In Movie"); + if (tk_flags & GF_ISOM_TK_IN_PREVIEW) fprintf(stderr, " In Preview"); + if (tk_flags & GF_ISOM_TK_SIZE_IS_AR) fprintf(stderr, " Size is AspectRatio"); + fprintf(stderr, "\n"); + gf_isom_get_media_language(file, trackNum, &lang); fprintf(stderr, "Media Info: Language \"%s (%s)\" - ", GetLanguage(lang), lang ); gf_free(lang); @@ -2127,6 +2672,9 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool if (!msub_type) msub_type = gf_isom_get_media_subtype(file, trackNum, 1); fprintf(stderr, "%s\" - %d samples\n", gf_4cc_to_str(msub_type), gf_isom_get_sample_count(file, trackNum)); + pfmt = gf_pixel_fmt_from_qt_type(msub_type); + codecid = gf_codec_id_from_isobmf(msub_type); + count = gf_isom_get_track_kind_count(file, trackNum); for (i = 0; i < count; i++) { char *kind_scheme, *kind_value; @@ -2165,7 +2713,32 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "Handler name: %s\n", handler_name); } - print_udta(file, trackNum); + print_udta(file, trackNum, GF_FALSE); + + DumpMetaItem(file, 0, trackNum, "\tTrack Meta"); + + gf_isom_get_track_switch_group_count(file, trackNum, &alt_group, &nb_groups); + if (alt_group) { + fprintf(stderr, "Alternate Group ID %d\n", alt_group); + for (i=0; idv_version_major, dovi->dv_version_minor, dovi->dv_profile, dovi->dv_level, + dovi->rpu_present_flag, dovi->bl_present_flag, dovi->el_present_flag, dovi->dv_bl_signal_compatibility_id); + + gf_odf_dovi_cfg_del(dovi); + } } gf_isom_get_audio_info(file, trackNum, 1, &sr, &nb_ch, &bps); @@ -2205,17 +2787,20 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool ) { esd = gf_isom_get_esd(file, trackNum, 1); if (!esd || !esd->decoderConfig) { - fprintf(stderr, "WARNING: Broken MPEG-4 Track\n"); + M4_LOG(GF_LOG_WARNING, ("WARNING: Broken MPEG-4 Track\n")); if (esd) gf_odf_desc_del((GF_Descriptor *)esd); } else { const char *st = gf_stream_type_name(esd->decoderConfig->streamType); - if (st) { - fprintf(stderr, "MPEG-4 Config%s%s Stream - ObjectTypeIndication 0x%02x\n", - full_dump ? "\n\t" : ": ", st, esd->decoderConfig->objectTypeIndication); - } else { - fprintf(stderr, "MPEG-4 Config%sStream Type 0x%02x - ObjectTypeIndication 0x%02x\n", - full_dump ? "\n\t" : ": ", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication); + if (dump_m4sys) { + if (st) { + fprintf(stderr, "MPEG-4 Config%s%s Stream - ObjectTypeIndication 0x%02x\n", + full_dump ? "\n\t" : ": ", st, esd->decoderConfig->objectTypeIndication); + } else { + fprintf(stderr, "MPEG-4 Config%sStream Type 0x%02x - ObjectTypeIndication 0x%02x\n", + full_dump ? "\n\t" : ": ", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication); + } } + if (esd->decoderConfig->streamType==GF_STREAM_OD) is_od_track=1; @@ -2230,7 +2815,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool gf_isom_get_visual_info(file, trackNum, 1, &w, &h); fprintf(stderr, "MPEG-4 Visual Size %d x %d\n", w, h); #endif - fprintf(stderr, "\tNon-compliant MPEG-4 Visual track: video_object_layer infos not found in sample description\n"); + M4_LOG(GF_LOG_WARNING, ("Non-compliant MPEG-4 Visual track: video_object_layer infos not found in sample description\n")); #ifndef GPAC_DISABLE_AV_PARSERS } else { GF_M4VDecSpecInfo dsi; @@ -2257,7 +2842,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool svccfg = gf_isom_svc_config_get(file, trackNum, 1); mvccfg = gf_isom_mvc_config_get(file, trackNum, 1); if (!avccfg && !svccfg && !mvccfg) { - fprintf(stderr, "\n\n\tNon-compliant AVC track: SPS/PPS not found in sample description\n"); + M4_LOG(GF_LOG_ERROR, ("\tNon-compliant AVC track: SPS/PPS not found in sample description\n")); } else if (avccfg) { fprintf(stderr, "\tAVC Info: %d SPS - %d PPS", gf_list_count(avccfg->sequenceParameterSets) , gf_list_count(avccfg->pictureParameterSets) ); fprintf(stderr, " - Profile %s @ Level %g\n", gf_avc_get_profile_name(avccfg->AVCProfileIndication), ((Double)avccfg->AVCLevelIndication)/10.0 ); @@ -2266,7 +2851,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool #ifndef GPAC_DISABLE_AV_PARSERS for (i=0; isequenceParameterSets); i++) { s32 par_n, par_d; - GF_AVCConfigSlot *slc = gf_list_get(avccfg->sequenceParameterSets, i); + GF_NALUFFParam *slc = gf_list_get(avccfg->sequenceParameterSets, i); gf_avc_get_sps_info(slc->data, slc->size, NULL, NULL, NULL, &par_n, &par_d); if ((par_n>0) && (par_d>0)) { u32 tw, th; @@ -2291,7 +2876,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "\tSVC NAL Unit length bits: %d\n", 8*svccfg->nal_unit_size); #ifndef GPAC_DISABLE_AV_PARSERS for (i=0; isequenceParameterSets); i++) { - GF_AVCConfigSlot *slc = gf_list_get(svccfg->sequenceParameterSets, i); + GF_NALUFFParam *slc = gf_list_get(svccfg->sequenceParameterSets, i); if (slc) { s32 par_n, par_d; u32 s_w, s_h, sps_id; @@ -2317,7 +2902,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "\tMVC NAL Unit length bits: %d\n", 8*mvccfg->nal_unit_size); #ifndef GPAC_DISABLE_AV_PARSERS for (i=0; isequenceParameterSets); i++) { - GF_AVCConfigSlot *slc = gf_list_get(mvccfg->sequenceParameterSets, i); + GF_NALUFFParam *slc = gf_list_get(mvccfg->sequenceParameterSets, i); if (slc) { u32 s_w, s_h, sps_id; s32 par_n, par_d; @@ -2366,7 +2951,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "\tHEVC Tile track without tiling info\n"); } } else if (!hevccfg && !lhvccfg) { - fprintf(stderr, "\n\n\tNon-compliant HEVC track: No hvcC or shcC found in sample description\n"); + M4_LOG(GF_LOG_ERROR, ("\tNon-compliant HEVC track: No hvcC or shcC found in sample description\n")); } if (gf_isom_get_reference_count(file, trackNum, GF_ISOM_REF_SABT)) { @@ -2401,7 +2986,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "Spatial scalability"); break; case 8: - fprintf(stderr, "Auxilary"); + fprintf(stderr, "Auxiliary"); break; default: fprintf(stderr, "unknown"); @@ -2417,21 +3002,22 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool char *szName; gf_isom_get_visual_info(file, trackNum, 1, &w, &h); if (full_dump) fprintf(stderr, "\t"); - if (!strnicmp((char *) &esd->decoderConfig->decoderSpecificInfo->data[3], "theora", 6)) szName = "Theora"; - else szName = "Unknown"; + szName = "Unknown"; + if (esd->decoderConfig->decoderSpecificInfo + && (esd->decoderConfig->decoderSpecificInfo->dataLength>=10) + && !strnicmp((char *) &esd->decoderConfig->decoderSpecificInfo->data[3], "theora", 6) + ) + szName = "Theora"; + fprintf(stderr, "Ogg/%s video / GPAC Mux - Visual Size %d x %d\n", szName, w, h); } - else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_JPEG) { - gf_isom_get_visual_info(file, trackNum, 1, &w, &h); - fprintf(stderr, "JPEG Stream - Visual Size %d x %d\n", w, h); - } - else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_PNG) { - gf_isom_get_visual_info(file, trackNum, 1, &w, &h); - fprintf(stderr, "PNG Stream - Visual Size %d x %d\n", w, h); - } - else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_J2K) { - gf_isom_get_visual_info(file, trackNum, 1, &w, &h); - fprintf(stderr, "JPEG2000 Stream - Visual Size %d x %d\n", w, h); + else { + //check if we know this codec from its OTI + u32 codec_id = gf_codecid_from_oti(GF_STREAM_VISUAL, esd->decoderConfig->objectTypeIndication); + if (codec_id) { + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + fprintf(stderr, "%s - Visual Size %d x %d\n", gf_codecid_name(codec_id), w, h); + } } if (!w || !h) { gf_isom_get_visual_info(file, trackNum, 1, &w, &h); @@ -2448,6 +3034,7 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool GF_Err e; u32 oti; #endif + u32 codec_id; Bool is_mp2 = GF_FALSE; switch (esd->decoderConfig->objectTypeIndication) { case GF_CODECID_AAC_MPEG2_MP: @@ -2461,8 +3048,9 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool else e = gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg); if (full_dump) fprintf(stderr, "\t"); - if (e) fprintf(stderr, "Corrupted AAC Config\n"); - else { + if (e) { + M4_LOG(GF_LOG_ERROR, ("Corrupted AAC Config\n")); + } else { char *signaling = "implicit"; char *heaac = ""; if (!is_mp2 && a_cfg.has_sbr) { @@ -2487,39 +3075,32 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool break; case GF_CODECID_MPEG2_PART3: case GF_CODECID_MPEG_AUDIO: + case GF_CODECID_MPEG_AUDIO_L1: if (msub_type == GF_ISOM_SUBTYPE_MPEG4_CRYP) { fprintf(stderr, "MPEG-1/2 Audio - %d Channels - SampleRate %d\n", nb_ch, sr); } else { #ifndef GPAC_DISABLE_AV_PARSERS GF_ISOSample *samp = gf_isom_get_sample(file, trackNum, 1, &oti); if (samp) { - u32 mhdr = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]); - if (full_dump) fprintf(stderr, "\t"); - fprintf(stderr, "%s Audio - %d Channel(s) - SampleRate %d - Layer %d\n", - gf_mp3_version_name(mhdr), - gf_mp3_num_channels(mhdr), - gf_mp3_sampling_rate(mhdr), - gf_mp3_layer(mhdr) - ); + if (samp->data && (samp->dataLength>4)) { + u32 mhdr = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]); + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "%s Audio - %d Channel(s) - SampleRate %d - Layer %d\n", + gf_mp3_version_name(mhdr), + gf_mp3_num_channels(mhdr), + gf_mp3_sampling_rate(mhdr), + gf_mp3_layer(mhdr) + ); + } gf_isom_sample_del(&samp); } else { - fprintf(stderr, "\n\tError fetching sample: %s\n", gf_error_to_string(gf_isom_last_error(file)) ); + M4_LOG(GF_LOG_ERROR, ("Error fetching sample: %s\n", gf_error_to_string(gf_isom_last_error(file)) )); } #else fprintf(stderr, "MPEG-1/2 Audio - %d Channels - SampleRate %d\n", nb_ch, sr); #endif } break; - /*OGG media*/ - case GF_CODECID_VORBIS: - fprintf(stderr, "Ogg/Vorbis audio / GPAC Mux - Sample Rate %d - %d channel(s)\n", sr, nb_ch); - break; - case GF_CODECID_FLAC: - fprintf(stderr, "Ogg/FLAC audio / GPAC Mux - Sample Rate %d - %d channel(s)\n", sr, nb_ch); - break; - case GF_CODECID_SPEEX: - fprintf(stderr, "Ogg/Speex audio / GPAC Mux - Sample Rate %d - %d channel(s)\n", sr, nb_ch); - break; case GF_CODECID_EVRC: fprintf(stderr, "EVRC Audio - Sample Rate 8000 - 1 channel\n"); break; @@ -2537,18 +3118,28 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "EVRC Audio (PacketVideo Mux) - Sample Rate 8000 - 1 channel\n"); } break; + default: + codec_id = gf_codecid_from_oti(GF_STREAM_AUDIO, esd->decoderConfig->objectTypeIndication); + if (codec_id) { + fprintf(stderr, "%s - Sample Rate %d - %d channel(s)\n", gf_codecid_name(codec_id), sr, nb_ch); + } + break; } } else if (esd->decoderConfig->streamType==GF_STREAM_SCENE) { if (esd->decoderConfig->objectTypeIndication<=4) { GF_BIFSConfig *b_cfg = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication); - fprintf(stderr, "BIFS Scene description - %s stream\n", b_cfg->elementaryMasks ? "Animation" : "Command"); - if (full_dump && !b_cfg->elementaryMasks) { - fprintf(stderr, "\tWidth %d Height %d Pixel Metrics %s\n", b_cfg->pixelWidth, b_cfg->pixelHeight, b_cfg->pixelMetrics ? "yes" : "no"); + if (b_cfg) { + fprintf(stderr, "BIFS Scene description - %s stream\n", b_cfg->elementaryMasks ? "Animation" : "Command"); + if (full_dump && !b_cfg->elementaryMasks) { + fprintf(stderr, "\tWidth %d Height %d Pixel Metrics %s\n", b_cfg->pixelWidth, b_cfg->pixelHeight, b_cfg->pixelMetrics ? "yes" : "no"); + } + gf_odf_desc_del((GF_Descriptor *)b_cfg); + } else { + fprintf(stderr, "! Invalid BIFS configuration !\n"); } - gf_odf_desc_del((GF_Descriptor *)b_cfg); } else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_AFX) { - u8 tag = esd->decoderConfig->decoderSpecificInfo ? esd->decoderConfig->decoderSpecificInfo->data[0] : 0xFF; + u8 tag = (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) ? esd->decoderConfig->decoderSpecificInfo->data[0] : 0xFF; const char *afxtype = gf_stream_type_afx_name(tag); fprintf(stderr, "AFX Stream - type %s (%d)\n", afxtype, tag); } else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_FONT) { @@ -2562,16 +3153,18 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool } else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_SYNTHESIZED_TEXTURE) { fprintf(stderr, "Synthetized Texture stream stream\n"); } else { - fprintf(stderr, "Unknown Systems stream OTI %d\n", esd->decoderConfig->objectTypeIndication); + M4_LOG(GF_LOG_WARNING, ("Unknown Systems stream OTI %d\n", esd->decoderConfig->objectTypeIndication)); } } /*sync is only valid if we open all tracks to take care of default MP4 sync..*/ if (!full_dump) { - if (!esd->OCRESID || (esd->OCRESID == esd->ESID)) - fprintf(stderr, "Self-synchronized\n"); - else - fprintf(stderr, "Synchronized on stream %d\n", esd->OCRESID); + if (dump_m4sys) { + if (!esd->OCRESID || (esd->OCRESID == esd->ESID)) + fprintf(stderr, "Self-synchronized\n"); + else + fprintf(stderr, "Synchronized on stream %d\n", esd->OCRESID); + } } else { fprintf(stderr, "\tDecoding Buffer size %d - Bitrate: avg %d - max %d kbps\n", esd->decoderConfig->bufferSizeDB, esd->decoderConfig->avgBitrate/1000, esd->decoderConfig->maxBitrate/1000); if (esd->dependsOnESID) @@ -2583,69 +3176,6 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool if (esd->URLString) fprintf(stderr, "\tRemote Data Source %s\n", esd->URLString); } gf_odf_desc_del((GF_Descriptor *) esd); - - /*ISMACryp*/ - if (msub_type == GF_ISOM_SUBTYPE_MPEG4_CRYP) { - const char *scheme_URI, *KMS_URI; - u32 scheme_type, version; - u32 IV_size; - Bool use_sel_enc; - - if (gf_isom_is_ismacryp_media(file, trackNum, 1)) { - gf_isom_get_ismacryp_info(file, trackNum, 1, NULL, &scheme_type, &version, &scheme_URI, &KMS_URI, &use_sel_enc, &IV_size, NULL); - fprintf(stderr, "\n*Encrypted stream - ISMA scheme %s (version %d)\n", gf_4cc_to_str(scheme_type), version); - if (scheme_URI) fprintf(stderr, "scheme location: %s\n", scheme_URI); - if (KMS_URI) { - if (!strnicmp(KMS_URI, "(key)", 5)) fprintf(stderr, "KMS location: key in file\n"); - else fprintf(stderr, "KMS location: %s\n", KMS_URI); - } - fprintf(stderr, "Selective Encryption: %s\n", use_sel_enc ? "Yes" : "No"); - if (IV_size) fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8); - } else if (gf_isom_is_omadrm_media(file, trackNum, 1)) { - const char *textHdrs; - u32 enc_type, hdr_len; - u64 orig_len; - fprintf(stderr, "\n*Encrypted stream - OMA DRM\n"); - gf_isom_get_omadrm_info(file, trackNum, 1, NULL, NULL, NULL, &scheme_URI, &KMS_URI, &textHdrs, &hdr_len, &orig_len, &enc_type, &use_sel_enc, &IV_size, NULL); - fprintf(stderr, "Rights Issuer: %s\n", KMS_URI); - fprintf(stderr, "Content ID: %s\n", scheme_URI); - if (textHdrs) { - u32 offset; - const char *start = textHdrs; - fprintf(stderr, "OMA Textual Headers:\n"); - i=0; - offset=0; - while (i>16, version&0xFFFF); - if (IV_size) - fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8); - if (gf_isom_cenc_is_pattern_mode(file, trackNum, 1)) - fprintf(stderr, "Pattern mode enabled\n"); - - } else if(gf_isom_is_adobe_protection_media(file, trackNum, 1)) { - gf_isom_get_adobe_protection_info(file, trackNum, 1, NULL, &scheme_type, &version, NULL); - fprintf(stderr, "\n*Encrypted stream - Adobe protection scheme %s (version %d)\n", gf_4cc_to_str(scheme_type), version); - } else { - fprintf(stderr, "\n*Encrypted stream - unknown scheme %s\n", gf_4cc_to_str(gf_isom_is_media_encrypted(file, trackNum, 0) )); - } - } - } } else if (msub_type == GF_ISOM_SUBTYPE_AV01) { GF_AV1Config *av1c; @@ -2654,23 +3184,27 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool fprintf(stderr, "\tAOM AV1 stream - Resolution %d x %d\n", w, h); av1c = gf_isom_av1_config_get(file, trackNum, 1); - fprintf(stderr, "\tversion=%u, profile=%u, level_idx0=%u, tier=%u\n", (u32)av1c->version, (u32)av1c->seq_profile, (u32)av1c->seq_level_idx_0, (u32)av1c->seq_tier_0); - fprintf(stderr, "\thigh_bitdepth=%u, twelve_bit=%u, monochrome=%u\n", (u32)av1c->high_bitdepth, (u32)av1c->twelve_bit, (u32)av1c->monochrome); - fprintf(stderr, "\tchroma: subsampling_x=%u, subsampling_y=%u, sample_position=%u\n", (u32)av1c->chroma_subsampling_x, (u32)av1c->chroma_subsampling_y, (u32)av1c->chroma_sample_position); + if (!av1c) { + fprintf(stderr, "\tCorrupted av1 config\n"); + } else { + fprintf(stderr, "\tversion=%u, profile=%u, level_idx0=%u, tier=%u\n", (u32)av1c->version, (u32)av1c->seq_profile, (u32)av1c->seq_level_idx_0, (u32)av1c->seq_tier_0); + fprintf(stderr, "\thigh_bitdepth=%u, twelve_bit=%u, monochrome=%u\n", (u32)av1c->high_bitdepth, (u32)av1c->twelve_bit, (u32)av1c->monochrome); + fprintf(stderr, "\tchroma: subsampling_x=%u, subsampling_y=%u, sample_position=%u\n", (u32)av1c->chroma_subsampling_x, (u32)av1c->chroma_subsampling_y, (u32)av1c->chroma_sample_position); - if (av1c->initial_presentation_delay_present) - fprintf(stderr, "\tInitial presentation delay %u\n", (u32) av1c->initial_presentation_delay_minus_one+1); + if (av1c->initial_presentation_delay_present) + fprintf(stderr, "\tInitial presentation delay %u\n", (u32) av1c->initial_presentation_delay_minus_one+1); - count = gf_list_count(av1c->obu_array); - for (i=0; iobu_array, i); - gf_sha1_csum((u8*)obu->obu, (u32)obu->obu_length, hash); - fprintf(stderr, "\tOBU#%d %s hash: ", i+1, gf_av1_get_obu_name(obu->obu_type) ); - for (j=0; j<20; j++) fprintf(stderr, "%02X", hash[j]); - fprintf(stderr, "\n"); + count = gf_list_count(av1c->obu_array); + for (i=0; iobu_array, i); + gf_sha1_csum((u8*)obu->obu, (u32)obu->obu_length, hash); + fprintf(stderr, "\tOBU#%d %s hash: ", i+1, gf_av1_get_obu_name(obu->obu_type) ); + for (j=0; j<20; j++) fprintf(stderr, "%02X", hash[j]); + fprintf(stderr, "\n"); + } + gf_odf_av1_cfg_del(av1c); } - gf_odf_av1_cfg_del(av1c); } else if (msub_type == GF_ISOM_SUBTYPE_3GP_H263) { u32 w, h; gf_isom_get_visual_info(file, trackNum, 1, &w, &h); @@ -2786,10 +3320,12 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool if (auxiliary_mimes != NULL) { fprintf(stderr, " - auxiliary-mime-types %s", auxiliary_mimes); } + } else if (mtype == GF_ISOM_MEDIA_SUBT) { + fprintf(stderr, "QT/3GPP subtitle"); } else { fprintf(stderr, "Unknown Text Stream"); } - fprintf(stderr, "\n Size %d x %d - Translation X=%d Y=%d - Layer %d\n", w, h, tx, ty, l); + fprintf(stderr, "\n\tSize %d x %d - Translation X=%d Y=%d - Layer %d\n", w, h, tx, ty, l); } else if (mtype == GF_ISOM_MEDIA_META) { const char *content_encoding = NULL; if (msub_type == GF_ISOM_SUBTYPE_METT) { @@ -2819,44 +3355,131 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool } else { fprintf(stderr, "Unknown Metadata Stream\n"); } - } else if ((msub_type == GF_ISOM_SUBTYPE_MH3D_MHA1) || (msub_type == GF_ISOM_SUBTYPE_MH3D_MHA2)) { - fprintf(stderr, "\tMPEG-H Audio stream - Sample Rate %d - %d channel(s) %d bps\n", sr, nb_ch, (u32) bps); + } else if ((msub_type==GF_ISOM_SUBTYPE_VVC1) || (msub_type==GF_ISOM_SUBTYPE_VVI1)) { + GF_VVCConfig *vvccfg; + u32 w, h; +#if !defined(GPAC_DISABLE_AV_PARSERS) + VVCState *vvc_state; + GF_SAFEALLOC(vvc_state, VVCState); + if (vvc_state) vvc_state->sps_active_idx = -1; +#endif + + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + if (full_dump) fprintf(stderr, "\t"); + fprintf(stderr, "VVC Video - Visual Size %d x %d\n", w, h); + vvccfg = gf_isom_vvc_config_get(file, trackNum, 1); + + if (!vvccfg) { + M4_LOG(GF_LOG_ERROR, ("Non-compliant VVC track: No vvcC found in sample description\n")); + } else { + dump_vvc_track_info(file, trackNum, vvccfg +#if !defined(GPAC_DISABLE_AV_PARSERS) + , vvc_state +#endif + ); + gf_odf_vvc_cfg_del(vvccfg); + fprintf(stderr, "\n"); + } +#if !defined(GPAC_DISABLE_AV_PARSERS) + if (vvc_state) gf_free(vvc_state); +#endif + } else if ((msub_type == GF_ISOM_SUBTYPE_MH3D_MHA1) || (msub_type == GF_ISOM_SUBTYPE_MH3D_MHA2) + || (msub_type == GF_ISOM_SUBTYPE_MH3D_MHM1) || (msub_type == GF_ISOM_SUBTYPE_MH3D_MHM2) + ) { + const u8 *compat_profiles; + u32 nb_compat_profiles; + Bool valid = GF_FALSE; + Bool allow_inband = GF_FALSE; + if ( (msub_type == GF_ISOM_SUBTYPE_MH3D_MHM1) || (msub_type == GF_ISOM_SUBTYPE_MH3D_MHM2)) + allow_inband = GF_TRUE; + + fprintf(stderr, "\tMPEG-H Audio stream - Sample Rate %d\n", sr); + esd = gf_media_map_esd(file, trackNum, 1); if (!esd || !esd->decoderConfig || !esd->decoderConfig->decoderSpecificInfo - || !esd->decoderConfig->decoderSpecificInfo->data || (esd->decoderConfig->decoderSpecificInfo->dataLength<5) + || !esd->decoderConfig->decoderSpecificInfo->data ) { - fprintf(stderr, "\tInvalid MPEG-H audio config\n"); - } else { - fprintf(stderr, "\tProfileLevelIndication: %02X\n", esd->decoderConfig->decoderSpecificInfo->data[1]); + if (allow_inband) { + GF_ISOSample *samp = gf_isom_get_sample(file, trackNum, 1, NULL); + if (samp) { + u64 ch_layout=0; + s32 PL = gf_mpegh_get_mhas_pl(samp->data, samp->dataLength, &ch_layout); + if (PL>=0) { + fprintf(stderr, "\tProfileLevelIndication: 0x%02X", PL); + if (ch_layout) + fprintf(stderr, " - Reference Channel Layout %s", gf_audio_fmt_get_layout_name(ch_layout) ); + fprintf(stderr, "\n"); + } + gf_isom_sample_del(&samp); + } + valid = GF_TRUE; + } + } else if (esd->decoderConfig->decoderSpecificInfo->dataLength>=5) { + fprintf(stderr, "\tProfileLevelIndication: 0x%02X - Reference Channel Layout %s\n", esd->decoderConfig->decoderSpecificInfo->data[1] + , gf_audio_fmt_get_layout_name_from_cicp(esd->decoderConfig->decoderSpecificInfo->data[2]) + ); + valid = GF_TRUE; + } + if (!valid) { + M4_LOG(GF_LOG_ERROR, ("Invalid MPEG-H audio config\n")); } if (esd) gf_odf_desc_del((GF_Descriptor *)esd); - } else if ((msub_type == GF_ISOM_SUBTYPE_MH3D_MHM1) || (msub_type == GF_ISOM_SUBTYPE_MH3D_MHM2)) { - fprintf(stderr, "\tMPEG-H AudioMux stream - Sample Rate %d - %d channel(s) %d bps\n", sr, nb_ch, (u32) bps); - esd = gf_media_map_esd(file, trackNum, 1); - if (!esd || !esd->decoderConfig || !esd->decoderConfig->decoderSpecificInfo - || !esd->decoderConfig->decoderSpecificInfo->data) { - GF_ISOSample *samp = gf_isom_get_sample(file, trackNum, 1, NULL); - if (samp) { - s32 PL = gf_mpegh_get_mhas_pl(samp->data, samp->dataLength); - if (PL>=0) - fprintf(stderr, "\tProfileLevelIndication: %02X\n", PL); - gf_isom_sample_del(&samp); - } - } else if (esd->decoderConfig->decoderSpecificInfo->dataLength<5) { - fprintf(stderr, "\tInvalid MPEG-H audio config\n"); + compat_profiles = gf_isom_get_mpegh_compatible_profiles(file, trackNum, 1, &nb_compat_profiles); + for (i=0; idecoderConfig->decoderSpecificInfo->data[1]); + fprintf(stderr, "%s\n", gf_codecid_name(codecid) ); } - if (esd) gf_odf_desc_del((GF_Descriptor *)esd); + } else if (pfmt) { + u32 w, h; + gf_isom_get_visual_info(file, trackNum, 1, &w, &h); + fprintf(stderr, "Raw video %s - Resolution %d x %d\n", gf_pixel_fmt_name(pfmt), w, h); + } else if (msub_type==GF_QT_SUBTYPE_TMCD) { + u32 stsd_idx; + GF_ISOSample *sample = gf_isom_get_sample(file, trackNum, 1, &stsd_idx); + fprintf(stderr, "Time Code stream\n"); + if (sample) { + u32 tmcd_flags, tmcd_num, tmcd_den, tmcd_fpt; + + gf_isom_get_tmcd_config(file, trackNum, stsd_idx, &tmcd_flags, &tmcd_num, &tmcd_den, &tmcd_fpt); + if (sample->data) { + char szTimecode[100]; + gf_inspect_format_timecode(sample->data, sample->dataLength, tmcd_flags, tmcd_num, tmcd_den, tmcd_fpt, szTimecode); + fprintf(stderr, "\tFirst timecode: %s\n", szTimecode); + } + gf_isom_sample_del(&sample); + } + } else if (msub_type==GF_ISOM_SUBTYPE_OPUS) { + fprintf(stderr, "\tOpus Audio - Sample Rate %d ch %d\n", sr, nb_ch); } else { - GF_GenericSampleDescription *udesc = gf_isom_get_generic_sample_description(file, trackNum, 1); + GF_GenericSampleDescription *udesc; + + udesc = gf_isom_get_generic_sample_description(file, trackNum, 1); if (udesc) { if (gf_isom_is_video_handler_type(mtype) ) { - fprintf(stderr, "%s Track - Compressor \"%s\" - Resolution %d x %d\n", - (mtype == GF_ISOM_MEDIA_VISUAL?"Visual":"Auxiliary Video"), + fprintf(stderr, "%s - Compressor \"%s\" - Resolution %d x %d\n", + ( (mtype == GF_ISOM_MEDIA_VISUAL ? "Visual" : "Auxiliary Video") ), udesc->compressor_name, udesc->width, udesc->height); } else if (mtype==GF_ISOM_MEDIA_AUDIO) { - fprintf(stderr, "Audio Track - Sample Rate %d - %d channel(s)\n", udesc->samplerate, udesc->nb_channels); + fprintf(stderr, "Audio - Sample Rate %d - %d channel(s)\n", udesc->samplerate, udesc->nb_channels); } else { fprintf(stderr, "Unknown media type\n"); } @@ -2873,39 +3496,85 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool } } - { - char szCodec[RFC6381_CODEC_NAME_SIZE_MAX]; - GF_Err e = gf_media_get_rfc_6381_codec_name(file, trackNum, szCodec, GF_FALSE, GF_FALSE); - if (e == GF_OK) { - fprintf(stderr, "\tRFC6381 Codec Parameters: %s\n", szCodec); - } - } - DumpMetaItem(file, 0, trackNum, "Track Meta"); + /*Crypto info*/ + if (gf_isom_is_track_encrypted(file, trackNum)) { + const char *scheme_URI, *KMS_URI; + u32 scheme_type, version; + u32 IV_size; + Bool use_sel_enc; - gf_isom_get_track_switch_group_count(file, trackNum, &alt_group, &nb_groups); - if (alt_group) { - fprintf(stderr, "Alternate Group ID %d\n", alt_group); - for (i=0; iDTS+samp->CTS_Offset; size += samp->dataLength; rate += samp->dataLength; - if (samp->DTS - time_slice>ts) { - if (max_rate < rate) max_rate = rate; + if ((samp->DTS - time_slice > ts) || (j+1==count) ) { + Double max_tmp = rate * ts / (samp->DTS - time_slice); + if (max_rate < max_tmp ) + max_rate = max_tmp; + rate = 0; time_slice = samp->DTS; } @@ -2969,28 +3641,25 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool if (csize && cdur) { fprintf(stderr, "\tConstant sample size %d bytes and dur %d / %d\n", csize, cdur, ts); } - scale = 1000; - scale /= ts; - dur = (u64) (scale * (s64)dur); + scale = 1000.0 / ts; + dur = (u64) (scale * dur); fprintf(stderr, "\tTotal size "LLU" bytes - Total samples duration "LLU" ms\n", size, dur); if (!dur) { fprintf(stderr, "\n"); return; } /*rate in byte, dur is in ms*/ - rate = (u32) ((size * 8 * 1000) / dur); + rate = 8000.0 * size / dur; if (!max_rate) max_rate = rate; else - max_rate *= 8; + max_rate *= 8.0; if (rate >= 1500) { - rate /= 1000; - max_rate /= 1000; - fprintf(stderr, "\tAverage rate %d kbps - Max Rate %d kbps\n", rate, max_rate); + fprintf(stderr, "\tAverage rate %.2f kbps - Max Rate %.2f kbps\n", rate/1000, max_rate/1000); } else { - fprintf(stderr, "\tAverage rate %d bps - Max Rate %d bps\n", rate, max_rate); + fprintf(stderr, "\tAverage rate %.2f bps - Max Rate %.2f bps\n", rate, max_rate); } { @@ -3013,27 +3682,32 @@ void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool } } -void DumpMovieInfo(GF_ISOFile *file) +void DumpMovieInfo(GF_ISOFile *file, Bool full_dump) { GF_InitialObjectDescriptor *iod; - u32 i, brand, min, timescale, count, tag_len; - const u8 *tag; + Bool dump_m4sys = GF_FALSE; + u32 i, brand, min, timescale, count, data_len; + const u8 *data; u64 create, modif; + Bool has_itags = GF_FALSE; char szDur[50]; - DumpMetaItem(file, 1, 0, "Root Meta"); + DumpMetaItem(file, 1, 0, "# File Meta"); if (!gf_isom_has_movie(file)) { if (gf_isom_has_segment(file, &brand, &min)) { count = gf_isom_segment_get_fragment_count(file); fprintf(stderr, "File is a segment - %d movie fragments - Brand %s (version %d):\n", count, gf_4cc_to_str(brand), min); for (i=0; i1 ? "s" : ""); + fprintf(stderr, "# Movie Info - %d track%s - TimeScale %d\n", i, i>1 ? "s" : "", timescale); - fprintf(stderr, "\tComputed Duration %s", format_duration(gf_isom_get_duration(file), timescale, szDur)); - fprintf(stderr, " - Indicated Duration %s\n", format_duration(gf_isom_get_original_duration(file), timescale, szDur)); + modif = gf_isom_get_duration(file); + create = gf_isom_get_original_duration(file); + fprintf(stderr, "Duration %s", format_duration(create, timescale, szDur)); + if (create!=modif) { + fprintf(stderr, " (recomputed %s)", format_duration(modif, timescale, szDur)); + } + fprintf(stderr, "\n"); #ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (gf_isom_is_fragmented(file)) { - fprintf(stderr, "\tFragmented File: yes - duration %s\n%d fragments - %d SegmentIndexes\n", format_duration(gf_isom_get_fragmented_duration(file), timescale, szDur), gf_isom_get_fragments_count(file, 0) , gf_isom_get_fragments_count(file, 1) ); + fprintf(stderr, "Fragmented: yes - duration %s\n%d fragments - %d SegmentIndexes\n", format_duration(gf_isom_get_fragmented_duration(file), timescale, szDur), gf_isom_get_fragments_count(file, 0) , gf_isom_get_fragments_count(file, 1) ); } else { - fprintf(stderr, "\tFragmented File: no\n"); + fprintf(stderr, "Fragmented: no\n"); } #endif if (gf_isom_moov_first(file)) - fprintf(stderr, "\tFile suitable for progressive download (moov before mdat)\n"); + fprintf(stderr, "Progressive (moov before mdat)\n"); if (gf_isom_get_brand_info(file, &brand, &min, &count) == GF_OK) { - fprintf(stderr, "\tFile Brand %s - version %d\n\t\tCompatible brands:", gf_4cc_to_str(brand), min); + fprintf(stderr, "Major Brand %s - version %d - compatible brands:", gf_4cc_to_str(brand), min); for (i=0; iESDescriptors)) fprintf(stderr, "No streams included in root OD\n"); + if (!gf_list_count(iod->ESDescriptors)) + fprintf(stderr, "No streams included in root OD\n"); + else + dump_m4sys = GF_TRUE; + gf_odf_desc_del((GF_Descriptor *) iod); - } else { - fprintf(stderr, "File has no MPEG4 IOD/OD\n"); } if (gf_isom_is_JPEG2000(file)) fprintf(stderr, "File is JPEG 2000\n"); @@ -3114,57 +3796,95 @@ void DumpMovieInfo(GF_ISOFile *file) } } - if (gf_isom_apple_get_tag(file, 0, &tag, &tag_len) == GF_OK) { + if (gf_isom_apple_get_tag(file, 0, &data, &data_len) == GF_OK) { + has_itags = GF_TRUE; fprintf(stderr, "\niTunes Info:\n"); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_NAME, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tName: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_ARTIST, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tArtist: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_ALBUM, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tAlbum: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_COMMENT, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tComment: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_COMPOSER, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tComposer: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_WRITER, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tWriter: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_ALBUM_ARTIST, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tAlbum Artist: %s\n", tag); - - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_GENRE, &tag, &tag_len)==GF_OK) { - if (tag[0]) { - fprintf(stderr, "\tGenre: %s\n", tag); - } else { - fprintf(stderr, "\tGenre: %s\n", gf_id3_get_genre(((u8*)tag)[1])); - } - } - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_COMPILATION, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tCompilation: %s\n", tag[0] ? "Yes" : "No"); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_GAPLESS, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tGapless album: %s\n", tag[0] ? "Yes" : "No"); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_CREATED, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tCreated: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_DISK, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tDisk: %d / %d\n", tag[3], tag[5]); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TOOL, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tEncoder Software: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_ENCODER, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tEncoded by: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TEMPO, &tag, &tag_len)==GF_OK) { - if (tag[0]) { - fprintf(stderr, "\tTempo (BPM): %s\n", tag); - } else { - fprintf(stderr, "\tTempo (BPM): %d\n", tag[1]); + i=0; + while (1) { + u32 int_val2, flags, itype; + GF_ISOiTunesTag tag; + u64 int_val; + s32 tag_idx; + GF_Err e = gf_isom_apple_enum_tag(file, i, &tag, &data, &data_len, &int_val, &int_val2, &flags); + if (e) break; + i++; + + tag_idx = gf_itags_find_by_itag(tag); + if (tag_idx<0) { + fprintf(stderr, "\t%s: %s\n", gf_4cc_to_str(tag), data); + continue; } - } - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TRACKNUMBER, &tag, &tag_len)==GF_OK) { - if (tag[0]) { - fprintf(stderr, "\tTrackNumber: %s\n", tag); - } else { - fprintf(stderr, "\tTrackNumber: %d / %d\n", (0xff00 & (tag[2]<<8)) | (0xff & tag[3]), (0xff00 & (tag[4]<<8)) | (0xff & tag[5])); + fprintf(stderr, "\t%s: ", gf_itags_get_name(tag_idx) ); + itype = gf_itags_get_type(tag_idx); + switch (itype) { + case GF_ITAG_BOOL: fprintf(stderr, int_val ? "yes" : "no"); break; + case GF_ITAG_INT8: + case GF_ITAG_INT16: + case GF_ITAG_INT32: + case GF_ITAG_INT64: + fprintf(stderr, LLU, int_val); + break; + case GF_ITAG_FRAC6: + case GF_ITAG_FRAC8: + fprintf(stderr, LLU" / %u", int_val, int_val2); + break; + case GF_ITAG_FILE: + if (flags==14) fprintf(stderr, "PNG File"); + else if (flags==13) fprintf(stderr, "JPEG File"); + else fprintf(stderr, "unknown (flags %d)", flags); + break; + case GF_ITAG_ID3_GENRE: + if (int_val) { + fprintf(stderr, "%s", gf_id3_get_genre((u32) int_val) ); + break; + } + //fallthrough + default: + if (data) + fprintf(stderr, "%s", data); + else + fprintf(stderr, data_len ? "none" : "unknown"); + break; } + fprintf(stderr, "\n"); } - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TRACK, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tTrack: %s\n", tag); - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_GROUP, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tGroup: %s\n", tag); - - if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_COVER_ART, &tag, &tag_len)==GF_OK) { - if (tag_len>>31) fprintf(stderr, "\tCover Art: PNG File\n"); - else fprintf(stderr, "\tCover Art: JPEG File\n"); + } + i=0; + while (1) { + u32 type, version; + char *wmatag; + GF_Err e = gf_isom_wma_enum_tag(file, i, &wmatag, &data, &data_len, &version, &type); + if (e) break; + if (!i) { + fprintf(stderr, "\nWMA Info:\n"); + } + i++; + fprintf(stderr, "\t%s", wmatag); + if (version!=1) + fprintf(stderr, " (version %d)", version); + fprintf(stderr, ": "); + + if (type) { + fprintf(stderr, "unknown type %d\n", type); + } else { + u16 *src_str = (u16 *) data; + u32 len = UTF8_MAX_BYTES_PER_CHAR * gf_utf8_wcslen(src_str); + char *utf8str = (char *)gf_malloc(len + 1); + u32 res_len = gf_utf8_wcstombs(utf8str, len, (const unsigned short **) &src_str); + if (res_len != GF_UTF8_FAIL) { + utf8str[res_len] = 0; + fprintf(stderr, "%s\n", utf8str); + } + gf_free(utf8str); } } - print_udta(file, 0); + + print_udta(file, 0, has_itags); fprintf(stderr, "\n"); for (i=0; iDTS ? pck->DTS : pck->PTS) / 90000.0; diff -= pes->last_pcr_value / (300.0 * 90000); fprintf(dumper->timestamps_info_file, "\t%f\n", diff); - if (diff<0) fprintf(stderr, "Warning: detected PTS/DTS value less than current PCR of %g sec\n", diff); + if (diff<0) { + M4_LOG(GF_LOG_WARNING, ("Warning: detected PTS/DTS value less than current PCR of %g sec\n", diff)); + } } else { fprintf(dumper->timestamps_info_file, "\t\n"); } @@ -3411,7 +4133,7 @@ void dump_mpeg2_ts(char *mpeg2ts_file, char *out_name, Bool prog_num) src = gf_fopen(mpeg2ts_file, "rb"); if (!src) { - fprintf(stderr, "Cannot open %s: no such file\n", mpeg2ts_file); + M4_LOG(GF_LOG_ERROR, ("Cannot open %s: no such file\n", mpeg2ts_file)); return; } ts = gf_m2ts_demux_new(); @@ -3467,7 +4189,7 @@ void dump_mpeg2_ts(char *mpeg2ts_file, char *out_name, Bool prog_num) sprintf(dumper.timestamps_info_name, "%s_prog_%d_timestamps.txt", mpeg2ts_file, prog_num/*, mpeg2ts_file*/); dumper.timestamps_info_file = gf_fopen(dumper.timestamps_info_name, "wt"); if (!dumper.timestamps_info_file) { - fprintf(stderr, "Cannot open file %s\n", dumper.timestamps_info_name); + M4_LOG(GF_LOG_ERROR, ("Cannot open file %s\n", dumper.timestamps_info_name)); return; } fprintf(dumper.timestamps_info_file, "PCK#\tPID\tPCR\tDTS\tPTS\tRAP\tDiscontinuity\tDTS-PCR Diff\n"); @@ -3503,9 +4225,6 @@ void dump_mpeg2_ts(char *mpeg2ts_file, char *out_name, Bool prog_num) #endif /*GPAC_DISABLE_MPEG2TS*/ -#include -#include - void get_file_callback(void *usr_cbk, GF_NETIO_Parameter *parameter) { if (parameter->msg_type==GF_NETIO_DATA_EXCHANGE) { @@ -3585,7 +4304,7 @@ static void revert_cache_file(char *item_path) gf_free(dst_name); } else { - fprintf(stderr, "Failed to reverse %s cache file\n", item_path); + M4_LOG(GF_LOG_ERROR, ("Failed to reverse %s cache file\n", item_path)); } gf_cfg_del(cached); gf_file_delete(szPATH); @@ -3703,7 +4422,7 @@ GF_Err rip_mpd(const char *mpd_src, const char *output_dir) } if (rep->segment_base) segment_base=GF_TRUE; - e = gf_mpd_resolve_url(mpd, rep, as, period, mpd_src, 0, GF_MPD_RESOLVE_URL_INIT, 0, 0, &seg_url, &out_range_start, &out_range_end, &segment_duration, &is_in_base_url, NULL, NULL); + e = gf_mpd_resolve_url(mpd, rep, as, period, mpd_src, 0, GF_MPD_RESOLVE_URL_INIT, 0, 0, &seg_url, &out_range_start, &out_range_end, &segment_duration, &is_in_base_url, NULL, NULL, NULL); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Error resolving init segment name : %s\n", gf_error_to_string(e))); continue; @@ -3731,7 +4450,7 @@ GF_Err rip_mpd(const char *mpd_src, const char *output_dir) if (segment_base) continue; while (1) { - e = gf_mpd_resolve_url(mpd, rep, as, period, mpd_src, 0, GF_MPD_RESOLVE_URL_MEDIA, seg_idx, 0, &seg_url, &out_range_start, &out_range_end, &segment_duration, NULL, NULL, NULL); + e = gf_mpd_resolve_url(mpd, rep, as, period, mpd_src, 0, GF_MPD_RESOLVE_URL_MEDIA, seg_idx, 0, &seg_url, &out_range_start, &out_range_end, &segment_duration, NULL, NULL, NULL, NULL); if (e) { if (e<0) { GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Error resolving segment name : %s\n", gf_error_to_string(e))); diff --git a/applications/mp4box/fileimport.c b/applications/mp4box/fileimport.c index 1ad2e19..7054f72 100644 --- a/applications/mp4box/fileimport.c +++ b/applications/mp4box/fileimport.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2020 + * Copyright (c) Telecom ParisTech 2000-2021 * All rights reserved * * This file is part of GPAC / mp4box application @@ -56,7 +56,7 @@ typedef struct GF_List *imports; } WGTEnum; -GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array) +GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array, Bool is_string) { u8 *data = NULL; GF_Err res = GF_OK; @@ -67,7 +67,12 @@ GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, B if (!udta_type && !is_box_array) return GF_BAD_PARAM; if (!src || !strlen(src)) { - return gf_isom_remove_user_data(dest, tracknum, udta_type, uuid); + GF_Err e = gf_isom_remove_user_data(dest, tracknum, udta_type, uuid); + if (e==GF_EOS) { + e = GF_OK; + M4_LOG(GF_LOG_WARNING, ("No track.udta found, ignoring\n")); + } + return e; } #ifndef GPAC_DISABLE_CORE_TOOLS @@ -78,7 +83,11 @@ GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, B size = gf_base64_decode((u8 *)src, size, data, size); } else #endif - { + if (is_string) { + data = (u8 *) src; + size = (u32) strlen(src)+1; + is_box_array = 0; + } else { GF_Err e = gf_file_load_data(src, (u8 **) &data, &size); if (e) return e; } @@ -89,7 +98,8 @@ GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, B } else { res = gf_isom_add_user_data(dest, tracknum, udta_type, uuid, data, size); } - gf_free(data); + if (!is_string) + gf_free(data); } return res; } @@ -117,7 +127,7 @@ void convert_file_info(char *inName, GF_ISOTrackID trackID) e = gf_media_import(&import); if (e) { - fprintf(stderr, "Error probing file %s: %s\n", inName, gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Error probing file %s: %s\n", inName, gf_error_to_string(e))); return; } if (trackID) { @@ -125,7 +135,7 @@ void convert_file_info(char *inName, GF_ISOTrackID trackID) } else { fprintf(stderr, "Import probing results for %s:\n", inName); if (!import.nb_tracks) { - fprintf(stderr, "File has no selectable tracks\n"); + M4_LOG(GF_LOG_WARNING, ("File has no selectable tracks\n")); return; } fprintf(stderr, "File has %d tracks\n", import.nb_tracks); @@ -136,7 +146,7 @@ void convert_file_info(char *inName, GF_ISOTrackID trackID) found = 0; for (i=0; inum = 0; + dur->den = 0; + } + if (!gf_parse_lfrac(str, f)) e = GF_BAD_PARAM; + return e; +} + +Bool scan_color(char *val, u32 *clr_prim, u32 *clr_tranf, u32 *clr_mx, Bool *clr_full_range) +{ + char *sep = strchr(val, ','); + if (!sep) return GF_FALSE; + sep[0] = 0; + *clr_prim = gf_cicp_parse_color_primaries(val); + sep[0] = ','; + if (*clr_prim == (u32) -1) return GF_FALSE; + val = sep+1; + + sep = strchr(val, ','); + if (!sep) return GF_FALSE; + sep[0] = 0; + *clr_tranf = gf_cicp_parse_color_transfer(val); + sep[0] = ','; + if (*clr_tranf == (u32) -1) return GF_FALSE; + val = sep+1; + + sep = strchr(val, ','); + if (sep) sep[0] = 0; + *clr_mx = gf_cicp_parse_color_matrix(val); + if (sep) sep[0] = ','; + if (*clr_mx == (u32) -1) return GF_FALSE; + if (!sep) return GF_TRUE; + + val = sep+1; + if (!strcmp(val, "yes") || !strcmp(val, "on")) { + *clr_full_range = GF_TRUE; + return GF_TRUE; + } + if (!strcmp(val, "no") || !strcmp(val, "off")) { + *clr_full_range = GF_FALSE; + return GF_TRUE; + } + + if (sscanf(val, "%d", (s32*) clr_full_range) == 1) + return GF_TRUE; + + return GF_FALSE; +} + +static GF_Err set_dv_profile(GF_ISOFile *dest, u32 track, char *dv_profile_str) +{ + GF_Err e; + Bool remove=GF_FALSE; + Bool force_dv=GF_FALSE; + u32 dv_profile = 0; + u32 dv_compat_id=0; + char *sep = strchr(dv_profile_str, '.'); + if (sep) { + sep[0] = 0; + if (!strcmp(sep+1, "none")) dv_compat_id=0; + else if (!strcmp(sep+1, "hdr10")) dv_compat_id=1; + else if (!strcmp(sep+1, "bt709")) dv_compat_id=2; + else if (!strcmp(sep+1, "hlg709")) dv_compat_id=3; + else if (!strcmp(sep+1, "hlg2100")) dv_compat_id=4; + else if (!strcmp(sep+1, "bt2020")) dv_compat_id=5; + else if (!strcmp(sep+1, "brd")) dv_compat_id=6; + else if ((sep[1]>='0') && (sep[1]<='9')) dv_compat_id=atoi(sep+1); + else { + M4_LOG(GF_LOG_WARNING, ("DV compatibility mode %s not recognized, using none\n", sep+1)); + } + } + if (dv_profile_str[0]=='f') { + force_dv = GF_TRUE; + dv_profile_str++; + } + + if (!strcmp(dv_profile_str, "none")) { + remove = GF_TRUE; + } else { + dv_profile = atoi(dv_profile_str); + if (dv_profile==8) { + if ((dv_compat_id!=1) && (dv_compat_id!=2)) { + M4_LOG(GF_LOG_ERROR, ("DV profile 8 must indicate a compatibility mode `hdr10` or `bt709`\n")); + return GF_BAD_PARAM; + } + } + } + + GF_DOVIDecoderConfigurationRecord *dovi = gf_isom_dovi_config_get(dest, track, 1); + if (dovi) { + dovi->dv_profile = dv_profile; + dovi->dv_bl_signal_compatibility_id = dv_compat_id; + dovi->force_dv = force_dv; + e = gf_isom_set_dolby_vision_profile(dest, track, 1, remove ? NULL : dovi); + gf_odf_dovi_cfg_del(dovi); + return e; + } + if (remove) return GF_OK; + u32 nb_samples = gf_isom_get_sample_count(dest, track); + if (!nb_samples) { + M4_LOG(GF_LOG_ERROR, ("No DV config in file and no samples, cannot guess DV config\n")); + return GF_NOT_SUPPORTED; + } + + GF_DOVIDecoderConfigurationRecord _dovi; + memset(&_dovi, 0, sizeof(GF_DOVIDecoderConfigurationRecord)); + _dovi.dv_version_major = 1; + _dovi.dv_version_minor = 0; + _dovi.dv_profile = dv_profile; + _dovi.dv_bl_signal_compatibility_id = dv_compat_id; + _dovi.force_dv = force_dv; + + u32 w, h; + Bool is_avc = GF_FALSE; + + e = gf_isom_get_visual_info(dest, track, 1, &w, &h); + if (e) return e; + //no DV profile present in file, we need to guess + GF_AVCConfig *avcc = gf_isom_avc_config_get(dest, track, 1); + GF_HEVCConfig *hvcc = gf_isom_hevc_config_get(dest, track, 1); + + if (!avcc && !hvcc) { + M4_LOG(GF_LOG_WARNING, ("DV profile can only be set on AVC or HEVC tracks\n")); + return GF_BAD_PARAM; + } + + u32 nalu_length = avcc ? avcc->nal_unit_size : hvcc->nal_unit_size; + if (avcc) { + is_avc = GF_TRUE; + gf_odf_avc_cfg_del(avcc); + } + if (hvcc) gf_odf_hevc_cfg_del(hvcc); + + //inspect at most first 50 samples + u32 i; + for (i=0; i<50; i++) { + u32 stsd_idx; + GF_BitStream *bs; + + GF_ISOSample *samp = gf_isom_get_sample(dest, track, i+1, &stsd_idx); + if (!samp) break; + + bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ); + + while (gf_bs_available(bs)) { + u32 nal_type; + u32 nal_size = gf_bs_read_int(bs, nalu_length*8); + if (is_avc) { + nal_type = gf_bs_read_u8(bs); + nal_type = nal_type & 0x1F; + nal_size--; + if (nal_type == GF_AVC_NALU_DV_RPU) _dovi.rpu_present_flag = 1; + else if (nal_type == GF_AVC_NALU_DV_EL) _dovi.el_present_flag = 1; + else if (nal_type <= GF_AVC_NALU_IDR_SLICE) _dovi.bl_present_flag = 1; + } else { + gf_bs_read_int(bs, 1); + nal_type = gf_bs_read_int(bs, 6); + gf_bs_read_int(bs, 1); + nal_size--; + if (nal_type == GF_HEVC_NALU_DV_RPU) _dovi.rpu_present_flag = 1; + else if (nal_type == GF_HEVC_NALU_DV_EL) _dovi.el_present_flag = 1; + else if (nal_type <= GF_HEVC_NALU_SLICE_CRA) _dovi.bl_present_flag = 1; + } + gf_bs_skip_bytes(bs, nal_size); + } + gf_bs_del(bs); + gf_isom_sample_del(&samp); + } + + u64 mdur = gf_isom_get_media_duration(dest, track); + mdur /= nb_samples; + u32 timescale = gf_isom_get_media_timescale(dest, track); + + _dovi.dv_level = gf_dolby_vision_level(w, h, timescale, mdur, is_avc ? GF_CODECID_AVC : GF_CODECID_HEVC); + return gf_isom_set_dolby_vision_profile(dest, track, 1, &_dovi); +} + + + +GF_Err apply_edits(GF_ISOFile *dest, u32 track, char *edits) +{ + u32 movie_ts = gf_isom_get_timescale(dest); + u32 media_ts = gf_isom_get_media_timescale(dest, track); + u64 media_dur = gf_isom_get_media_duration(dest, track); + + while (edits) { + GF_Err e; + char c=0; + char *sep = strchr(edits+1, 'r'); + if (!sep) sep = strchr(edits+1, 'e'); + if (sep) { + c = sep[0]; + sep[0] = 0; + } + + //remove all edits + if (edits[0] == 'r') { + e = gf_isom_remove_edits(dest, track); + if (e) goto error; + } + else if (edits[0]=='e') { + u64 movie_t, media_t, edur; + u32 rate; + GF_Fraction64 movie_time, media_time, media_rate, edit_dur; + char *mtime_sep; + + edits+=1; + mtime_sep = strchr(edits, ','); + movie_time.den = media_time.den = media_rate.den = 0; + if (!mtime_sep) { + e = parse_fracs(edits, &movie_time, &edit_dur); + if (e) goto error; + } + else { + mtime_sep[0] = 0; + e = parse_fracs(edits, &movie_time, &edit_dur); + if (e) goto error; + mtime_sep[0] = ','; + edits = mtime_sep+1; + mtime_sep = strchr(edits, ','); + if (!mtime_sep) { + e = parse_fracs(edits, &media_time, NULL); + if (e) goto error; + media_rate.num = media_rate.den = 1; + } else { + mtime_sep[0] = 0; + e = parse_fracs(edits, &media_time, NULL); + if (e) goto error; + mtime_sep[0] = ','; + e = parse_fracs(mtime_sep+1, &media_rate, NULL); + if (e) goto error; + } + } + if (!movie_time.den || (movie_time.num<0)) { + e = GF_BAD_PARAM; + fprintf(stderr, "Wrong edit format %s, movie time must be valid and >= 0\n", edits); + goto error; + } + movie_t = movie_time.num * movie_ts / movie_time.den; + if (!edit_dur.den || !edit_dur.num) { + edur = media_dur; + edur *= movie_ts; + edur /= media_ts; + } else { + edur = edit_dur.num; + edur *= movie_ts; + edur /= edit_dur.den; + if (edur>media_dur) + edur = media_dur; + } + if (!media_time.den) { + e = gf_isom_set_edit(dest, track, movie_t, edur, 0, GF_ISOM_EDIT_EMPTY); + } else { + rate = 0; + if (media_rate.den) { + u64 frac; + rate = (u32) ( media_rate.num / media_rate.den ); + frac = media_rate.num - rate*media_rate.den; + frac *= 0xFFFF; + frac /= media_rate.den; + rate = (rate<<16) | (u32) frac; + } + media_t = media_time.num * media_ts / media_time.den; + e = gf_isom_set_edit_with_rate(dest, track, movie_t, edur, media_t, rate); + } + if (e==GF_EOS) { + fprintf(stderr, "Inserted empty edit before edit at start time "LLD"/"LLU"\n", movie_time.num, movie_time.den); + e = GF_OK; + } + if (e) goto error; + } else { + e = GF_BAD_PARAM; + fprintf(stderr, "Wrong edit format %s, should start with 'e' or 'r'\n", edits); + goto error; + } +error: + if (sep) sep[0] = c; + if (e) return e; + + if (!sep) break; + edits = sep; + } + return GF_OK; } -GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, GF_FilterSession *fsess, char **mux_args_if_first_pass, u32 tk_idx) +static const char *videofmt_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef"}; + + +GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, GF_FilterSession *fsess, char **mux_args_if_first_pass, char **mux_sid_if_first_pass, u32 tk_idx) { - u32 track_id, i, j, timescale, track, stype, profile, level, new_timescale, rescale_num, rescale_den, svc_mode, txt_flags, split_tile_mode, temporal_mode, nb_tracks; - s32 par_d, par_n, prog_id, delay, force_rate, moov_timescale; - s32 tw, th, tx, ty, txtw, txth, txtx, txty; - Bool do_audio, do_video, do_auxv,do_pict, do_all, disable, track_layout, text_layout, chap_ref, is_chap, is_chap_file, keep_handler, negative_cts_offset, rap_only, refs_only, force_par, rewrite_bs; - u32 group, handler, rvc_predefined, check_track_for_svc, check_track_for_lhvc, check_track_for_hevc; + u32 track_id, i, j, timescale, track, stype, profile, compat, level, new_timescale, rescale_num, rescale_den, svc_mode, txt_flags, split_tile_mode, temporal_mode, nb_tracks; + s32 par_d, par_n, prog_id, force_rate, moov_timescale; + s32 tw, th, tx, ty, tz, txtw, txth, txtx, txty; + Bool do_audio, do_video, do_auxv,do_pict, do_all, track_layout, text_layout, chap_ref, is_chap, is_chap_file, keep_handler, rap_only, refs_only, force_par, rewrite_bs; + u32 group, handler, rvc_predefined, check_track_for_svc, check_track_for_lhvc, check_track_for_hevc, do_disable; const char *szLan; GF_Err e = GF_OK; - u32 tmcd_track = 0; + GF_Fraction delay; + u32 tmcd_track = 0, neg_ctts_mode=0; Bool keep_audelim = GF_FALSE; u32 print_stats_graph=fs_dump_flags; GF_MediaImporter import; - char *ext, szName[1000], *handler_name, *rvc_config, *chapter_name; + char *ext, *final_name=NULL, *handler_name, *rvc_config, *chapter_name; GF_List *kinds; GF_TextFlagsMode txt_mode = GF_ISOM_TEXT_FLAGS_OVERWRITE; u8 max_layer_id_plus_one, max_temporal_id_plus_one; @@ -289,14 +606,15 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction Bool has_mx=GF_FALSE; s32 mx[9]; u32 bitdepth=0; - u32 dv_profile=0; /*Dolby Vision*/ + char dv_profile[100]; /*Dolby Vision*/ u32 clr_type=0; u32 clr_prim; u32 clr_tranf; u32 clr_mx; - u32 clr_full_range=GF_FALSE; + Bool rescale_override=GF_FALSE; + Bool clr_full_range=GF_FALSE; Bool fmt_ok = GF_TRUE; - u32 icc_size=0; + u32 icc_size=0, track_flags=0; u8 *icc_data = NULL; u32 tc_fps_num=0, tc_fps_den=0, tc_h=0, tc_m=0, tc_s=0, tc_f=0, tc_frames_per_tick=0; Bool tc_force_counter=GF_FALSE; @@ -307,12 +625,21 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction char *opt_src = NULL; char *opt_dst = NULL; char *fchain = NULL; + char *edits = NULL; + const char *fail_msg = NULL; + char *hdr_file=NULL; Bool set_ccst=GF_FALSE; Bool has_last_sample_dur=GF_FALSE; + u32 fake_import = 0; GF_Fraction last_sample_dur = {0,0}; - + s32 fullrange, videofmt, colorprim, colortfc, colormx; clap_wn = clap_wd = clap_hn = clap_hd = clap_hon = clap_hod = clap_von = clap_vod = 0; + GF_ISOMTrackFlagOp track_flags_mode=0; + u32 roll_change=0; + u32 roll = 0; + Bool src_is_isom = GF_FALSE; + dv_profile[0] = 0; rvc_predefined = 0; chapter_name = NULL; new_timescale = 1; @@ -325,31 +652,36 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction */ svc_mode = 0; + if (import_flags==0xFFFFFFFF) { + import_flags = 0; + fake_import = 1; + } + memset(&import, 0, sizeof(GF_MediaImporter)); - strcpy(szName, inName); + final_name = gf_strdup(inName); #ifdef WIN32 /*dirty hack for msys&mingw: when we use import options, the ':' separator used prevents msys from translating the path we do this for regular cases where the path starts with the drive letter. If the path start with anything else (/home , /opt, ...) we're screwed :( */ - if ( (szName[0]=='/') && (szName[2]=='/')) { - szName[0] = szName[1]; - szName[1] = ':'; + if ( (final_name[0]=='/') && (final_name[2]=='/')) { + final_name[0] = final_name[1]; + final_name[1] = ':'; } #endif is_chap_file = 0; handler = 0; - disable = 0; + do_disable = 0; chap_ref = 0; is_chap = 0; kinds = gf_list_new(); track_layout = 0; szLan = NULL; - delay = 0; + delay.num = delay.den = 0; group = 0; stype = 0; - profile = level = 0; - negative_cts_offset = 0; + profile = compat = level = 0; + fullrange = videofmt = colorprim = colortfc = colormx = -1; split_tile_mode = 0; temporal_mode = 0; rap_only = 0; @@ -358,34 +690,52 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction max_layer_id_plus_one = max_temporal_id_plus_one = 0; force_rate = -1; - tw = th = tx = ty = txtw = txth = txtx = txty = 0; + tw = th = tx = ty = tz = txtw = txth = txtx = txty = 0; par_d = par_n = -1; force_par = rewrite_bs = GF_FALSE; - ext = gf_url_colon_suffix(szName); + ext_start = gf_file_ext_start(final_name); + ext = strrchr(ext_start ? ext_start : final_name, '#'); + if (!ext) ext = gf_url_colon_suffix(final_name, '='); + char c_sep = ext ? ext[0] : 0; + if (ext) ext[0] = 0; + if (!strlen(final_name) || !strcmp(final_name, "self")) { + fake_import = 2; + } + if (gf_isom_probe_file(final_name)) + src_is_isom = GF_TRUE; + + if (ext) ext[0] = c_sep; + + ext = gf_url_colon_suffix(final_name, '='); + +#define GOTO_EXIT(_msg) if (e) { fail_msg = _msg; goto exit; } + +#define CHECK_FAKEIMPORT(_opt) if (fake_import) { M4_LOG(GF_LOG_ERROR, ("Option %s not available for self-reference import\n", _opt)); e = GF_BAD_PARAM; goto exit; } +#define CHECK_FAKEIMPORT_2(_opt) if (fake_import==1) { M4_LOG(GF_LOG_ERROR, ("Option %s not available for self-reference import\n", _opt)); e = GF_BAD_PARAM; goto exit; } + handler_name = NULL; rvc_config = NULL; while (ext) { - char *ext2 = gf_url_colon_suffix(ext+1); + char *ext2 = gf_url_colon_suffix(ext+1, '='); if (ext2) ext2[0] = 0; /*all extensions for track-based importing*/ if (!strnicmp(ext+1, "dur=", 4)) { - s32 dur_n=0, dur_d=0; - if (strchr(ext, '/')) { - sscanf(ext+5, "%d/%d", &dur_n, &dur_d); - } else if (strchr(ext, '-')) { - dur_n = atoi(ext+5); - dur_d = 1; + CHECK_FAKEIMPORT("dur") + + if (strchr(ext, '-')) { + import.duration.num = atoi(ext+5); + import.duration.den = 1; } else { - //use 1/10 of millisecond precision - dur_n = (u32)( (atof(ext+5) * 10000) + 0.5 ); - dur_d = 10000; + gf_parse_frac(ext+5, &import.duration); } - import.duration.num = dur_n; - import.duration.den = dur_d; + } + else if (!strnicmp(ext+1, "start=", 6)) { + CHECK_FAKEIMPORT("start") + import.start_time = atof(ext+7); } else if (!strnicmp(ext+1, "lang=", 5)) { /* prevent leak if param is set twice */ @@ -394,7 +744,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction szLan = gf_strdup(ext+6); } - else if (!strnicmp(ext+1, "delay=", 6)) delay = atoi(ext+7); + else if (!strnicmp(ext+1, "delay=", 6)) { + if (sscanf(ext+7, "%d/%u", &delay.num, &delay.den)!=2) { + delay.num = atoi(ext+7); + delay.den = 1000; //in ms + } + } else if (!strnicmp(ext+1, "par=", 4)) { if (!stricmp(ext + 5, "none")) { par_n = par_d = 0; @@ -411,9 +766,17 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } if (ext[5]=='w') { rewrite_bs = GF_TRUE; - sscanf(ext+6, "%d:%d", &par_n, &par_d); + if (sscanf(ext+6, "%d:%d", &par_n, &par_d)!=2) { + M4_LOG(GF_LOG_ERROR, ("Unrecognized syntax for par=, expecting N:D got %s\n", ext+5)); + e = GF_BAD_PARAM; + goto exit; + } } else { - sscanf(ext+5, "%d:%d", &par_n, &par_d); + if (sscanf(ext+5, "%d:%d", &par_n, &par_d) != 2) { + M4_LOG(GF_LOG_ERROR, ("Unrecognized syntax for par=, expecting N:D got %s\n", ext+5)); + e = GF_BAD_PARAM; + goto exit; + } } } } @@ -428,10 +791,10 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } else if (!strnicmp(ext+1, "mx=", 3)) { if (strstr(ext+4, "0x")) { - if (sscanf(ext+4, "0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d", &mx[0], &mx[1], &mx[2], &mx[3], &mx[4], &mx[5], &mx[6], &mx[7], &mx[8])==9) { + if (sscanf(ext+4, "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%d", &mx[0], &mx[1], &mx[2], &mx[3], &mx[4], &mx[5], &mx[6], &mx[7], &mx[8])==9) { has_mx=GF_TRUE; } - } else if (sscanf(ext+4, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &mx[0], &mx[1], &mx[2], &mx[3], &mx[4], &mx[5], &mx[6], &mx[7], &mx[8])==9) { + } else if (sscanf(ext+4, "%d,%d,%d,%d,%d,%d,%d,%d,%d", &mx[0], &mx[1], &mx[2], &mx[3], &mx[4], &mx[5], &mx[6], &mx[7], &mx[8])==9) { has_mx=GF_TRUE; } } @@ -439,6 +802,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction handler_name = gf_strdup(ext+6); } else if (!strnicmp(ext+1, "ext=", 4)) { + CHECK_FAKEIMPORT("ext") /*extensions begin with '.'*/ if (*(ext+5) == '.') import.force_ext = gf_strdup(ext+5); @@ -449,45 +813,68 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } } else if (!strnicmp(ext+1, "hdlr=", 5)) handler = GF_4CC(ext[6], ext[7], ext[8], ext[9]); - else if (!strnicmp(ext+1, "disable", 7)) disable = 1; + else if (!strnicmp(ext+1, "stype=", 6)) stype = GF_4CC(ext[7], ext[8], ext[9], ext[10]); + else if (!strnicmp(ext+1, "tkhd", 4)) { + char *flags = ext+6; + if (flags[0]=='+') { track_flags_mode = GF_ISOM_TKFLAGS_ADD; flags += 1; } + else if (flags[0]=='-') { track_flags_mode = GF_ISOM_TKFLAGS_REM; flags += 1; } + else track_flags_mode = GF_ISOM_TKFLAGS_SET; + + if (strstr(flags, "enable")) track_flags |= GF_ISOM_TK_ENABLED; + if (strstr(flags, "movie")) track_flags |= GF_ISOM_TK_IN_MOVIE; + if (strstr(flags, "preview")) track_flags |= GF_ISOM_TK_IN_PREVIEW; + if (strstr(flags, "size_ar")) track_flags |= GF_ISOM_TK_SIZE_IS_AR; + if (!track_flags) { + if (!strnicmp(flags, "0x", 2)) flags += 2; + sscanf(flags, "%X", &track_flags); + } + } else if (!strnicmp(ext+1, "disable", 7)) { + do_disable = !stricmp(ext+1, "disable=no") ? 2 : 1; + } else if (!strnicmp(ext+1, "group=", 6)) { group = atoi(ext+7); if (!group) group = gf_isom_get_next_alternate_group_id(dest); } else if (!strnicmp(ext+1, "fps=", 4)) { u32 ticks, dts_inc; + CHECK_FAKEIMPORT("fps") if (!strcmp(ext+5, "auto")) { - fprintf(stderr, "Warning, fps=auto option is deprecated\n"); + M4_LOG(GF_LOG_ERROR, ("Warning, fps=auto option is deprecated\n")); } else if ((sscanf(ext+5, "%u-%u", &ticks, &dts_inc) == 2) || (sscanf(ext+5, "%u/%u", &ticks, &dts_inc) == 2)) { if (!dts_inc) dts_inc=1; force_fps.num = ticks; force_fps.den = dts_inc; } else { - force_fps.den = 1000; - force_fps.num = (u32) (atof(ext+5) * force_fps.den); + if (gf_sys_old_arch_compat()) { + force_fps.den = 1000; + force_fps.num = (u32) (atof(ext+5) * force_fps.den); + } else { + gf_parse_frac(ext+5, &force_fps); + } } } else if (!stricmp(ext+1, "rap")) rap_only = 1; else if (!stricmp(ext+1, "refs")) refs_only = 1; - else if (!stricmp(ext+1, "trailing")) import_flags |= GF_IMPORT_KEEP_TRAILING; - else if (!strnicmp(ext+1, "agg=", 4)) frames_per_sample = atoi(ext+5); - else if (!stricmp(ext+1, "dref")) import_flags |= GF_IMPORT_USE_DATAREF; - else if (!stricmp(ext+1, "keep_refs")) import_flags |= GF_IMPORT_KEEP_REFS; - else if (!stricmp(ext+1, "nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; - else if (!stricmp(ext+1, "packed")) import_flags |= GF_IMPORT_FORCE_PACKED; - else if (!stricmp(ext+1, "sbr")) import_flags |= GF_IMPORT_SBR_IMPLICIT; - else if (!stricmp(ext+1, "sbrx")) import_flags |= GF_IMPORT_SBR_EXPLICIT; - else if (!stricmp(ext+1, "ovsbr")) import_flags |= GF_IMPORT_OVSBR; - else if (!stricmp(ext+1, "ps")) import_flags |= GF_IMPORT_PS_IMPLICIT; - else if (!stricmp(ext+1, "psx")) import_flags |= GF_IMPORT_PS_EXPLICIT; - else if (!stricmp(ext+1, "mpeg4")) import_flags |= GF_IMPORT_FORCE_MPEG4; - else if (!stricmp(ext+1, "nosei")) import_flags |= GF_IMPORT_NO_SEI; - else if (!stricmp(ext+1, "svc") || !stricmp(ext+1, "lhvc") ) import_flags |= GF_IMPORT_SVC_EXPLICIT; - else if (!stricmp(ext+1, "nosvc") || !stricmp(ext+1, "nolhvc")) import_flags |= GF_IMPORT_SVC_NONE; + else if (!stricmp(ext+1, "trailing")) { CHECK_FAKEIMPORT("trailing") import_flags |= GF_IMPORT_KEEP_TRAILING; } + else if (!strnicmp(ext+1, "agg=", 4)) { CHECK_FAKEIMPORT("agg") frames_per_sample = atoi(ext+5); } + else if (!stricmp(ext+1, "dref")) { CHECK_FAKEIMPORT("dref") import_flags |= GF_IMPORT_USE_DATAREF; } + else if (!stricmp(ext+1, "keep_refs")) { CHECK_FAKEIMPORT("keep_refs") import_flags |= GF_IMPORT_KEEP_REFS; } + else if (!stricmp(ext+1, "nodrop")) { CHECK_FAKEIMPORT("nodrop") import_flags |= GF_IMPORT_NO_FRAME_DROP; } + else if (!stricmp(ext+1, "packed")) { CHECK_FAKEIMPORT("packed") import_flags |= GF_IMPORT_FORCE_PACKED; } + else if (!stricmp(ext+1, "sbr")) { CHECK_FAKEIMPORT("sbr") import_flags |= GF_IMPORT_SBR_IMPLICIT; } + else if (!stricmp(ext+1, "sbrx")) { CHECK_FAKEIMPORT("sbrx") import_flags |= GF_IMPORT_SBR_EXPLICIT; } + else if (!stricmp(ext+1, "ovsbr")) { CHECK_FAKEIMPORT("ovsbr") import_flags |= GF_IMPORT_OVSBR; } + else if (!stricmp(ext+1, "ps")) { CHECK_FAKEIMPORT("ps") import_flags |= GF_IMPORT_PS_IMPLICIT; } + else if (!stricmp(ext+1, "psx")) { CHECK_FAKEIMPORT("psx") import_flags |= GF_IMPORT_PS_EXPLICIT; } + else if (!stricmp(ext+1, "mpeg4")) { CHECK_FAKEIMPORT("mpeg4") import_flags |= GF_IMPORT_FORCE_MPEG4; } + else if (!stricmp(ext+1, "nosei")) { CHECK_FAKEIMPORT("nosei") import_flags |= GF_IMPORT_NO_SEI; } + else if (!stricmp(ext+1, "svc") || !stricmp(ext+1, "lhvc") ) { CHECK_FAKEIMPORT("svc/lhvc") import_flags |= GF_IMPORT_SVC_EXPLICIT; } + else if (!stricmp(ext+1, "nosvc") || !stricmp(ext+1, "nolhvc")) { CHECK_FAKEIMPORT("nosvc/nolhvc") import_flags |= GF_IMPORT_SVC_NONE; } /*split SVC layers*/ else if (!strnicmp(ext+1, "svcmode=", 8) || !strnicmp(ext+1, "lhvcmode=", 9)) { char *mode = ext+9; + CHECK_FAKEIMPORT_2("svcmode/lhvcmode") if (mode[0]=='=') mode = ext+10; if (!stricmp(mode, "splitnox")) @@ -504,6 +891,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction /*split SHVC temporal sublayers*/ else if (!strnicmp(ext+1, "temporal=", 9)) { char *mode = ext+10; + CHECK_FAKEIMPORT_2("svcmode/lhvcmode") if (!stricmp(mode, "split")) temporal_mode = 2; else if (!stricmp(mode, "splitnox")) @@ -511,22 +899,23 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction else if (!stricmp(mode, "splitbase")) temporal_mode = 1; else { - fprintf(stderr, "Unrecognized temporal mode %s, ignoring\n", mode); + M4_LOG(GF_LOG_ERROR, ("Unrecognized temporal mode %s, ignoring\n", mode)); temporal_mode = 0; } } - else if (!stricmp(ext+1, "subsamples")) import_flags |= GF_IMPORT_SET_SUBSAMPLES; - else if (!stricmp(ext+1, "deps")) import_flags |= GF_IMPORT_SAMPLE_DEPS; - else if (!stricmp(ext+1, "ccst")) set_ccst = GF_TRUE; - else if (!stricmp(ext+1, "alpha")) import.is_alpha = GF_TRUE; - else if (!stricmp(ext+1, "forcesync")) import_flags |= GF_IMPORT_FORCE_SYNC; - else if (!stricmp(ext+1, "xps_inband")) xps_inband = 1; - else if (!stricmp(ext+1, "xps_inbandx")) xps_inband = 2; - else if (!stricmp(ext+1, "au_delim")) keep_audelim = GF_TRUE; + else if (!stricmp(ext+1, "subsamples")) { CHECK_FAKEIMPORT("subsamples") import_flags |= GF_IMPORT_SET_SUBSAMPLES; } + else if (!stricmp(ext+1, "deps")) { CHECK_FAKEIMPORT("deps") import_flags |= GF_IMPORT_SAMPLE_DEPS; } + else if (!stricmp(ext+1, "ccst")) { CHECK_FAKEIMPORT("ccst") set_ccst = GF_TRUE; } + else if (!stricmp(ext+1, "alpha")) { CHECK_FAKEIMPORT("alpha") import.is_alpha = GF_TRUE; } + else if (!stricmp(ext+1, "forcesync")) { CHECK_FAKEIMPORT("forcesync") import_flags |= GF_IMPORT_FORCE_SYNC; } + else if (!stricmp(ext+1, "xps_inband")) { CHECK_FAKEIMPORT("xps_inband") xps_inband = 1; } + else if (!stricmp(ext+1, "xps_inbandx")) { CHECK_FAKEIMPORT("xps_inbandx") xps_inband = 2; } + else if (!stricmp(ext+1, "au_delim")) { CHECK_FAKEIMPORT("au_delim") keep_audelim = GF_TRUE; } else if (!strnicmp(ext+1, "max_lid=", 8) || !strnicmp(ext+1, "max_tid=", 8)) { s32 val = atoi(ext+9); + CHECK_FAKEIMPORT_2("max_lid/lhvcmode") if (val < 0) { - fprintf(stderr, "Warning: request max layer/temporal id is negative - ignoring\n"); + M4_LOG(GF_LOG_ERROR, ("Warning: request max layer/temporal id is negative - ignoring\n")); } else { if (!strnicmp(ext+1, "max_lid=", 8)) max_layer_id_plus_one = 1 + (u8) val; @@ -534,14 +923,13 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction max_temporal_id_plus_one = 1 + (u8) val; } } - else if (!stricmp(ext+1, "tiles")) split_tile_mode = 2; - else if (!stricmp(ext+1, "tiles_rle")) split_tile_mode = 3; - else if (!stricmp(ext+1, "split_tiles")) split_tile_mode = 1; + else if (!stricmp(ext+1, "tiles")) { CHECK_FAKEIMPORT_2("tiles") split_tile_mode = 2; } + else if (!stricmp(ext+1, "tiles_rle")) { CHECK_FAKEIMPORT_2("tiles_rle") split_tile_mode = 3; } + else if (!stricmp(ext+1, "split_tiles")) { CHECK_FAKEIMPORT_2("split_tiles") split_tile_mode = 1; } /*force all composition offsets to be positive*/ - else if (!strnicmp(ext+1, "negctts", 7)) negative_cts_offset = 1; - else if (!strnicmp(ext+1, "stype=", 6)) { - stype = GF_4CC(ext[7], ext[8], ext[9], ext[10]); + else if (!strnicmp(ext+1, "negctts", 7)) { + neg_ctts_mode = !strnicmp(ext+1, "negctts=no", 10) ? 2 : 1; } else if (!stricmp(ext+1, "chap")) is_chap = 1; else if (!strnicmp(ext+1, "chapter=", 8)) { @@ -552,19 +940,30 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction is_chap_file=1; } else if (!strnicmp(ext+1, "layout=", 7)) { - if ( sscanf(ext+8, "%dx%dx%dx%d", &tw, &th, &tx, &ty)==4) { - track_layout = 1; - } else if ( sscanf(ext+8, "%dx%d", &tw, &th)==2) { - track_layout = 1; + track_layout = 1; + if ( sscanf(ext+13, "%dx%dx%dx%dx%d", &tw, &th, &tx, &ty, &tz)==5) { + } else if ( sscanf(ext+13, "%dx%dx%dx%d", &tw, &th, &tx, &ty)==4) { + tz = 0; + } else if ( sscanf(ext+13, "%dx%dx%d", &tw, &th, &tz)==3) { tx = ty = 0; + } else if ( sscanf(ext+8, "%dx%d", &tw, &th)==2) { + tx = ty = tz = 0; } } + else if (!strnicmp(ext+1, "rescale=", 8)) { - if (sscanf(ext+9, "%d/%d", &rescale_num, &rescale_den) != 2) { + if (sscanf(ext+9, "%u/%u", &rescale_num, &rescale_den) != 2) { rescale_num = atoi(ext+9); rescale_den = 0; } } + else if (!strnicmp(ext+1, "sampdur=", 8)) { + if (sscanf(ext+9, "%u/%u", &rescale_den, &rescale_num) != 2) { + rescale_den = atoi(ext+9); + rescale_num = 0; + } + rescale_override = GF_TRUE; + } else if (!strnicmp(ext+1, "timescale=", 10)) { new_timescale = atoi(ext+11); } @@ -572,7 +971,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction moov_timescale = atoi(ext+8); } - else if (!stricmp(ext+1, "noedit")) import_flags |= GF_IMPORT_NO_EDIT_LIST; + else if (!stricmp(ext+1, "noedit")) { import_flags |= GF_IMPORT_NO_EDIT_LIST; } else if (!strnicmp(ext+1, "rvc=", 4)) { @@ -581,13 +980,30 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } } else if (!strnicmp(ext+1, "fmt=", 4)) import.streamFormat = gf_strdup(ext+5); - else if (!strnicmp(ext+1, "profile=", 8)) profile = atoi(ext+9); - else if (!strnicmp(ext+1, "level=", 6)) level = atoi(ext+7); - else if (!strnicmp(ext+1, "novpsext", 8)) import_flags |= GF_IMPORT_NO_VPS_EXTENSIONS; - else if (!strnicmp(ext+1, "keepav1t", 8)) import_flags |= GF_IMPORT_KEEP_AV1_TEMPORAL_OBU; - else if (!strnicmp(ext+1, "font=", 5)) import.fontName = gf_strdup(ext+6); - else if (!strnicmp(ext+1, "size=", 5)) import.fontSize = atoi(ext+6); + else if (!strnicmp(ext+1, "profile=", 8)) { + if (!stricmp(ext+9, "high444")) profile = 244; + else if (!stricmp(ext+9, "high")) profile = 100; + else if (!stricmp(ext+9, "extended")) profile = 88; + else if (!stricmp(ext+9, "main")) profile = 77; + else if (!stricmp(ext+9, "baseline")) profile = 66; + else profile = atoi(ext+9); + } + else if (!strnicmp(ext+1, "level=", 6)) { + if( atof(ext+7) < 6 ) + level = (int)(10*atof(ext+7)+.5); + else + level = atoi(ext+7); + } + else if (!strnicmp(ext+1, "compat=", 7)) { + compat = atoi(ext+8); + } + + else if (!strnicmp(ext+1, "novpsext", 8)) { CHECK_FAKEIMPORT("novpsext") import_flags |= GF_IMPORT_NO_VPS_EXTENSIONS; } + else if (!strnicmp(ext+1, "keepav1t", 8)) { CHECK_FAKEIMPORT("keepav1t") import_flags |= GF_IMPORT_KEEP_AV1_TEMPORAL_OBU; } + + else if (!strnicmp(ext+1, "font=", 5)) { CHECK_FAKEIMPORT("font") import.fontName = gf_strdup(ext+6); } + else if (!strnicmp(ext+1, "size=", 5)) { CHECK_FAKEIMPORT("size") import.fontSize = atoi(ext+6); } else if (!strnicmp(ext+1, "text_layout=", 12)) { if ( sscanf(ext+13, "%dx%dx%dx%d", &txtw, &txth, &txtx, &txty)==4) { text_layout = 1; @@ -598,17 +1014,17 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } #ifndef GPAC_DISABLE_SWF_IMPORT - else if (!stricmp(ext+1, "swf-global")) import.swf_flags |= GF_SM_SWF_STATIC_DICT; - else if (!stricmp(ext+1, "swf-no-ctrl")) import.swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; - else if (!stricmp(ext+1, "swf-no-text")) import.swf_flags |= GF_SM_SWF_NO_TEXT; - else if (!stricmp(ext+1, "swf-no-font")) import.swf_flags |= GF_SM_SWF_NO_FONT; - else if (!stricmp(ext+1, "swf-no-line")) import.swf_flags |= GF_SM_SWF_NO_LINE; - else if (!stricmp(ext+1, "swf-no-grad")) import.swf_flags |= GF_SM_SWF_NO_GRADIENT; - else if (!stricmp(ext+1, "swf-quad")) import.swf_flags |= GF_SM_SWF_QUAD_CURVE; - else if (!stricmp(ext+1, "swf-xlp")) import.swf_flags |= GF_SM_SWF_SCALABLE_LINE; - else if (!stricmp(ext+1, "swf-ic2d")) import.swf_flags |= GF_SM_SWF_USE_IC2D; - else if (!stricmp(ext+1, "swf-same-app")) import.swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; - else if (!strnicmp(ext+1, "swf-flatten=", 12)) import.swf_flatten_angle = (Float) atof(ext+13); + else if (!stricmp(ext+1, "swf-global")) { CHECK_FAKEIMPORT("swf-global") import.swf_flags |= GF_SM_SWF_STATIC_DICT; } + else if (!stricmp(ext+1, "swf-no-ctrl")) { CHECK_FAKEIMPORT("swf-no-ctrl") import.swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; } + else if (!stricmp(ext+1, "swf-no-text")) { CHECK_FAKEIMPORT("swf-no-text") import.swf_flags |= GF_SM_SWF_NO_TEXT; } + else if (!stricmp(ext+1, "swf-no-font")) { CHECK_FAKEIMPORT("swf-no-font") import.swf_flags |= GF_SM_SWF_NO_FONT; } + else if (!stricmp(ext+1, "swf-no-line")) { CHECK_FAKEIMPORT("swf-no-line") import.swf_flags |= GF_SM_SWF_NO_LINE; } + else if (!stricmp(ext+1, "swf-no-grad")) { CHECK_FAKEIMPORT("swf-no-grad") import.swf_flags |= GF_SM_SWF_NO_GRADIENT; } + else if (!stricmp(ext+1, "swf-quad")) { CHECK_FAKEIMPORT("swf-quad") import.swf_flags |= GF_SM_SWF_QUAD_CURVE; } + else if (!stricmp(ext+1, "swf-xlp")) { CHECK_FAKEIMPORT("swf-xlp") import.swf_flags |= GF_SM_SWF_SCALABLE_LINE; } + else if (!stricmp(ext+1, "swf-ic2d")) { CHECK_FAKEIMPORT("swf-ic2d") import.swf_flags |= GF_SM_SWF_USE_IC2D; } + else if (!stricmp(ext+1, "swf-same-app")) { CHECK_FAKEIMPORT("swf-same-app") import.swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; } + else if (!strnicmp(ext+1, "swf-flatten=", 12)) { CHECK_FAKEIMPORT("swf-flatten") import.swf_flatten_angle = (Float) atof(ext+13); } #endif else if (!strnicmp(ext+1, "kind=", 5)) { @@ -644,22 +1060,31 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction else if (!strnicmp(ext+1, "rate=", 5)) { force_rate = atoi(ext+6); } - else if (!stricmp(ext+1, "fstat")) + else if (!stricmp(ext+1, "stats") || !stricmp(ext+1, "fstat")) print_stats_graph |= 1; - else if (!stricmp(ext+1, "fgraph")) + else if (!stricmp(ext+1, "graph") || !stricmp(ext+1, "graph")) print_stats_graph |= 2; - else if (!strncmp(ext+1, "sopt", 4) || !strncmp(ext+1, "dopt", 4) || !strncmp(ext+1, "@@", 2)) { + else if (!strncmp(ext+1, "sopt", 4) || !strncmp(ext+1, "dopt", 4) || !strncmp(ext+1, "@", 1)) { if (ext2) ext2[0] = ':'; opt_src = strstr(ext, ":sopt:"); opt_dst = strstr(ext, ":dopt:"); - fchain = strstr(ext, ":@@"); + fchain = strstr(ext, ":@"); if (opt_src) opt_src[0] = 0; if (opt_dst) opt_dst[0] = 0; if (fchain) fchain[0] = 0; if (opt_src) import.filter_src_opts = opt_src+6; if (opt_dst) import.filter_dst_opts = opt_dst+6; - if (fchain) import.filter_chain = fchain+3; + if (fchain) { + //check for old syntax (0.9->1.0) :@@ + if (fchain[2]=='@') { + import.filter_chain = fchain + 3; + import.is_chain_old_syntax = GF_TRUE; + } else { + import.filter_chain = fchain + 2; + import.is_chain_old_syntax = GF_FALSE; + } + } ext = NULL; break; @@ -676,21 +1101,24 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction else if (!stricmp(mode, "v1-qt")) import.asemode = GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF; else - fprintf(stderr, "Unrecognized audio sample entry mode %s, ignoring\n", mode); - } - - else if (!strnicmp(ext+1, "audio_roll=", 11)) { - import.audio_roll_change = GF_TRUE; - import.audio_roll = atoi(ext+12); + M4_LOG(GF_LOG_ERROR, ("Unrecognized audio sample entry mode %s, ignoring\n", mode)); } + else if (!strnicmp(ext+1, "audio_roll=", 11)) { roll_change = 3; roll = atoi(ext+12); } + else if (!strnicmp(ext+1, "roll=", 5)) { roll_change = 1; roll = atoi(ext+6); } + else if (!strnicmp(ext+1, "proll=", 6)) { roll_change = 2; roll = atoi(ext+7); } else if (!strcmp(ext+1, "stz2")) { use_stz2 = GF_TRUE; } else if (!strnicmp(ext+1, "bitdepth=", 9)) { bitdepth=atoi(ext+10); } + else if (!strnicmp(ext+1, "hdr=", 4)) { + hdr_file = gf_strdup(ext+5); + } else if (!strnicmp(ext+1, "colr=", 5)) { char *cval = ext+6; - if (strlen(cval)<6) { + if (!strcmp(cval, "none")) { + clr_type = (u32) -1; + } else if (strlen(cval)<6) { fmt_ok = GF_FALSE; } else { clr_type = GF_4CC(cval[0],cval[1],cval[2],cval[3]); @@ -698,19 +1126,15 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction if (cval[0] != ',') { fmt_ok = GF_FALSE; } - else if (clr_type==GF_ISOM_SUBTYPE_NCLX) { - if (sscanf(cval+1, "%d,%d,%d,%d", &clr_prim, &clr_tranf, &clr_mx, &clr_full_range) != 4) - fmt_ok=GF_FALSE; - } - else if (clr_type==GF_ISOM_SUBTYPE_NCLC) { - if (sscanf(cval+1, "%d,%d,%d", &clr_prim, &clr_tranf, &clr_mx) != 3) - fmt_ok=GF_FALSE; + else if ((clr_type==GF_ISOM_SUBTYPE_NCLX) || (clr_type==GF_ISOM_SUBTYPE_NCLC)) { + fmt_ok = scan_color(cval+1, &clr_prim, &clr_tranf, &clr_mx, &clr_full_range); } else if ((clr_type==GF_ISOM_SUBTYPE_RICC) || (clr_type==GF_ISOM_SUBTYPE_PROF)) { FILE *f = gf_fopen(cval+1, "rb"); if (!f) { - fprintf(stderr, "Failed to open file %s\n", cval+1); - fmt_ok = GF_FALSE; + M4_LOG(GF_LOG_ERROR, ("Failed to open file %s\n", cval+1)); + e = GF_BAD_PARAM; + goto exit; } else { gf_fseek(f, 0, SEEK_END); icc_size = (u32) gf_ftell(f); @@ -720,21 +1144,65 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction gf_fclose(f); } } else { - fprintf(stderr, "unrecognized profile %s\n", gf_4cc_to_str(clr_type) ); - fmt_ok = GF_FALSE; + M4_LOG(GF_LOG_ERROR, ("Unrecognized colr profile %s\n", gf_4cc_to_str(clr_type) )); + e = GF_BAD_PARAM; + goto exit; } } if (!fmt_ok) { - fprintf(stderr, "Bad format for clr option, check help\n"); e = GF_BAD_PARAM; - goto exit; + GOTO_EXIT("parsing colr option"); } } else if (!strnicmp(ext + 1, "dv-profile=", 11)) { - dv_profile = atoi(ext + 12); + strncpy(dv_profile, ext + 12, 99); + dv_profile[99]=0; + } + else if (!strnicmp(ext+1, "fullrange=", 10)) { + if (!stricmp(ext+11, "off") || !stricmp(ext+11, "no")) fullrange = 0; + else if (!stricmp(ext+11, "on") || !stricmp(ext+11, "yes")) fullrange = 1; + else { + e = GF_BAD_PARAM; + GOTO_EXIT("invalid format for fullrange") + } + } + else if (!strnicmp(ext+1, "videofmt=", 10)) { + u32 idx, count = GF_ARRAY_LENGTH(videofmt_names); + for (idx=0; idx0) { + e = gf_isom_set_timescale(dest, moov_timescale); + GOTO_EXIT("changing timescale") + } + import.run_in_session = fsess; import.update_mux_args = NULL; if (do_all) @@ -943,12 +1444,14 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction e = gf_media_import(&import); if (e) { if (import.update_mux_args) gf_free(import.update_mux_args); - goto exit; + GOTO_EXIT("importing media"); } if (fsess) { *mux_args_if_first_pass = import.update_mux_args; import.update_mux_args = NULL; + *mux_sid_if_first_pass = import.update_mux_sid; + import.update_mux_sid = NULL; goto exit; } } @@ -956,74 +1459,112 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction nb_tracks = gf_isom_get_track_count(dest); for (i=0; i>=32; - - keep_handler = (tk_source_magic & 1) ? GF_TRUE : GF_FALSE; - media_type = gf_isom_get_media_type(dest, track); + e = GF_OK; + if (!fake_import) { + u64 tk_source_magic; + tk_source_magic = gf_isom_get_track_magic(dest, track); - if (moov_timescale) { - if (moov_timescale<0) moov_timescale = gf_isom_get_media_timescale(dest, track); - gf_isom_set_timescale(dest, moov_timescale); - moov_timescale = 0; + if ((tk_source_magic & 0xFFFFFFFFUL) != source_magic) + continue; + tk_source_magic>>=32; + keep_handler = (tk_source_magic & 1) ? GF_TRUE : GF_FALSE; + } else { + keep_handler = GF_TRUE; + + if (do_audio && (media_type!=GF_ISOM_MEDIA_AUDIO)) continue; + if (do_video && (media_type!=GF_ISOM_MEDIA_VISUAL)) continue; + if (do_auxv && (media_type!=GF_ISOM_MEDIA_AUXV)) continue; + if (do_pict && (media_type!=GF_ISOM_MEDIA_PICT)) continue; + if (track_id && (gf_isom_get_track_id(dest, track) != track_id)) + continue; } timescale = gf_isom_get_timescale(dest); - if (szLan) gf_isom_set_media_language(dest, track, (char *) szLan); - if (disable) gf_isom_set_track_enabled(dest, track, GF_FALSE); - - if (import_flags & GF_IMPORT_NO_EDIT_LIST) - gf_isom_remove_edits(dest, track); + if (szLan) { + e = gf_isom_set_media_language(dest, track, (char *) szLan); + GOTO_EXIT("changing language") + } + if (do_disable) { + e = gf_isom_set_track_enabled(dest, track, (do_disable==2) ? GF_TRUE : GF_FALSE); + GOTO_EXIT("disabling track") + } + if (track_flags_mode) { + e = gf_isom_set_track_flags(dest, track, track_flags, track_flags_mode); + GOTO_EXIT("disabling track") + } - if (delay) { + if (import_flags & GF_IMPORT_NO_EDIT_LIST) { + e = gf_isom_remove_edits(dest, track); + GOTO_EXIT("removing edits") + } + if (delay.num && delay.den) { u64 tk_dur; - gf_isom_remove_edits(dest, track); + e = gf_isom_remove_edits(dest, track); tk_dur = gf_isom_get_track_duration(dest, track); - if (delay>0) { - gf_isom_append_edit(dest, track, (timescale*delay)/1000, 0, GF_ISOM_EDIT_EMPTY); - gf_isom_append_edit(dest, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); + if (delay.num>0) { + //cast to s64, timescale*delay could be quite large before /1000 + e |= gf_isom_append_edit(dest, track, ((s64) delay.num) * timescale / delay.den, 0, GF_ISOM_EDIT_EMPTY); + e |= gf_isom_append_edit(dest, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); } else { - u64 to_skip = (timescale*(-delay))/1000; + //cast to s64, timescale*delay could be quite large before /1000 + u64 to_skip = ((s64) -delay.num) * timescale / delay.den; if (to_skip=0) && (par_d>=0)) || force_par) { e = gf_media_change_par(dest, track, par_n, par_d, force_par, rewrite_bs); + GOTO_EXIT("changing PAR") + } + if ((fullrange>=0) || (videofmt>=0) || (colorprim>=0) || (colortfc>=0) || (colormx>=0)) { + e = gf_media_change_color(dest, i+1, fullrange, videofmt, colorprim, colortfc, colormx); + GOTO_EXIT("changing color in bitstream") } if (has_clap) { e = gf_isom_set_clean_aperture(dest, track, 1, clap_wn, clap_wd, clap_hn, clap_hd, clap_hon, clap_hod, clap_von, clap_vod); + GOTO_EXIT("changing clean aperture") } if (bitdepth) { - gf_isom_set_visual_bit_depth(dest, track, 1, bitdepth); + e = gf_isom_set_visual_bit_depth(dest, track, 1, bitdepth); + GOTO_EXIT("changing bit depth") } if (clr_type) { - gf_isom_set_visual_color_info(dest, track, 1, clr_type, clr_prim, clr_tranf, clr_mx, clr_full_range, icc_data, icc_size); + if (clr_type==(u32)-1) + clr_type = 0; + + e = gf_isom_set_visual_color_info(dest, track, 1, clr_type, clr_prim, clr_tranf, clr_mx, clr_full_range, icc_data, icc_size); + GOTO_EXIT("changing color info") + } + if (hdr_file) { + e = parse_high_dynamc_range_xml_desc(dest, track, hdr_file); + GOTO_EXIT("setting HDR info") } - if (dv_profile) { - gf_isom_set_dolby_vision_profile(dest, track, 1, dv_profile); + if (dv_profile[0]) { + e = set_dv_profile(dest, track, dv_profile); + GOTO_EXIT("setting DV profile") } if (set_ccst) { - gf_isom_set_image_sequence_coding_constraints(dest, track, 1, GF_FALSE, GF_FALSE, GF_TRUE, 15); + e = gf_isom_set_image_sequence_coding_constraints(dest, track, 1, GF_FALSE, GF_FALSE, GF_TRUE, 15); + GOTO_EXIT("setting image sequence constraints") } } if (has_mx) { e = gf_isom_set_track_matrix(dest, track, mx); + GOTO_EXIT("setting track matrix") } if (use_stz2) { e = gf_isom_use_compact_size(dest, track, GF_TRUE); + GOTO_EXIT("setting compact size") } if (gf_isom_get_media_subtype(dest, track, 1) == GF_ISOM_MEDIA_TIMECODE) { @@ -1031,9 +1572,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } if (rap_only || refs_only) { e = gf_media_remove_non_rap(dest, track, refs_only); - if (e) goto exit; + GOTO_EXIT("removing non RAPs") + } + if (handler_name) { + e = gf_isom_set_handler_name(dest, track, handler_name); + GOTO_EXIT("setting handler name") } - if (handler_name) gf_isom_set_handler_name(dest, track, handler_name); else if (!keep_handler) { char szHName[1024]; const char *fName = gf_url_get_resource_name((const char *)inName); @@ -1042,85 +1586,124 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction else fName = "?"; sprintf(szHName, "%s@GPAC%s", fName, gf_gpac_version()); - gf_isom_set_handler_name(dest, track, szHName); + e = gf_isom_set_handler_name(dest, track, szHName); + GOTO_EXIT("setting handler name") + } + if (handler) { + e = gf_isom_set_media_type(dest, track, handler); + GOTO_EXIT("setting media type") } - if (handler) gf_isom_set_media_type(dest, track, handler); - if (group) { - gf_isom_set_alternate_group_id(dest, track, group); + e = gf_isom_set_alternate_group_id(dest, track, group); + GOTO_EXIT("setting alternate group") } if (track_layout) { - gf_isom_set_track_layout_info(dest, track, tw<<16, th<<16, tx<<16, ty<<16, 0); + e = gf_isom_set_track_layout_info(dest, track, tw<<16, th<<16, tx<<16, ty<<16, tz); + GOTO_EXIT("setting track layout") + } + if (stype) { + e = gf_isom_set_media_subtype(dest, track, 1, stype); + GOTO_EXIT("setting media subtype") } - if (stype) - gf_isom_set_media_subtype(dest, track, 1, stype); - if (is_chap && chap_ref) { - set_chapter_track(dest, track, chap_ref); + e = set_chapter_track(dest, track, chap_ref); + GOTO_EXIT("setting chapter track") } - for (j = 0; j < gf_list_count(kinds); j+=2) { char *kind_scheme = (char *)gf_list_get(kinds, j); char *kind_value = (char *)gf_list_get(kinds, j+1); - gf_isom_add_track_kind(dest, i+1, kind_scheme, kind_value); + e = gf_isom_add_track_kind(dest, i+1, kind_scheme, kind_value); + GOTO_EXIT("setting track kind") } - if (profile || level) - gf_media_change_pl(dest, track, profile, level); - + if (profile || compat || level) { + e = gf_media_change_pl(dest, track, profile, compat, level); + GOTO_EXIT("changing video PL") + } if (gf_isom_get_mpeg4_subtype(dest, track, 1)) keep_sys_tracks = 1; + //if moov timescale is <0 (auto mode) set it at import time + if (fake_import) { + if (import_flags & GF_IMPORT_NO_EDIT_LIST) + gf_isom_remove_edits(dest, track); + + if (moov_timescale<0) { + moov_timescale = gf_isom_get_media_timescale(dest, track); + } + if (moov_timescale>0) { + e = gf_isom_set_timescale(dest, moov_timescale); + GOTO_EXIT("changing timescale") + } + + if (import.asemode && (media_type==GF_ISOM_MEDIA_AUDIO)) { + u32 sr, ch, bps; + gf_isom_get_audio_info(dest, track, 1, &sr, &ch, &bps); + gf_isom_set_audio_info(dest, track, 1, sr, ch, bps, import.asemode); + } + } + + if (roll_change) { + if ((roll_change!=3) || (media_type==GF_ISOM_MEDIA_AUDIO)) { + e = gf_isom_set_sample_roll_group(dest, track, (u32) -1, (roll_change==2) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL, roll); + GOTO_EXIT("assigning roll") + } + } + if (new_timescale>1) { - gf_isom_set_media_timescale(dest, track, new_timescale, 0, 0); + e = gf_isom_set_media_timescale(dest, track, new_timescale, 0, 0); + GOTO_EXIT("setting media timescale") } if (rescale_num > 1) { switch (gf_isom_get_media_type(dest, track)) { case GF_ISOM_MEDIA_AUDIO: - fprintf(stderr, "Cannot force media timescale for audio media types - ignoring\n"); - break; + if (!rescale_override) { + M4_LOG(GF_LOG_WARNING, ("Cannot force media timescale for audio media types - ignoring\n")); + break; + } default: - e = gf_isom_set_media_timescale(dest, track, rescale_num, rescale_den, 1); + e = gf_isom_set_media_timescale(dest, track, rescale_num, rescale_den, rescale_override ? 2 : 1); if (e==GF_EOS) { - fprintf(stderr, "Rescale ignored, same config in source file\n"); + M4_LOG(GF_LOG_WARNING, ("Rescale ignored, same config in source file\n")); e = GF_OK; - } else if (e) { - fprintf(stderr, "Error rescaling media track %d\n", track); - goto exit; } + GOTO_EXIT("rescaling media track") break; } } - if (has_last_sample_dur) { - gf_isom_set_last_sample_duration_ex(dest, track, last_sample_dur.num, last_sample_dur.den); + if (has_last_sample_dur) { + e = gf_isom_set_last_sample_duration_ex(dest, track, last_sample_dur.num, last_sample_dur.den); + GOTO_EXIT("setting last sample duration") } if (rvc_config) { +#ifdef GPAC_DISABLE_ZLIB + M4_LOG(GF_LOG_ERROR, ("Error: no zlib support - RVC not available\n")); + e = GF_NOT_SUPPORTED; + goto exit; +#else u8 *data; u32 size; e = gf_file_load_data(rvc_config, (u8 **) &data, &size); - if (e) { - fprintf(stderr, "Error: failed to load rvc config from file: %s\n", gf_error_to_string(e) ); - } else { -#ifdef GPAC_DISABLE_ZLIB - fprintf(stderr, "Error: no zlib support - RVC not available\n"); - e = GF_NOT_SUPPORTED; - gf_free(data); - goto exit; -#else - gf_gz_compress_payload(&data, size, &size); + GOTO_EXIT("loading RVC config file") + + gf_gz_compress_payload(&data, size, &size); + e |= gf_isom_set_rvc_config(dest, track, 1, 0, "application/rvc-config+xml+gz", data, size); + gf_free(data); + GOTO_EXIT("compressing and assigning RVC config") #endif - gf_isom_set_rvc_config(dest, track, 1, 0, "application/rvc-config+xml+gz", data, size); - gf_free(data); - } } else if (rvc_predefined>0) { - gf_isom_set_rvc_config(dest, track, 1, rvc_predefined, NULL, NULL, 0); + e = gf_isom_set_rvc_config(dest, track, 1, rvc_predefined, NULL, NULL, 0); + GOTO_EXIT("setting RVC predefined config") } - gf_isom_set_composition_offset_mode(dest, track, negative_cts_offset); + if (neg_ctts_mode) { + e = gf_isom_set_composition_offset_mode(dest, track, (neg_ctts_mode==1) ? GF_TRUE : GF_FALSE); + GOTO_EXIT("setting composition offset mode") + } if (gf_isom_get_avc_svc_type(dest, track, 1)>=GF_ISOM_AVCTYPE_AVC_SVC) check_track_for_svc = track; @@ -1138,10 +1721,18 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } if (txt_flags) { - gf_isom_text_set_display_flags(dest, track, 0, txt_flags, txt_mode); + e = gf_isom_text_set_display_flags(dest, track, 0, txt_flags, txt_mode); + GOTO_EXIT("setting text track display flags") } + + if (edits) { + e = apply_edits(dest, track, edits); + GOTO_EXIT("applying edits") + } + if (force_rate>=0) { - gf_isom_update_bitrate(dest, i+1, 1, force_rate, force_rate, 0); + e = gf_isom_update_bitrate(dest, i+1, 1, force_rate, force_rate, 0); + GOTO_EXIT("updating bitrate") } if (split_tile_mode) { @@ -1165,6 +1756,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction } else { e = gf_isom_add_chapter(dest, 0, 0, chapter_name); } + GOTO_EXIT("importing chapters") } if (tmcd_track) { @@ -1178,7 +1770,8 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction default: continue; } - gf_isom_set_track_reference(dest, i+1, GF_ISOM_REF_TMCD, tmcd_id); + e = gf_isom_set_track_reference(dest, i+1, GF_ISOM_REF_TMCD, tmcd_id); + GOTO_EXIT("assigning TMCD track references") } } @@ -1198,7 +1791,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction { e = gf_media_filter_hevc(dest, i, max_temporal_id_plus_one, max_layer_id_plus_one); if (e) { - fprintf(stderr, "Warning: track ID %d: error while filtering LHVC layers\n", gf_isom_get_track_id(dest, i)); + M4_LOG(GF_LOG_ERROR, ("Warning: track ID %d: error while filtering LHVC layers\n", gf_isom_get_track_id(dest, i))); e = GF_OK; } } @@ -1208,10 +1801,10 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction if (check_track_for_svc) { if (svc_mode) { e = gf_media_split_svc(dest, check_track_for_svc, (svc_mode==2) ? 1 : 0); - if (e) goto exit; + GOTO_EXIT("splitting SVC track") } else { e = gf_media_merge_svc(dest, check_track_for_svc, 1); - if (e) goto exit; + GOTO_EXIT("merging SVC/SHVC track") } } #ifndef GPAC_DISABLE_AV_PARSERS @@ -1221,7 +1814,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction if (svc_mode==3) xmode = GF_LHVC_EXTRACTORS_OFF; else if (svc_mode==4) xmode = GF_LHVC_EXTRACTORS_OFF_FORCE_INBAND; e = gf_media_split_lhvc(dest, check_track_for_lhvc, GF_FALSE, (svc_mode==1) ? 0 : 1, xmode ); - if (e) goto exit; + GOTO_EXIT("splitting L-HEVC track") } else { //TODO - merge, temporal sublayers } @@ -1230,12 +1823,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction if (check_track_for_hevc) { if (split_tile_mode) { e = gf_media_split_hevc_tiles(dest, split_tile_mode - 1); - if (e) goto exit; + GOTO_EXIT("splitting HEVC tiles") } if (temporal_mode) { GF_LHVCExtractoreMode xmode = (temporal_mode==3) ? GF_LHVC_EXTRACTORS_OFF : GF_LHVC_EXTRACTORS_ON; e = gf_media_split_lhvc(dest, check_track_for_hevc, GF_TRUE, (temporal_mode==1) ? GF_FALSE : GF_TRUE, xmode ); - if (e) goto exit; + GOTO_EXIT("splitting HEVC temporal sublayers") } } #endif @@ -1255,12 +1848,11 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction tmcd_tk = gf_isom_new_track(dest, 0, GF_ISOM_MEDIA_TIMECODE, tc_fps_num); if (!tmcd_tk) { e = gf_isom_last_error(dest); - goto exit; + GOTO_EXIT("creating TMCD track") } - e = gf_isom_set_track_enabled(import.dest, tmcd_tk, 1); + e = gf_isom_set_track_enabled(dest, tmcd_tk, 1); if (e != GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(e))); - goto exit; + GOTO_EXIT("enabling TMCD track") } if (!tc_frames_per_tick) { @@ -1272,12 +1864,13 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction u32 tmcd_value = (tc_h * 3600 + tc_m*60 + tc_s)*tc_frames_per_tick+tc_f; tmcd_id = gf_isom_get_track_id(dest, tmcd_tk); - e = gf_isom_tmcd_config_new(dest, tmcd_tk, tc_fps_num, tc_fps_den, tc_frames_per_tick, tc_drop_frame, tc_force_counter, &desc_index); - if (e) goto exit; + e = gf_isom_tmcd_config_new(dest, tmcd_tk, tc_fps_num, tc_fps_den, tc_frames_per_tick, tc_drop_frame, tc_force_counter, &desc_index); + GOTO_EXIT("configuring TMCD sample description") if (video_ref) { - gf_isom_set_track_reference(dest, video_ref, GF_ISOM_REF_TMCD, tmcd_id); + e = gf_isom_set_track_reference(dest, video_ref, GF_ISOM_REF_TMCD, tmcd_id); + GOTO_EXIT("assigning TMCD track ref on video track") } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, tmcd_value); @@ -1287,15 +1880,17 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction gf_bs_del(bs); e = gf_isom_add_sample(dest, tmcd_tk, desc_index, samp); gf_isom_sample_del(&samp); + GOTO_EXIT("assigning TMCD sample") if (video_ref) { u64 video_ref_dur = gf_isom_get_media_duration(dest, video_ref); video_ref_dur *= tc_fps_num; video_ref_dur /= gf_isom_get_media_timescale(dest, video_ref); - gf_isom_set_last_sample_duration(dest, tmcd_tk, (u32) video_ref_dur); + e = gf_isom_set_last_sample_duration(dest, tmcd_tk, (u32) video_ref_dur); } else { - gf_isom_set_last_sample_duration(dest, tmcd_tk, tc_fps_den ? tc_fps_den : 1); + e = gf_isom_set_last_sample_duration(dest, tmcd_tk, tc_fps_den ? tc_fps_den : 1); } + GOTO_EXIT("setting TMCD sample dur") } #endif /*GPAC_DISABLE_AV_PARSERS*/ @@ -1309,6 +1904,7 @@ exit: if (opt_src) opt_src[0] = ':'; if (opt_dst) opt_dst[0] = ':'; if (fchain) fchain[0] = ':'; + if (hdr_file) gf_free(hdr_file); gf_list_del(kinds); if (handler_name) gf_free(handler_name); @@ -1317,34 +1913,62 @@ exit: if (import.streamFormat) gf_free(import.streamFormat); if (import.force_ext) gf_free(import.force_ext); if (rvc_config) gf_free(rvc_config); + if (edits) gf_free(edits); if (szLan) gf_free((char *)szLan); if (icc_data) gf_free(icc_data); + if (final_name) gf_free(final_name); + + if (!e) return GF_OK; + if (fail_msg) { + M4_LOG(GF_LOG_ERROR, ("Failure while %s: %s\n", fail_msg, gf_error_to_string(e) )); + } return e; } +typedef struct +{ + Double progress; + u32 file_idx; +} SplitInfo; static Bool on_split_event(void *_udta, GF_Event *evt) { Double progress; - u32 *prev_progress = (u32 *)_udta; + SplitInfo *sinfo = (SplitInfo *)_udta; if (!_udta) return GF_FALSE; if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE; if (!evt->progress.total) return GF_FALSE; progress = (Double) (100*evt->progress.done) / evt->progress.total; - if ((u32) progress==*prev_progress) + if (progress <= sinfo->progress) return GF_FALSE; - *prev_progress = (u32) progress; + if (evt->progress.done == evt->progress.total) { + if (sinfo->progress <= 0) + return GF_FALSE; #ifndef GPAC_DISABLE_LOG - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Spliting: % 2.2f %%\r", progress)); + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("splitting: file %d done\n", sinfo->file_idx)); #else - fprintf(stderr, "Spliting: % 2.2f %%\r", progress); + fprintf(stderr, "splitting: file %d done\n", sinfo->file_idx); #endif + sinfo->file_idx++; + sinfo->progress = -1; + } else { + sinfo->progress = progress; +#ifndef GPAC_DISABLE_LOG + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("splitting: % 2.2f %%\r", progress)); +#else + fprintf(stderr, "splitting: % 2.2f %%\r", progress); +#endif + } return GF_FALSE; } -GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, char *inName, Double InterleavingTime, Double chunk_start_time, Bool adjust_split_end, char *outName, const char *tmpdir, Bool force_rap_split, const char *split_range_str) +extern u32 do_flat; +extern Bool do_frag; +extern Double interleaving_time; + +GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, char *inName, Double InterleavingTime, Double chunk_start_time, u32 adjust_split_end, char *outName, Bool force_rap_split, const char *split_range_str, u32 fs_dump_flags) { Bool chunk_extraction, rap_split, split_until_end; GF_Err e; @@ -1353,7 +1977,10 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, char *filter_args = NULL; GF_FilterSession *fs; GF_Filter *src, *reframe, *dst; - u32 progress = (u32) -1; + SplitInfo sinfo; + + sinfo.progress = -1; + sinfo.file_idx = 1; chunk_extraction = (chunk_start>=0) ? GF_TRUE : GF_FALSE; if (split_range_str) @@ -1376,16 +2003,16 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, fs = gf_fs_new_defaults(0); if (!fs) { - fprintf(stderr, "Failed to load filter session, aborting\n"); + M4_LOG(GF_LOG_ERROR, ("Failed to load filter session, aborting\n")); return GF_IO_ERR; } - - sprintf(szArgs, "mp4dmx:mov=%p", mp4); + //load source with all tracks processing + sprintf(szArgs, "mp4dmx:mov=%p:alltk", mp4); src = gf_fs_load_filter(fs, szArgs, &e); if (!src) { - fprintf(stderr, "Failed to load source filter: %s\n", gf_error_to_string(e) ); + M4_LOG(GF_LOG_ERROR, ("Failed to load source filter: %s\n", gf_error_to_string(e) )); gf_fs_del(fs); return e; } @@ -1402,13 +2029,52 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, sprintf(szArgs, ":xs=S"LLU"k", split_size_kb); gf_dynstrcat(&filter_args, szArgs, NULL); } else if (chunk_extraction) { - gf_dynstrcat(&filter_args, ":xround=closest", NULL); + //we adjust end: start at the iframe at or after requested time and use xadjust (move end to next I-frame) + //so that two calls with X:Y and Y:Z have the same Y boundary + if (adjust_split_end==1) { + gf_dynstrcat(&filter_args, ":xadjust:xround=after", NULL); + } else if (adjust_split_end==2) { + gf_dynstrcat(&filter_args, ":xadjust:xround=before", NULL); + } else if (adjust_split_end==3) { + gf_dynstrcat(&filter_args, ":xround=seek", NULL); + } else if (!gf_sys_find_global_arg("xround")) { + gf_dynstrcat(&filter_args, ":xround=closest", NULL); + } + if (!adjust_split_end || (adjust_split_end==3)) { + if (!gf_sys_find_global_arg("probe_ref")) { + gf_dynstrcat(&filter_args, ":probe_ref", NULL); + } + } + if (split_range_str) { + Bool is_time = GF_FALSE; + char c; + //S-E syntax char *end = (char *) strchr(split_range_str, '-'); - assert(end); + if (!end) { + //S:E syntax + end = (char *) strchr(split_range_str, ':'); + //if another `:` assume time format + if (end && strchr(end+1, ':')) + is_time = GF_TRUE; + } else if (strchr(split_range_str, ':')) { + is_time = GF_TRUE; + } + if (!end) { + gf_free(filter_args); + M4_LOG(GF_LOG_ERROR, ("Invalid range specifer %s, expecting START-END or START:END\n", split_range_str )); + gf_fs_del(fs); + return GF_BAD_PARAM; + } + + c = end[0]; end[0] = 0; - sprintf(szArgs, ":xs=T%s:xe=T%s", split_range_str, end+1); - end[0] = '-'; + if (is_time) { + sprintf(szArgs, ":xs=T%s:xe=T%s", split_range_str, end+1); + } else { + sprintf(szArgs, ":xs=%s:xe=%s", split_range_str, end+1); + } + end[0] = c; } else if (split_until_end) { Double end=0; if (split_dur<-2) { @@ -1427,9 +2093,6 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, sprintf(szArgs, ":xs=%u/1000:xe=%u/1000", (u32) (chunk_start*1000), (u32) ((chunk_start+split_dur) * 1000) ); } gf_dynstrcat(&filter_args, szArgs, NULL); - if (adjust_split_end) { - gf_dynstrcat(&filter_args, ":xadjust", NULL); - } if (!outName) { sprintf(szFile, "%s_$FS$", szName); } @@ -1442,14 +2105,15 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, } else { gf_fs_del(fs); gf_free(filter_args); - fprintf(stderr, "Unrecognized split syntax\n"); + M4_LOG(GF_LOG_ERROR, ("Unrecognized split syntax\n")); return GF_BAD_PARAM; } reframe = gf_fs_load_filter(fs, filter_args, &e); gf_free(filter_args); + filter_args = NULL; if (!reframe) { - fprintf(stderr, "Failed to load reframer filter: %s\n", gf_error_to_string(e) ); + M4_LOG(GF_LOG_ERROR, ("Failed to load reframer filter: %s\n", gf_error_to_string(e) )); gf_fs_del(fs); return e; } @@ -1459,9 +2123,42 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, } else { strcpy(szFile, outName); } + if (gf_dir_exists(szFile)) { + char c = szFile[strlen(szFile)-1]; + if ((c!='/') && (c!='\\')) + strcat(szFile, "/"); + + strcat(szFile, szName); + strcat(szFile, "_$num%03d$.mp4"); + M4_LOG(GF_LOG_WARNING, ("Split output is a directory, will use template %s\n", szFile)); + } + else if (split_size_kb || split_dur) { + if (!strchr(szFile, '$') && (stricmp(szFile, "null") || !strcmp(szFile, "/dev/null")) ) { + char *sep = gf_file_ext_start(szFile); + if (sep) sep[0] = 0; + strcat(szFile, "_$num$.mp4"); + M4_LOG(GF_LOG_WARNING, ("Split by %s but output not a template, using %s as output\n", split_size_kb ? "size" : "duration", szFile)); + } + } + if (do_frag) { + sprintf(szArgs, ":cdur=%g", interleaving_time); + strcat(szFile, ":store=frag"); + strcat(szFile, szArgs); + } + else if (do_flat==1) { + strcat(szFile, ":store=flat"); + } + else if (do_flat || interleaving_time) { + if (do_flat==3) { + strcat(szFile, ":store=fstart"); + } + sprintf(szArgs, ":cdur=%g", interleaving_time); + strcat(szFile, szArgs); + } + dst = gf_fs_load_destination(fs, szFile, NULL, NULL, &e); if (!dst) { - fprintf(stderr, "Failed to load destination filter: %s\n", gf_error_to_string(e) ); + M4_LOG(GF_LOG_ERROR, ("Failed to load destination filter: %s\n", gf_error_to_string(e) )); gf_fs_del(fs); return e; } @@ -1475,7 +2172,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, && !gf_sys_is_quiet() ) { gf_fs_enable_reporting(fs, GF_TRUE); - gf_fs_set_ui_callback(fs, on_split_event, &progress); + gf_fs_set_ui_callback(fs, on_split_event, &sinfo); } #ifdef GPAC_ENABLE_COVERAGE else if (gf_sys_is_cov_mode()) { @@ -1490,22 +2187,27 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, if (e>=GF_OK) e = gf_fs_get_last_process_error(fs); } + gf_fs_print_non_connected(fs); + if (fs_dump_flags & 1) gf_fs_print_stats(fs); + if (fs_dump_flags & 2) gf_fs_print_connections(fs); + gf_fs_del(fs); + if (esize==slc_dst->size) && !memcmp(slc->data, slc_dst->data, slc->size) ) { found = 1; break; @@ -1518,9 +2220,10 @@ static Bool merge_parameter_set(GF_List *src, GF_List *dst, const char *name) return GF_TRUE; } -static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 src_track, Bool force_cat) +static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile **o_orig, u32 src_track, Bool force_cat, u32 *orig_nal_len, u32 *dst_nal_len) { GF_AVCConfig *avc_src, *avc_dst; + GF_ISOFile *orig = *o_orig; u32 dst_tk = gf_isom_get_track_by_id(dest, tk_id); avc_src = gf_isom_avc_config_get(orig, src_track, 1); @@ -1537,7 +2240,8 @@ static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 s gf_media_nal_rewrite_samples(dest, dst_tk, 8*avc_src->nal_unit_size); avc_dst->nal_unit_size = avc_src->nal_unit_size; } else if (avc_src->nal_unit_size < avc_dst->nal_unit_size) { - gf_media_nal_rewrite_samples(orig, src_track, 8*avc_dst->nal_unit_size); + *orig_nal_len = avc_src->nal_unit_size; + *dst_nal_len = avc_dst->nal_unit_size; } /*merge PS*/ @@ -1558,17 +2262,18 @@ static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 s if (!force_cat) { gf_isom_avc_set_inband_config(dest, dst_tk, 1, GF_FALSE); } else { - fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id); + M4_LOG(GF_LOG_WARNING, ("WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id)); } } return dst_tk; } #ifndef GPAC_DISABLE_HEVC -static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 src_track, Bool force_cat) +static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile **o_orig, u32 src_track, Bool force_cat, u32 *orig_nal_len, u32 *dst_nal_len) { u32 i; GF_HEVCConfig *hevc_src, *hevc_dst; + GF_ISOFile *orig = *o_orig; u32 dst_tk = gf_isom_get_track_by_id(dest, tk_id); hevc_src = gf_isom_hevc_config_get(orig, src_track, 1); @@ -1583,15 +2288,16 @@ static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 gf_media_nal_rewrite_samples(dest, dst_tk, 8*hevc_src->nal_unit_size); hevc_dst->nal_unit_size = hevc_src->nal_unit_size; } else if (hevc_src->nal_unit_size < hevc_dst->nal_unit_size) { - gf_media_nal_rewrite_samples(orig, src_track, 8*hevc_dst->nal_unit_size); + *orig_nal_len = hevc_src->nal_unit_size; + *dst_nal_len = hevc_dst->nal_unit_size; } /*merge PS*/ for (i=0; iparam_array); i++) { u32 k; - GF_HEVCParamArray *src_ar = gf_list_get(hevc_src->param_array, i); + GF_NALUFFParamArray *src_ar = gf_list_get(hevc_src->param_array, i); for (k=0; kparam_array); k++) { - GF_HEVCParamArray *dst_ar = gf_list_get(hevc_dst->param_array, k); + GF_NALUFFParamArray *dst_ar = gf_list_get(hevc_dst->param_array, k); if (dst_ar->type==src_ar->type) { if (!merge_parameter_set(src_ar->nalus, dst_ar->nalus, "SPS")) dst_tk = 0; @@ -1612,22 +2318,63 @@ static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 if (!force_cat) { gf_isom_hevc_set_inband_config(dest, dst_tk, 1, GF_FALSE); } else { - fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id); + M4_LOG(GF_LOG_WARNING, ("WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id)); } } return dst_tk; } #endif /*GPAC_DISABLE_HEVC */ -GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); +static GF_Err rewrite_nal_size_field(GF_ISOSample *samp, u32 orig_nal_len, u32 dst_nal_len) +{ + GF_Err e = GF_OK; + u32 msize=0, remain = samp->dataLength; + GF_BitStream *oldbs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ); + GF_BitStream *newbs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); + u8 *buffer = NULL; + + while (remain) { + u32 size = gf_bs_read_int(oldbs, orig_nal_len*8); + if (size > remain) { + e = GF_ISOM_INVALID_FILE; + goto exit; + } + gf_bs_write_int(newbs, size, dst_nal_len*8); + remain -= orig_nal_len; + if (size > msize) { + msize = size; + buffer = (u8*)gf_realloc(buffer, sizeof(u8)*msize); + if (!buffer) { + e = GF_OUT_OF_MEM; + goto exit; + } + } + gf_bs_read_data(oldbs, buffer, size); + gf_bs_write_data(newbs, buffer, size); + remain -= size; + } + gf_free(samp->data); + samp->data = NULL; + samp->dataLength = 0; + gf_bs_get_content(newbs, &samp->data, &samp->dataLength); + +exit: + gf_bs_del(newbs); + gf_bs_del(oldbs); + if (buffer) gf_free(buffer); + return e; +} -GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command, Bool is_pl) + +GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); + +GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, Bool force_cat, Bool align_timelines, Bool allow_add_in_command, Bool is_pl) { u32 i, j, count, nb_tracks, nb_samp, nb_done; GF_ISOFile *orig; GF_Err e; char *opts, *multi_cat; - Double ts_scale; + Double ts_scale, media_ts_scale; Double dest_orig_dur; u32 dst_tk, tk_id, mtype; u64 insert_dts; @@ -1635,37 +2382,46 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ GF_ISOSample *samp; GF_Fraction64 aligned_to_DTS_frac; - if (is_pl) return cat_playlist(dest, fileName, import_flags, force_fps, frames_per_sample, tmp_dir, force_cat, align_timelines, allow_add_in_command); + if (is_pl) return cat_playlist(dest, fileName, import_flags, force_fps, frames_per_sample, force_cat, align_timelines, allow_add_in_command); if (strchr(fileName, '*') || (strchr(fileName, '@')) ) - return cat_multiple_files(dest, fileName, import_flags, force_fps, frames_per_sample, tmp_dir, force_cat, align_timelines, allow_add_in_command); + return cat_multiple_files(dest, fileName, import_flags, force_fps, frames_per_sample, force_cat, align_timelines, allow_add_in_command); multi_cat = allow_add_in_command ? strchr(fileName, '+') : NULL; if (multi_cat) { multi_cat[0] = 0; multi_cat = &multi_cat[1]; } - opts = gf_url_colon_suffix(fileName); + opts = gf_url_colon_suffix(fileName, '='); e = GF_OK; /*if options are specified, reimport the file*/ - is_isom = opts ? 0 : gf_isom_probe_file(fileName); + if (opts) opts[0] = 0; + is_isom = gf_isom_probe_file(fileName); - if (!is_isom || opts) { - orig = gf_isom_open("temp", GF_ISOM_WRITE_EDIT, tmp_dir); - e = import_file(orig, fileName, import_flags, force_fps, frames_per_sample, NULL, NULL, 0); + if (!is_isom || multi_cat) { + orig = gf_isom_open("temp", GF_ISOM_WRITE_EDIT, NULL); + if (opts) opts[0] = ':'; + e = import_file(orig, fileName, import_flags, force_fps, frames_per_sample, NULL, NULL, NULL, 0); if (e) return e; } else { - /*we open the original file in edit mode since we may have to rewrite AVC samples*/ - orig = gf_isom_open(fileName, GF_ISOM_OPEN_EDIT, tmp_dir); + //open read+edit mode to allow applying options on file + orig = gf_isom_open(fileName, GF_ISOM_OPEN_READ_EDIT, NULL); + if (opts) opts[0] = ':'; + if (!orig) return gf_isom_last_error(NULL); + + if (opts) { + e = import_file(orig, fileName, 0xFFFFFFFF, force_fps, frames_per_sample, NULL, NULL, NULL, 0); + if (e) return e; + } } while (multi_cat) { char *sep = strchr(multi_cat, '+'); if (sep) sep[0] = 0; - e = import_file(orig, multi_cat, import_flags, force_fps, frames_per_sample, NULL, NULL, 0); + e = import_file(orig, multi_cat, import_flags, force_fps, frames_per_sample, NULL, NULL, NULL, 0); if (e) { gf_isom_delete(orig); return e; @@ -1683,7 +2439,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ case GF_ISOM_MEDIA_HINT: case GF_ISOM_MEDIA_OD: case GF_ISOM_MEDIA_FLASH: - fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by concatenation - removing from destination\n", gf_isom_get_track_id(orig, i+1), gf_4cc_to_str(mtype)); + M4_LOG(GF_LOG_WARNING, ("WARNING: Track ID %d (type %s) not handled by concatenation - removing from destination\n", gf_isom_get_track_id(orig, i+1), gf_4cc_to_str(mtype))); continue; case GF_ISOM_MEDIA_AUDIO: case GF_ISOM_MEDIA_TEXT: @@ -1708,7 +2464,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ } } if (!nb_samp) { - fprintf(stderr, "No suitable media tracks to cat in %s - skipping\n", fileName); + M4_LOG(GF_LOG_ERROR, ("No suitable media tracks to cat in %s - skipping\n", fileName)); goto err_exit; } @@ -1723,13 +2479,13 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ for (i=0; iDTS; samp->DTS = (u64) (ts_scale * samp->DTS + (new_track ? 0 : insert_dts)); samp->CTS_Offset = (u32) (samp->CTS_Offset * ts_scale); if (gf_isom_is_self_contained(orig, i+1, di)) { + if (orig_nal_len && dst_nal_len) { + e = rewrite_nal_size_field(samp, orig_nal_len, dst_nal_len); + if (e) { + gf_isom_sample_del(&samp); + goto err_exit; + } + } e = gf_isom_add_sample(dest, dst_tk, di + dst_tk_sample_entry, samp); } else { u64 offset; @@ -2003,6 +2780,11 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ e = gf_isom_copy_sample_info(dest, dst_tk, orig, i+1, j+1); if (e) goto err_exit; + if (j+1==count) { + u32 sdur = gf_isom_get_sample_duration(orig, i+1, j+1); + gf_isom_set_last_sample_duration(dest, dst_tk, (u32) (ts_scale * sdur) ); + } + gf_set_progress("Appending", nb_done, nb_samp); nb_done++; } @@ -2042,7 +2824,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ /*safety test: some files have broken edit lists. If no more than 2 entries, check that the segment duration is less or equal to the movie duration*/ if (prev_dur * movts_dst < segmentDuration * trackts_dst) { - fprintf(stderr, "Warning: suspicious edit list entry found: duration %g sec but longest track duration before cat is %g - fixing it\n", (Double) (s64) segmentDuration/movts_dst, prev_dur/trackts_dst); + M4_LOG(GF_LOG_WARNING, ("Warning: suspicious edit list entry found: duration %g sec but longest track duration before cat is %g - fixing it\n", (Double) (s64) segmentDuration/movts_dst, prev_dur/trackts_dst)); segmentDuration = (dest_track_dur_before_cat - mediaTime) * movts_dst; segmentDuration /= trackts_dst; } @@ -2065,7 +2847,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ if (count) { e = gf_isom_get_edit(dest, dst_tk, count, &editTime, &segmentDuration, &mediaTime, &editMode); if (e) { - fprintf(stderr, "Error: edit segment error on destination track %u could not be retrieved.\n", dst_tk); + M4_LOG(GF_LOG_ERROR, ("Error: edit segment error on destination track %u could not be retrieved.\n", dst_tk)); goto err_exit; } } else if (gf_isom_get_edits_count(orig, i+1)) { @@ -2099,7 +2881,8 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_ t *= ts_scale; segmentDuration = (s64) t; t = (Double) (s64) mediaTime; - t *= ts_scale; + //we are in media time, apply media ts scale, not file ts scale + t *= media_ts_scale; t+= (s64) dest_track_dur_before_cat; mediaTime = (s64) t; if ((editMode == GF_ISOM_EDIT_EMPTY) && (mediaTime > 0)) { @@ -2174,7 +2957,6 @@ typedef struct u32 import_flags; GF_Fraction force_fps; u32 frames_per_sample; - char *tmp_dir; Bool force_cat, align_timelines, allow_add_in_command; } CATEnum; @@ -2191,12 +2973,12 @@ Bool cat_enumerate(void *cbk, char *szName, char *szPath, GF_FileEnumInfo *file_ strcpy(szFileName, szPath); strcat(szFileName, cat_enum->szOpt); - e = cat_isomedia_file(cat_enum->dest, szFileName, cat_enum->import_flags, cat_enum->force_fps, cat_enum->frames_per_sample, cat_enum->tmp_dir, cat_enum->force_cat, cat_enum->align_timelines, cat_enum->allow_add_in_command, GF_FALSE); + e = cat_isomedia_file(cat_enum->dest, szFileName, cat_enum->import_flags, cat_enum->force_fps, cat_enum->frames_per_sample, cat_enum->force_cat, cat_enum->align_timelines, cat_enum->allow_add_in_command, GF_FALSE); if (e) return 1; return 0; } -GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) +GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) { CATEnum cat_enum; char *sep; @@ -2205,7 +2987,6 @@ GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, GF cat_enum.import_flags = import_flags; cat_enum.force_fps = force_fps; cat_enum.frames_per_sample = frames_per_sample; - cat_enum.tmp_dir = tmp_dir; cat_enum.force_cat = force_cat; cat_enum.align_timelines = align_timelines; cat_enum.allow_add_in_command = allow_add_in_command; @@ -2242,7 +3023,7 @@ GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, GF sep[0] = 0; sep = strchr(cat_enum.szRad2, '%'); if (!sep) sep = strchr(cat_enum.szRad2, '#'); - if (!sep) sep = gf_url_colon_suffix(cat_enum.szRad2); + if (!sep) sep = gf_url_colon_suffix(cat_enum.szRad2, '='); strcpy(cat_enum.szOpt, ""); if (sep) { if (strlen(sep) >= sizeof(cat_enum.szOpt)) { @@ -2255,7 +3036,7 @@ GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, GF return gf_enum_directory(cat_enum.szPath, 0, cat_enumerate, &cat_enum, NULL); } -GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) +GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) { GF_Err e; FILE *pl = gf_fopen(playlistName, "r"); @@ -2282,7 +3063,7 @@ GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_F url = gf_url_concatenate(playlistName, szLine); if (!url) url = gf_strdup(szLine); - e = cat_isomedia_file(dest, url, import_flags, force_fps, frames_per_sample, tmp_dir, force_cat, align_timelines, allow_add_in_command, GF_FALSE); + e = cat_isomedia_file(dest, url, import_flags, force_fps, frames_per_sample, force_cat, align_timelines, allow_add_in_command, GF_FALSE); if (e) { @@ -2327,7 +3108,7 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log e = gf_sm_load_init(&load); if (e<0) { gf_sm_load_done(&load); - fprintf(stderr, "Cannot load context %s - %s\n", in, gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Cannot load context %s - %s\n", in, gf_error_to_string(e))); goto err_exit; } e = gf_sm_load_run(&load); @@ -2410,7 +3191,7 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log #endif /*GPAC_DISABLE_SCENE_STATS*/ if (e<0) { - fprintf(stderr, "Error loading file %s\n", gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Error loading file %s\n", gf_error_to_string(e))); goto err_exit; } else { gf_log_cbk prev_logs = NULL; @@ -2546,15 +3327,15 @@ GF_Err EncodeBIFSChunk(GF_SceneManager *ctx, char *bifsOutputFile, GF_Err (*AUCa /*NO CHANGE TO BIFSC otherwise the generated update will not match the input context*/ nbb = GetNbBits(ctx->max_node_id); if (!bcfg->nodeIDbits) bcfg->nodeIDbits=nbb; - if (bcfg->nodeIDbitsnodeIDbitsmax_route_id); if (!bcfg->routeIDbits) bcfg->routeIDbits = nbb; - if (bcfg->routeIDbitsrouteIDbitsmax_proto_id); if (!bcfg->protoIDbits) bcfg->protoIDbits=nbb; - if (bcfg->protoIDbitsprotoIDbitsname, "HDR")) { - fprintf(stderr, "Error parsing HDR XML file: root name is \"%s\", expecting \"HDR\"\n", root->name); + M4_LOG(GF_LOG_ERROR, ("Error parsing HDR XML file: root name is \"%s\", expecting \"HDR\"\n", root->name)); gf_xml_dom_del(parser); return GF_NON_COMPLIANT_BITSTREAM; } i = 0; while ((stream = gf_list_enum(root->content, &i))) { - u32 id = 0, j; + u32 j; GF_XMLAttribute* att = NULL; GF_XMLNode *box = NULL; if (stream->type != GF_XML_NODE_TYPE) continue; if (strcmp(stream->name, "Track")) continue; - j = 0; - while ((att = gf_list_enum(stream->attributes, &j))) { - if (!strcmp(att->name, "id")) id = atoi(att->value); - else fprintf(stderr, "HDR XML: ignoring track attribute \"%s\"\n", att->name); + if (!track) { + j = 0; + while ((att = gf_list_enum(stream->attributes, &j))) { + if (!strcmp(att->name, "id")) { + u32 id = atoi(att->value); + track = gf_isom_get_track_by_id(movie, id); + if (!track) { + fprintf(stderr, "HDR XML: no track with ID %d, ignoring attribute\n", id); + } + } + else fprintf(stderr, "HDR XML: ignoring track attribute \"%s\"\n", att->name); + } } j = 0; @@ -3015,9 +3813,18 @@ GF_Err parse_high_dynamc_range_xml_desc(GF_ISOFile *movie, char *file_name) } } - e = gf_isom_set_high_dynamic_range_info(movie, id, 1, &mdcv, &clli); + if (!track) { + for (i=0; i scanf("%1023s", rad)) { - fprintf(stderr, "No ouput file name entered, aborting.\n"); + fprintf(stderr, "No output file name entered, aborting.\n"); break; } e = gf_seng_save_context(livesess.seng, !strcmp(rad, "std") ? NULL : rad); @@ -699,7 +699,9 @@ int live_session(int argc, char **argv) if (update_length) { e = gf_seng_encode_from_string(livesess.seng, es_id, aggregate_au ? 0 : 1, update_buffer, live_session_callback); - if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Processing command failed: %s\n", gf_error_to_string(e))); + } e = gf_seng_aggregate_context(livesess.seng, 0); update_context = 1; diff --git a/applications/mp4box/main.c b/applications/mp4box/main.c index 7871248..1b3fb4f 100644 --- a/applications/mp4box/main.c +++ b/applications/mp4box/main.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2020 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / mp4box application @@ -57,124 +57,355 @@ #define BUFFSIZE 8192 #define DEFAULT_INTERLEAVING_IN_SEC 0.5 +//undefine to check validity of defined args' syntax +//#define TEST_ARGS + int mp4boxTerminal(int argc, char **argv); -Bool dvbhdemux = GF_FALSE; -Bool keep_sys_tracks = GF_FALSE; +static u32 mp4box_cleanup(u32 ret_code); + +/* + * START OF ARGUMENT VALUES DECLARATION + */ + + +typedef struct +{ + GF_ISOTrackID trackID; + char *line; +} SDPLine; -/*some global vars for swf import :(*/ -u32 swf_flags = 0; -Float swf_flatten_angle = 0; -s32 laser_resolution = 0; -static FILE *helpout = NULL; -static u32 help_flags = 0; +typedef enum { + META_ACTION_SET_TYPE = 0, + META_ACTION_ADD_ITEM = 1, + META_ACTION_REM_ITEM = 2, + META_ACTION_SET_PRIMARY_ITEM = 3, + META_ACTION_SET_XML = 4, + META_ACTION_SET_BINARY_XML = 5, + META_ACTION_REM_XML = 6, + META_ACTION_DUMP_ITEM = 7, + META_ACTION_DUMP_XML = 8, + META_ACTION_ADD_IMAGE_ITEM = 9, + META_ACTION_ADD_IMAGE_DERIVED = 10, +} MetaActionType; typedef struct { - u32 code; - const char *name; - const char *comment; -} itunes_tag; -static const itunes_tag itags[] = { - {GF_ISOM_ITUNE_ALBUM_ARTIST, "album_artist", "usage: album_artist=album artist"}, - {GF_ISOM_ITUNE_ALBUM, "album", "usage: album=name" }, - {GF_ISOM_ITUNE_TRACKNUMBER, "tracknum", "usage: track=x/N"}, - {GF_ISOM_ITUNE_TRACK, "track", "usage: track=name"}, - {GF_ISOM_ITUNE_ARTIST, "artist", "usage: artist=name"}, - {GF_ISOM_ITUNE_COMMENT, "comment", "usage: comment=any comment"}, - {GF_ISOM_ITUNE_COMPILATION, "compilation", "usage: compilation=yes,no"}, - {GF_ISOM_ITUNE_COMPOSER, "composer", "usage: composer=name"}, - {GF_ISOM_ITUNE_CREATED, "created", "usage: created=time"}, - {GF_ISOM_ITUNE_DISK, "disk", "usage: disk=x/N"}, - {GF_ISOM_ITUNE_TOOL, "tool", "usage: tool=name"}, - {GF_ISOM_ITUNE_GENRE, "genre", "usage: genre=name"}, - {GF_ISOM_ITUNE_NAME, "name", "usage: name=name"}, - {GF_ISOM_ITUNE_TEMPO, "tempo", "usage: tempo=integer"}, - {GF_ISOM_ITUNE_WRITER, "writer", "usage: writer=name"}, - {GF_ISOM_ITUNE_GROUP, "group", "usage: group=name"}, - {GF_ISOM_ITUNE_COVER_ART, "cover", "usage: cover=file.jpg,file.png"}, - {GF_ISOM_ITUNE_ENCODER, "encoder", "usage: encoder=name"}, - {GF_ISOM_ITUNE_GAPLESS, "gapless", "usage: gapless=yes,no"}, - {GF_ISOM_ITUNE_ALL, "all", "usage: all=NULL"}, + u32 ref_item_id; + u32 ref_type; +} MetaRef; + +typedef struct +{ + MetaActionType act_type; + Bool root_meta, use_dref; + GF_ISOTrackID trackID; + u32 meta_4cc; + char *szPath, *szName, *mime_type, *enc_type, *keep_props; + u32 item_id; + Bool primary; + Bool replace; + u32 item_type; + u32 ref_item_id; + GF_List *item_refs; + u32 group_id; + u32 group_type; + GF_ImageItemProperties *image_props; +} MetaAction; + + +typedef enum { + TRACK_ACTION_REM_TRACK= 0, + TRACK_ACTION_SET_LANGUAGE, + TRACK_ACTION_SET_DELAY, + TRACK_ACTION_SET_KMS_URI, + TRACK_ACTION_SET_PAR, + TRACK_ACTION_SET_HANDLER_NAME, + TRACK_ACTION_ENABLE, + TRACK_ACTION_DISABLE, + TRACK_ACTION_REFERENCE, + TRACK_ACTION_RAW_EXTRACT, + TRACK_ACTION_REM_NON_RAP, + TRACK_ACTION_SET_KIND, + TRACK_ACTION_REM_KIND, + TRACK_ACTION_SET_ID, + TRACK_ACTION_SET_UDTA, + TRACK_ACTION_SWAP_ID, + TRACK_ACTION_REM_NON_REFS, + TRACK_ACTION_SET_CLAP, + TRACK_ACTION_SET_MX, + TRACK_ACTION_SET_EDITS, + TRACK_ACTION_SET_TIME, + TRACK_ACTION_SET_MEDIA_TIME, +} TrackActionType; + +typedef struct +{ + TrackActionType act_type; + GF_ISOTrackID trackID; + char lang[10]; + GF_Fraction delay; + const char *kms; + const char *hdl_name; + s32 par_num, par_den; + u8 force_par, rewrite_bs; + u32 dump_type, sample_num; + char *out_name; + char *src_name; + char *string; + u32 udta_type; + char *kind_scheme, *kind_value; + u32 newTrackID; + s32 clap_wnum, clap_wden, clap_hnum, clap_hden, clap_honum, clap_hoden, clap_vonum, clap_voden; + s32 mx[9]; + u64 time; + u8 dump_track_type; +} TrackAction; + +enum +{ + GF_ISOM_CONV_TYPE_ISMA = 1, + GF_ISOM_CONV_TYPE_ISMA_EX, + GF_ISOM_CONV_TYPE_3GPP, + GF_ISOM_CONV_TYPE_IPOD, + GF_ISOM_CONV_TYPE_PSP, + GF_ISOM_CONV_TYPE_MOV }; -u32 nb_itunes_tags = sizeof(itags) / sizeof(itunes_tag); +typedef enum { + TSEL_ACTION_SET_PARAM = 0, + TSEL_ACTION_REMOVE_TSEL = 1, + TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP = 2, +} TSELActionType; + +typedef struct +{ + TSELActionType act_type; + GF_ISOTrackID trackID; + + GF_ISOTrackID refTrackID; + u32 criteria[30]; + u32 nb_criteria; + Bool is_switchGroup; + u32 switchGroupID; +} TSELAction; + +GF_FileType get_file_type_by_ext(char *inName); + + +char outfile[GF_MAX_PATH]; +#ifndef GPAC_DISABLE_SCENE_ENCODER +GF_SMEncodeOptions smenc_opts; +u32 swf_flags = GF_SM_SWF_SPLIT_TIMELINE; +#endif +GF_Fraction import_fps; + +//things to free upon cleanup +MetaAction *metas = NULL; +TrackAction *tracks = NULL; +TSELAction *tsel_acts = NULL; +SDPLine *sdp_lines = NULL; +u32 *brand_add = NULL; +u32 *brand_rem = NULL; +char **mpd_base_urls = NULL; +u32 nb_mpd_base_urls = 0; +GF_DashSegmenterInput *dash_inputs = NULL; +u32 nb_dash_inputs = 0; + + + +//all other options values - keep options with assignment other than 0 on a single line + +FILE *helpout = NULL; +u32 help_flags = 0; + +Double interleaving_time=0.0, split_duration=0.0, split_start=-1.0, dash_duration=0.0, dash_subduration=0.0, swf_flatten_angle=0.0; +Bool dash_duration_strict=0, dvbhdemux=0, keep_sys_tracks=0; + +u64 initial_tfdt=0; +s32 subsegs_per_sidx=0, laser_resolution=0, ast_offset_ms=0; +const char *split_range_str = NULL; +GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_DEFAULT; +u32 stat_level=0, hint_flags=0, info_track_id=0, import_flags=0, nb_add=0, nb_cat=0, crypt=0, agg_samples=0, nb_sdp_ex=0, max_ptime=0, split_size=0, nb_meta_act=0, nb_track_act=0, rtp_rate=0, major_brand=0, nb_alt_brand_add=0, nb_alt_brand_rem=0, old_interleave=0, minor_version=0, conv_type=0, nb_tsel_acts=0, program_number=0, dump_nal=0, time_shift_depth=0, initial_moof_sn=0, dump_std=0, import_subtitle=0, dump_saps=0, dump_saps_mode=0, force_new=0; +GF_DashDynamicMode dash_mode=GF_DASH_STATIC; +#ifndef GPAC_DISABLE_SCENE_DUMP +GF_SceneDumpFormat dump_mode=GF_SM_DUMP_NONE; +#endif + +/*align cat is the new default behavior for -cat*/ +Bool align_cat=GF_TRUE; + +Double mpd_live_duration=0; +Bool do_hint=0, do_save=0, full_interleave=0, do_frag=0, hint_interleave=0, dump_rtp=0, regular_iod=0, remove_sys_tracks=0, remove_hint=0, remove_root_od=0; +Bool print_sdp=0, open_edit=0, dump_cr=0, force_ocr=0, encode=0, do_scene_log=0, dump_srt=0, dump_ttxt=0, do_saf=0, dump_m2ts=0, dump_cart=0, dump_chunk=0, dump_check_xml=0; +Bool do_hash=0, verbose=0, force_cat=0, pack_wgt=0, single_group=0, clean_groups=0, dash_live=0, no_fragments_defaults=0; +Bool single_traf_per_moof=0, tfdt_per_traf=0, hls_clock=0, do_mpd_rip=0, merge_vtt_cues=0, get_nb_tracks=0; +u32 compress_moov=0; +char *inName=NULL, *outName=NULL, *mediaSource=NULL, *input_ctx=NULL, *output_ctx=NULL, *drm_file=NULL, *avi2raw=NULL, *cprt=NULL; +char *chap_file=NULL, *chap_file_qt=NULL, *itunes_tags=NULL, *pack_file=NULL, *raw_cat=NULL, *seg_name=NULL, *dash_ctx_file=NULL; +char *compress_top_boxes=NULL, *high_dynamc_range_filename=NULL, *use_init_seg=NULL, *box_patch_filename=NULL, *udp_dest = NULL; + +GF_ISOTrackID trackID=0; +u32 track_dump_type=0, dump_isom=0, dump_timestamps=0, dump_nal_type=0, do_flat=0, box_patch_trackID=0, print_info=0; +Bool no_inplace=0, merge_last_seg=0, freeze_box_order=0, no_odf_conf=0; +Double min_buffer = 1.5; +u32 size_top_box=0, fs_dump_flags=0, dump_chap=0, dump_udta_type=0, dump_udta_track=0, moov_pading=0, sdtp_in_traf=0, segment_marker=0, timescale=0; + +u32 dash_scale = 1000; +GF_ISOFile *file = NULL; + +Bool insert_utc=0, chunk_mode=0, HintCopy=0, hint_no_offset=0, do_bin_xml=0, frag_real_time=0, force_co64=0, live_scene=0, use_mfra=0; +Bool dump_iod=0, samplegroups_in_traf=0, mvex_after_traks=0, daisy_chain_sidx=0, use_ssix=0, single_segment=0, single_file=0, segment_timeline=0; +Bool has_add_image=0; + +char *do_mpd_conv=NULL; +u32 MTUSize = 1450; +char *dash_start_date=NULL; +GF_DASH_ContentLocationMode cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET; +Double mpd_update_time = 0.0; +GF_MemTrackerType mem_track = GF_MemTrackerNone; +GF_DASHPSSHMode pssh_mode=0; + +GF_DashProfile dash_profile=GF_DASH_PROFILE_AUTO; +char *dash_profile_extension = NULL; +char *dash_cues = NULL; +Bool strict_cues=0, use_url_template=0, seg_at_rap=0, frag_at_rap=0, memory_frags=0, keep_utc=0, has_next_arg=0, no_cache=0, no_loop=0; +u32 adjust_split_end=0; +char *do_wget = NULL; +char *mux_name = NULL; +char *seg_ext = NULL; +char *init_seg_ext = NULL; +char *dash_title = NULL; +char *dash_source = NULL; +char *dash_more_info = NULL; + +FILE *logfile = NULL; +u32 run_for=0, dash_cumulated_time=0, dash_prev_time=0, dash_now_time=0; +GF_DASH_SplitMode dash_split_mode = GF_DASH_SPLIT_OUT; + + +typedef u32 (*parse_arg_fun)(char *arg_val, u32 param); +typedef u32 (*parse_arg_fun2)(char *arg_name, char *arg_val, u32 param); + +//other custom option parsing functions definitions are in mp4box.h +static u32 parse_meta_args(char *opts, MetaActionType act_type); +static Bool parse_tsel_args(char *opts, TSELActionType act); + + + +/* + * START OF ARGS PARSING AND HELP + */ -void PrintVersion() +Bool print_version(char *arg_val, u32 param) { fprintf(stderr, "MP4Box - GPAC version %s\n" "%s\n" "GPAC Configuration: " GPAC_CONFIGURATION "\n" "Features: %s %s\n", gf_gpac_version(), gf_gpac_copyright_cite(), gf_sys_features(GF_FALSE), gf_sys_features(GF_TRUE)); + return GF_TRUE; } -GF_GPACArg m4b_gen_args[] = +//arg will toggle open_edit +#define ARG_OPEN_EDIT 1 +//arg will toggle do_save +#define ARG_NEED_SAVE 1<<1 +#define ARG_NO_INPLACE 1<<2 +#define ARG_BIT_MASK 1<<3 +#define ARG_BIT_MASK_REM 1<<4 +#define ARG_HAS_VALUE 1<<5 +#define ARG_DIV_1000 1<<6 +#define ARG_NON_ZERO 1<<7 +#define ARG_64BITS 1<<8 +#define ARG_IS_4CC 1<<9 +#define ARG_BOOL_REV 1<<10 +#define ARG_INT_INC 1<<11 +#define ARG_IS_FUN 1<<12 +#define ARG_EMPTY 1<<13 +#define ARG_PUSH_SYSARGS 1<<14 +#define ARG_IS_FUN2 1<<15 + + + +typedef struct +{ + GF_GPAC_ARG_BASE + + void *arg_ptr; + u32 argv_val; + u16 parse_flags; +} MP4BoxArg; + +#define MP4BOX_ARG(_a, _c, _f, _g, _h, _i, _j) {_a, NULL, _c, NULL, NULL, _f, _g, _h, _i, _j} +#define MP4BOX_ARG_ALT(_a, _b, _c, _f, _g, _h, _i, _j) {_a, _b, _c, NULL, NULL, _f, _g, _h, _i, _j} +#define MP4BOX_ARG_S(_a, _s, _c, _g, _h, _i, _j) {_a, NULL, _c, _s, NULL, GF_ARG_CUSTOM, _g, _h, _i, _j} +#define MP4BOX_ARG_S_ALT(_a, _b, _s, _c, _g, _h, _i, _j) {_a, _b, _c, _s, NULL, GF_ARG_CUSTOM, _g, _h, _i, _j} + + +MP4BoxArg m4b_gen_args[] = { #ifdef GPAC_MEMORY_TRACKING - GF_DEF_ARG("mem-track", NULL, "enable memory tracker", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("mem-track-stack", NULL, "enable memory tracker with stack dumping", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), + MP4BOX_ARG("mem-track", "enable memory tracker", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, NULL, 0, 0), + MP4BOX_ARG("mem-track-stack", "enable memory tracker with stack dumping", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, NULL, 0, 0), #endif - GF_DEF_ARG("p", NULL, "use indicated profile for the global GPAC config. If not found, config file is created. If a file path is indicated, this will load profile from that file. Otherwise, this will create a directory of the specified name and store new config there. Reserved name `0` means a new profile, not stored to disk. Works using -p=NAME or -p NAME", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("inter", NULL, "interleave file, producing track chunks with given duration in ms. A value of 0 disables interleaving ", "0.5", NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("old-inter", NULL, "same as [-inter]() but wihout drift correction", NULL, NULL, GF_ARG_DOUBLE, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("tight", NULL, "tight interleaving (sample based) of the file. This reduces disk seek operations but increases file size", NULL, NULL, GF_ARG_DOUBLE, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("flat", NULL, "store file with all media data first, non-interleaved. This speeds up writing time when creating new files", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("frag", NULL, "fragment file, producing track fragments of given duration in ms. This disables interleaving", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("out", NULL, "specify output file name. By default input file is overwritten", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("tmp", NULL, "specify directory for temporary file creation", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("co64", NULL, "force usage of 64-bit chunk offsets for ISOBMF files", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("new", NULL, "force creation of a new destination file", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("newfs", NULL, "force creation of a new destination file without temp file but interleaving support", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("no-sys", NULL, "remove all MPEG-4 Systems info except IOD, kept for profiles. This is the default when creating regular AV content", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("no-iod", NULL, "remove MPEG-4 InitialObjectDescriptor from file", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("mfra", NULL, "insert movie fragment random offset when fragmenting file (ignored in dash mode)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("isma", NULL, "rewrite the file as an ISMA 1.0 file", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("ismax", NULL, "same as [-isma]() and remove all clock references", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("3gp", NULL, "rewrite as 3GPP(2) file (no more MPEG-4 Systems Info), always enabled if destination file extension is `.3gp`, `.3g2` or `.3gpp`. Some tracks may be removed in the process", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("ipod", NULL, "rewrite the file for iPod/old iTunes", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("psp", NULL, "rewrite the file for PSP devices", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("brand", NULL, "set major brand of file (`ABCD`) or brand with optional version (`ABCD:v`)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("ab", NULL, "add given brand to file's alternate brand list", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("rb", NULL, "remove given brand to file's alternate brand list", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("cprt", NULL, "add copyright string to file", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("chap", NULL, "set chapter information from given file", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("chapqt", NULL, "set chapter information from given file, using QT signaling for text tracks", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("set-track-id `id1:id2`", NULL, "change id of track with id1 to id2", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("swap-track-id `id1:id2`", NULL, "swap the id between tracks with id1 to id2", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("rem", NULL, "remove given track from file", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("rap", NULL, "remove all non-RAP samples from given track", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("refonly", NULL, "remove all non-reference pictures from given track", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("enable", NULL, "enable given track", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("disable", NULL, "disable given track", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("timescale", NULL, "set movie timescale to given value (ticks per second)", "600", NULL, GF_ARG_INT, 0), - GF_DEF_ARG("lang `[tkID=]LAN`", NULL, "set language. LAN is the BCP-47 code (eng, en-UK, ...). If no track ID is given, sets language to all tracks", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("delay `tkID=TIME`", NULL, "set track start delay in ms", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("par `tkID=PAR`", NULL, "set visual track pixel aspect ratio. PAR is:\n" + MP4BOX_ARG("p", "use indicated profile for the global GPAC config. If not found, config file is created. If a file path is indicated, this will load profile from that file. Otherwise, this will create a directory of the specified name and store new config there. Reserved name `0` means a new profile, not stored to disk. Works using -p=NAME or -p NAME", GF_ARG_STRING, GF_ARG_HINT_EXPERT, NULL, 0, 0), + {"inter", NULL, "interleave file, producing track chunks with given duration in ms. A value of 0 disables interleaving ", "0.5", NULL, GF_ARG_DOUBLE, 0, parse_store_mode, 0, ARG_IS_FUN}, + MP4BOX_ARG("old-inter", "same as [-inter]() but without drift correction", GF_ARG_DOUBLE, GF_ARG_HINT_EXPERT, parse_store_mode, 1, ARG_IS_FUN), + MP4BOX_ARG("tight", "tight interleaving (sample based) of the file. This reduces disk seek operations but increases file size", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &full_interleave, 0, ARG_OPEN_EDIT|ARG_NEED_SAVE), + MP4BOX_ARG("flat", "store file with all media data first, non-interleaved. This speeds up writing time when creating new files", GF_ARG_BOOL, 0, &do_flat, 0, ARG_NO_INPLACE), + MP4BOX_ARG("frag", "fragment file, producing track fragments of given duration in ms. This disables interleaving", GF_ARG_DOUBLE, 0, parse_store_mode, 2, ARG_IS_FUN), + MP4BOX_ARG("out", "specify ISOBMFF output file name. By default input file is overwritten", GF_ARG_STRING, 0, &outName, 0, 0), + MP4BOX_ARG("co64","force usage of 64-bit chunk offsets for ISOBMF files", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &force_co64, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("new", "force creation of a new destination file", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &force_new, 0, 0), + MP4BOX_ARG("newfs", "force creation of a new destination file without temp file but interleaving support", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, parse_store_mode, 3, ARG_IS_FUN), + MP4BOX_ARG_ALT("no-sys", "nosys", "remove all MPEG-4 Systems info except IOD, kept for profiles. This is the default when creating regular AV content", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &remove_sys_tracks, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("no-iod", "remove MPEG-4 InitialObjectDescriptor from file", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &remove_root_od, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("mfra", "insert movie fragment random offset when fragmenting file (ignored in dash mode)", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &use_mfra, 0, 0), + MP4BOX_ARG("isma", "rewrite the file as an ISMA 1.0 file", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_ISMA, ARG_OPEN_EDIT), + MP4BOX_ARG("ismax", "same as [-isma]() and remove all clock references", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_ISMA_EX, ARG_OPEN_EDIT), + MP4BOX_ARG("3gp", "rewrite as 3GPP(2) file (no more MPEG-4 Systems Info), always enabled if destination file extension is `.3gp`, `.3g2` or `.3gpp`. Some tracks may be removed in the process", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_3GPP, ARG_OPEN_EDIT), + MP4BOX_ARG("ipod", "rewrite the file for iPod/old iTunes", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_IPOD, ARG_OPEN_EDIT), + MP4BOX_ARG("psp", "rewrite the file for PSP devices", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_PSP, ARG_OPEN_EDIT), + MP4BOX_ARG("brand", "set major brand of file (`ABCD`) or brand with optional version (`ABCD:v`)", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_brand, 0, ARG_IS_FUN), + MP4BOX_ARG("ab", "add given brand to file's alternate brand list", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_brand, 1, ARG_IS_FUN), + MP4BOX_ARG("rb", "remove given brand to file's alternate brand list", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_brand, 2, ARG_IS_FUN), + MP4BOX_ARG("cprt", "add copyright string to file", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &cprt, 0, 0), + MP4BOX_ARG("chap", "set chapter information from given file. The following formats are supported (but cannot be mixed) in the chapter text file:\n" + " - ZoomPlayer: `AddChapter(nb_frames,chapter name)`, `AddChapterBySeconds(nb_sec,chapter name)` and `AddChapterByTime(h,m,s,chapter name)` with 1 chapter per line\n" + " - Time codes: `h:m:s chapter_name`, `h:m:s:ms chapter_name` and `h:m:s.ms chapter_name` with 1 chapter per line\n" + " - SMPTE codes: `h:m:s;nb_f/fps chapter_name` and `h:m:s;nb_f chapter_name` with `nb_f` the number of frames and `fps` the framerate with 1 chapter per line\n" + " - Common syntax: `CHAPTERX=h:m:s[:ms or .ms]` on first line and `CHAPTERXNAME=name` on next line (reverse order accepted)", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &chap_file, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("chapqt", "set chapter information from given file, using QT signaling for text tracks", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &chap_file_qt, 0, ARG_OPEN_EDIT), + MP4BOX_ARG_S("set-track-id", "id1:id2", "change id of track with id1 to id2", 0, parse_track_action, TRACK_ACTION_SET_ID, ARG_IS_FUN), + MP4BOX_ARG_S("swap-track-id", "id1:id2", "swap the id between tracks with id1 to id2", 0, parse_track_action, TRACK_ACTION_SWAP_ID, ARG_IS_FUN), + MP4BOX_ARG("rem", "remove given track from file", GF_ARG_INT, 0, parse_track_action, TRACK_ACTION_REM_TRACK, ARG_IS_FUN), + MP4BOX_ARG("rap", "remove all non-RAP samples from given track", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_rap_ref, 0, ARG_IS_FUN | ARG_EMPTY), + MP4BOX_ARG("refonly", "remove all non-reference pictures from given track", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_rap_ref, 1, ARG_IS_FUN | ARG_EMPTY), + MP4BOX_ARG("enable", "enable given track", GF_ARG_INT, 0, parse_track_action, TRACK_ACTION_ENABLE, ARG_IS_FUN), + MP4BOX_ARG("disable", "disable given track", GF_ARG_INT, 0, parse_track_action, TRACK_ACTION_DISABLE, ARG_IS_FUN), + {"timescale", NULL, "set movie timescale to given value (ticks per second)", "600", NULL, GF_ARG_INT, 0, ×cale, 0, ARG_OPEN_EDIT}, + MP4BOX_ARG_S("lang", "[tkID=]LAN", "set language. LAN is the BCP-47 code (eng, en-UK, ...). If no track ID is given, sets language to all tracks", 0, parse_track_action, TRACK_ACTION_SET_LANGUAGE, ARG_IS_FUN), + MP4BOX_ARG_S("delay", "tkID=TIME", "set track start delay (>0) or initial skip (<0) in ms or in fractional seconds (`N/D`)", 0, parse_track_action, TRACK_ACTION_SET_DELAY, ARG_IS_FUN), + MP4BOX_ARG_S("par", "tkID=PAR", "set visual track pixel aspect ratio. PAR is:\n" " - N:D: set PAR to N:D in track, do not modify the bitstream\n" " - wN:D: set PAR to N:D in track and try to modify the bitstream\n" " - none: remove PAR info from track, do not modify the bitstream\n" " - auto: retrieve PAR info from bitstream and set it in track\n" - " - force: force 1:1 PAR in track, do not modify the bitstream", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("clap `tkID=CLAP`", NULL, "set visual track clean aperture. CLAP is `Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd` or `none`\n" + " - force: force 1:1 PAR in track, do not modify the bitstream", GF_ARG_HINT_ADVANCED, parse_track_action, TRACK_ACTION_SET_PAR, ARG_IS_FUN + ), + MP4BOX_ARG_S("clap", "tkID=CLAP", "set visual track clean aperture. CLAP is `Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd` or `none`\n" "- n, d: numerator, denominator\n" "- W, H, HO, VO: clap width, clap height, clap horizontal offset, clap vertical offset\n" - , NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("mx `tkID=MX`", NULL, "set track matrix, with MX is M1:M2:M3:M4:M5:M6:M7:M8:M9 in 16.16 fixed point intergers or hexa" - , NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("name `tkID=NAME`", NULL, "set track handler name to NAME (UTF-8 string)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("itags `tag1[:tag2]`", NULL, "set iTunes tags to file, see [-tag-list]()", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("tag-list", NULL, "print the set of supported iTunes tags", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("split", NULL, "split in files of given max duration", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("split-size", "splits", "split in files of given max size (in kb)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("split-rap", "splitr", "split in files at each new RAP", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("split-chunk VAL", "splitx", "extract a new file from source. `VAL` can be formated as:\n" - "- `S:E`: `S` (number of seconds) to `E` with `E` a number (in seconds), `end` or `end-N`, N number of seconds before the end\n" - "- `S-E`: start and end dates, each formatted as `HH:MM:SS.ms` or `MM:SS.ms`", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("splitz `S:E`", NULL, "same as -split-chunk, but adjust the end time to be before the last RAP sample", NULL, NULL, GF_ARG_STRING, 0), - - GF_DEF_ARG("group-add", NULL, "create a new grouping information in the file. Format is a colon-separated list of following options:\n" + , GF_ARG_HINT_ADVANCED, parse_track_action, TRACK_ACTION_SET_CLAP, ARG_IS_FUN), + MP4BOX_ARG_S("mx", "tkID=MX", "set track matrix, with MX is M1:M2:M3:M4:M5:M6:M7:M8:M9 in 16.16 fixed point integers or hexa" + , GF_ARG_HINT_ADVANCED, parse_track_action, TRACK_ACTION_SET_MX, ARG_IS_FUN), + MP4BOX_ARG_S("kind", "tkID=schemeURI=value", "set kind for the track or for all tracks using `all=schemeURI=value`", 0, parse_track_action, TRACK_ACTION_SET_KIND, ARG_IS_FUN), + MP4BOX_ARG_S("kind-rem", "tkID=schemeURI=value", "remove kind if given schemeID for the track or for all tracks with `all=schemeURI=value`", 0, parse_track_action, TRACK_ACTION_REM_KIND, ARG_IS_FUN), + MP4BOX_ARG_S("name", "tkID=NAME", "set track handler name to NAME (UTF-8 string)", GF_ARG_HINT_ADVANCED, parse_track_action, TRACK_ACTION_SET_HANDLER_NAME, ARG_IS_FUN), + MP4BOX_ARG("itags", "set iTunes tags to file, see `-h tags`", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &itunes_tags, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("group-add", "create a new grouping information in the file. Format is a colon-separated list of following options:\n" "- refTrack=ID: ID of the track used as a group reference. If not set, the track will belong to the same group as the " "previous trackID specified. If 0 or no previous track specified, a new alternate group will be created\n" "- switchID=ID: ID of the switch group to create. If 0, a new ID will be computed for you. If <0, disables SwitchGroup\n" @@ -182,26 +413,41 @@ GF_GPACArg m4b_gen_args[] = "- trackID=ID: ID of the track to add to this group\n" " \n" "Warning: Options modify state as they are parsed, `trackID=1:criteria=lang:trackID=2` is different from `criteria=lang:trackID=1:trackID=2`" - "\n", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - - GF_DEF_ARG("group-rem-track", NULL, "remove given track from its group", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("group-rem", NULL, "remove the track's group\n", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("group-clean", NULL, "remove all group information from all tracks\n", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("ref `id:XXXX:refID`", NULL, "add a reference of type 4CC from track ID to track refID\n", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("keep-utc", NULL, "keep UTC timing in the file after edit\n", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("udta tkID:[OPTS]", NULL, "set udta for given track or movie if tkID is 0. OPTS is a colon separated list of:\n" + "\n", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_tsel_args, TSEL_ACTION_SET_PARAM, ARG_IS_FUN), + + MP4BOX_ARG("group-rem-track", "remove given track from its group", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_tsel_args, TSEL_ACTION_REMOVE_TSEL, ARG_IS_FUN), + MP4BOX_ARG("group-rem", "remove the track's group", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_tsel_args, TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP, ARG_IS_FUN), + MP4BOX_ARG("group-clean", "remove all group information from all tracks", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &clean_groups, 0, ARG_OPEN_EDIT), + MP4BOX_ARG_S("ref", "id:XXXX:refID", "add a reference of type 4CC from track ID to track refID", GF_ARG_HINT_ADVANCED, parse_track_action, TRACK_ACTION_REFERENCE, ARG_IS_FUN), + MP4BOX_ARG("keep-utc", "keep UTC timing in the file after edit", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &keep_utc, 0, 0), + MP4BOX_ARG_S("udta", "tkID:[OPTS]", "set udta for given track or movie if tkID is 0. OPTS is a colon separated list of:\n" "- type=CODE: 4CC code of the UDTA (not needed for `box=` option)\n" "- box=FILE: location of the udta data, formatted as serialized boxes\n" "- box=base64,DATA: base64 encoded udta data, formatted as serialized boxes\n" "- src=FILE: location of the udta data (will be stored in a single box of type CODE)\n" "- src=base64,DATA: base64 encoded udta data (will be stored in a single box of type CODE)\n" - "Note: If no source is set, UDTA of type CODE will be removed\n", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("patch [tkID=]FILE", NULL, "apply box patch described in FILE, for given trackID if set\n", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("bo", NULL, "freeze the order of boxes in input file\n", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("init-seg", NULL, "use the given file as an init segment for dumping or for encryption\n", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED), - GF_DEF_ARG("zmov", NULL, "compress movie box according to ISOBMFF box compression\n", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED), - - + "- str=STRING: use the given string as payload for the udta box\n" + "Note: If no source is set, UDTA of type CODE will be removed\n", GF_ARG_HINT_ADVANCED, parse_track_action, TRACK_ACTION_SET_UDTA, ARG_IS_FUN|ARG_OPEN_EDIT), + MP4BOX_ARG_S("patch", "[tkID=]FILE", "apply box patch described in FILE, for given trackID if set", GF_ARG_HINT_ADVANCED, parse_boxpatch, 0, ARG_IS_FUN), + MP4BOX_ARG("bo", "freeze the order of boxes in input file", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &freeze_box_order, 0, 0), + MP4BOX_ARG("init-seg", "use the given file as an init segment for dumping or for encryption", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &use_init_seg, 0, 0), + MP4BOX_ARG("zmov", "compress movie box according to ISOBMFF box compression", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, parse_compress, 0, ARG_IS_FUN), + MP4BOX_ARG("xmov", "same as zmov and wraps ftyp in otyp", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, parse_compress, 1, ARG_IS_FUN), + MP4BOX_ARG_S("edits", "tkID=EDITS", "set edit list. The following syntax is used (no separators between entries):\n" + " - `r`: removes all edits\n" + " - `eSTART`: add empty edit with given start time. START can be\n" + " - `VAL`: start time in seconds (int, double, fraction), media duration used as edit duration\n" + " - `VAL-DUR`: start time and duration in seconds (int, double, fraction)\n" + " - `eSTART,MEDIA[,RATE]`: add regular edit with given start, media start time in seconds (int, double, fraction) and rate (fraction or INT)\n" + " - Examples: \n" + " - `re0-5e5-3,4`: remove edits, add empty edit at 0s for 5s, then add regular edit at 5s for 3s starting at 4s in media track\n" + " - `re0-4,0,0.5`: remove edits, add single edit at 0s for 4s starting at 0s in media track and playing at speed 0.5\n" + , 0, parse_track_action, TRACK_ACTION_SET_EDITS, ARG_IS_FUN), + MP4BOX_ARG("moovpad", "specify amount of padding to keep after moov box for later inplace editing - if 0, moov padding is disabled", GF_ARG_INT, GF_ARG_HINT_EXPERT, &moov_pading, 0, ARG_NEED_SAVE), + MP4BOX_ARG("no-inplace", "disable inplace rewrite", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &no_inplace, 0, 0), + MP4BOX_ARG("hdr", "update HDR information based on given XML, 'none' removes HDR info", GF_ARG_STRING, GF_ARG_HINT_EXPERT, &high_dynamc_range_filename, 0, ARG_OPEN_EDIT), + MP4BOX_ARG_S("time", "[tkID=]DAY/MONTH/YEAR-H:M:S", "set movie or track creation time", GF_ARG_HINT_EXPERT, parse_track_action, TRACK_ACTION_SET_TIME, ARG_IS_FUN), + MP4BOX_ARG_S("mtime", "tkID=DAY/MONTH/YEAR-H:M:S", "set media creation time", GF_ARG_HINT_EXPERT, parse_track_action, TRACK_ACTION_SET_MEDIA_TIME, ARG_IS_FUN), {0} }; @@ -209,47 +455,108 @@ void PrintGeneralUsage() { u32 i=0; gf_sys_format_help(helpout, help_flags, "# General Options\n" - "MP4Box is a multimedia packager, with a vast number of functionalities: conversion, splitting, hinting, dumping, DASH-ing, encryption and others.\n" + "MP4Box is a multimedia packager, with a vast number of functionalities: conversion, splitting, hinting, dumping, DASH-ing, encryption, transcoding and others.\n" "MP4Box provides a large set of options, classified by categories (see [-h]()). These options do not follow any particular ordering.\n" - "MP4Box performs in-place rewrite of IsoMedia files (the input file is overwritten). You can change this behaviour by using the [-out]() option.\n" - "MP4Box stores by default the file with 0.5 second interleaving and meta-data (`moov`...) at the beginning, making it suitable for HTTP streaming. This may however takes longer to store the file, use [-flat]() to change this behaviour.\n" + " \n" + "By default, MP4Box rewrites the input file. You can change this behavior by using the [-out]() option.\n" + "MP4Box stores by default the file with 0.5 second interleaving and meta-data (`moov` ...) at the beginning, making it suitable for HTTP download-and-play. This may however takes longer to store the file, use [-flat]() to change this behavior.\n" + " \n" "MP4Box usually generates a temporary file when creating a new IsoMedia file. The location of this temporary file is OS-dependent, and it may happen that the drive/partition the temporary file is created on has not enough space or no write access. In such a case, you can specify a temporary file location with [-tmp]().\n" - "Note: Track operations identify tracks through their ID (usually refered as tkID in the help), not their order.\n" + " \n" "Option values:\n" "Unless specified otherwise, an option of type `integer` expects a trackID value following it." "An option of type `boolean` expects no following value." + "Note: Track operations identify tracks through their ID (usually referred to as tkID in the help), not their order.\n" " \n" - "# File Splitting and Concatenation\n" - "MP4Box can split IsoMedia files by size, duration or extract a given part of the file to new IsoMedia file(s). This process requires that at most one track in the input file has non random-access points (typically one video track at most). This process will also ignore all MPEG-4 Systems tracks and hint tracks, but will try to split private media tracks.\n" - "Note: The input file must have enough random access points in order to be split. This may not be the case with some video files where only the very first sample of the video track is a key frame (many 3GP files with H263 video are recorded that way). In order to split such files you will have to use a real video editor and re-encode the content.\n" - "Note: You can add media to a file and split it in the same pass. In this case, the destination file (the one which would be obtained without spliting) will not be stored.\n" - " \n" - "Options:\n" ); + while (m4b_gen_args[i].name) { - GF_GPACArg *arg = &m4b_gen_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_gen_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-gen"); } } -GF_GPACArg m4b_dash_args[] = +MP4BoxArg m4b_split_args[] = +{ + MP4BOX_ARG("split", "split in files of given max duration (float number) in seconds. A trailing unit can be specified:\n" + "- `M`, `m`: duration is in minutes\n" + "- `H`, `h`: size is in hours", GF_ARG_STRING, 0, parse_split, 0, ARG_IS_FUN), + MP4BOX_ARG_ALT("split-rap", "splitr", "split in files at each new RAP", GF_ARG_STRING, 0, parse_split, 1, ARG_IS_FUN), + MP4BOX_ARG_ALT("split-size", "splits", "split in files of given max size (integer number) in kilobytes. A trailing unit can be specified:\n" + "- `M`, `m`: size is in megabytes\n" + "- `G`, `g`: size is in gigabytes", GF_ARG_STRING, 0, parse_split, 2, ARG_IS_FUN), + MP4BOX_ARG_ALT("split-chunk", "splitx", "extract the specified time range as follows:\n" + "- the start time is moved to the RAP sample closest to the specified start time\n" + "- the end time is kept as requested" + , GF_ARG_STRING, 0, parse_split, 3, ARG_IS_FUN), + MP4BOX_ARG("splitz", "extract the specified time range so that ranges `A:B` and `B:C` share exactly the same boundary `B`:\n" + "- the start time is moved to the RAP sample at or after the specified start time\n" + "- the end time is moved to the frame preceding the RAP sample at or following the specified end time" + , GF_ARG_STRING, 0, parse_split, 4, ARG_IS_FUN), + MP4BOX_ARG("splitg", "extract the specified time range as follows:\n" + "- the start time is moved to the RAP sample at or before the specified start time\n" + "- the end time is moved to the frame preceding the RAP sample at or following the specified end time" + , GF_ARG_STRING, 0, parse_split, 5, ARG_IS_FUN), + MP4BOX_ARG("splitf", "extract the specified time range and insert edits such that the extracted output is exactly the specified range\n", GF_ARG_STRING, 0, parse_split, 6, ARG_IS_FUN), + {0} +}; + + +static void PrintSplitUsage() +{ + u32 i=0; + gf_sys_format_help(helpout, help_flags, " \n" + "# File splitting\n" + "MP4Box can split input files by size, duration or extract a given part of the file to new IsoMedia file(s).\n" + "This requires that at most one track in the input file has non random-access points (typically one video track at most).\n" + "Splitting will ignore all MPEG-4 Systems tracks and hint tracks, but will try to split private media tracks.\n" + "The input file must have enough random access points in order to be split. If this is not the case, you will have to re-encode the content.\n" + "You can add media to a file and split it in the same pass. In this case, the destination file (the one which would be obtained without splitting) will not be stored.\n" + " \n" + "Time ranges are specified as follows:\n" + "- `S-E`: `S` start and `E` end times, formatted as `HH:MM:SS.ms`, `MM:SS.ms` or time in seconds (int, double, fraction)\n" + "- `S:E`: `S` start time and `E` end times in seconds (int, double, fraction)\n" + "- `S:end` or `S:end-N`: `S` start time in seconds (int, double), `N` number of seconds (int, double) before the end\n" + " \n" + "MP4Box splitting runs a filter session using the `reframer` filter as follows:\n" + "- `splitrange` option of the reframer is always set\n" + "- source is demultiplexed with `alltk` option set\n" + "- start and end ranges are passed to `xs` and `xe` options of the reframer\n" + "- for `-splitz`, options `xadjust` and `xround=after` are enforced\n" + "- for `-splitg`, options `xadjust` and `xround=before` are enforced\n" + "- for `-splitf`, option `xround=seek` is enforced and `propbe_ref`set if not specified at prompt\n" + "- for `-splitx`, option `xround=closest` and `propbe_ref` are enforced if not specified at prompt\n" + " \n" + "The default output storage mode is to full interleave and will require a temp file for each output. This behavior can be modified using `-flat`, `-newfs`, `-inter` and `-frag`.\n" + "The output file name(s) can be specified using `-out` and templates (e.g. `-out split$num%%04d$.mp4` produces split0001.mp4, split0002.mp4, ...).\n" + " \n" + ); + + i=0; + while (m4b_split_args[i].name) { + GF_GPACArg *arg = (GF_GPACArg *) &m4b_split_args[i]; + i++; + gf_sys_print_arg(helpout, help_flags, arg, "mp4box-split"); + } + +} + + +MP4BoxArg m4b_dash_args[] = { - GF_DEF_ARG("mpd", NULL, "convert given HLS or smooth manifest (local or remote http) to MPD. \nWarning: This is not compatible with other DASH options and does not convert associated segments", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("dash", "-dash-strict", "create DASH from input files with given segment (subsegment for onDemand profile) duration in ms", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("dash-live", NULL, "generate a live DASH session using the given segment duration in ms; using `-dash-live=F`will also write the live context to `F`. MP4Box will run the live session until `q` is pressed or a fatal error occurs", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("ddbg-live", NULL, "same as [-dash-live]() without time regulation for debug purposes", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("frag", NULL, "specify the fragment duration in ms. If not set, this is the DASH duration (one fragment per segment)", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("out", NULL, "specify the output MPD file name", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("tmp", NULL, "specify directory for temporary file creation", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("profile", NULL, "specify the target DASH profile, and set default options to ensure conformance to the desired profile. Default profile is `full` in static mode, `live` in dynamic mode", NULL, "onDemand|live|main|simple|full|hbbtv1.5:live|dashavc264:live|dashavc264:onDemand", GF_ARG_STRING, 0), - GF_DEF_ARG("profile-ext", NULL, "specify a list of profile extensions, as used by DASH-IF and DVB. The string will be colon-concatenated with the profile used", NULL, NULL, GF_ARG_STRING, 0), - - GF_DEF_ARG("rap", NULL, "ensure that segments begin with random access points, segment durations might vary depending on the source encoding", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("frag-rap", NULL, "ensure that all fragments begin with random access points (duration might vary depending on the source encoding)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("segment-name", NULL, "set the segment name for generated segments. If not set (default), segments are concatenated in output file except in `live` profile where `dash_%%s`. Supported replacement strings are:\n" + MP4BOX_ARG ("dash", "create DASH from input files with given segment (subsegment for onDemand profile) duration in ms", GF_ARG_DOUBLE, 0, &dash_duration, 0, ARG_NON_ZERO), + MP4BOX_ARG("dash-live", "generate a live DASH session using the given segment duration in ms; using `-dash-live=F` will also write the live context to `F`. MP4Box will run the live session until `q` is pressed or a fatal error occurs", GF_ARG_DOUBLE, 0, parse_dashlive, 0, ARG_IS_FUN2), + MP4BOX_ARG("ddbg-live", "same as [-dash-live]() without time regulation for debug purposes", GF_ARG_DOUBLE, 0, parse_dashlive, 1, ARG_IS_FUN2), + MP4BOX_ARG("frag", "specify the fragment duration in ms. If not set, this is the DASH duration (one fragment per segment)", GF_ARG_DOUBLE, 0, parse_store_mode, 2, ARG_IS_FUN), + MP4BOX_ARG("out", "specify the output MPD file name", GF_ARG_STRING, 0, &outName, 0, 0), + MP4BOX_ARG_ALT("profile", "dash-profile", "specify the target DASH profile, and set default options to ensure conformance to the desired profile. Default profile is `full` in static mode, `live` in dynamic mode (old syntax using `:live` instead of `.live` as separator still possible). Defined values are onDemand, live, main, simple, full, hbbtv1.5.live, dashavc264.live, dashavc264.onDemand, dashif.ll", GF_ARG_STRING, 0, parse_dash_profile, 0, ARG_IS_FUN), + MP4BOX_ARG("profile-ext", "specify a list of profile extensions, as used by DASH-IF and DVB. The string will be colon-concatenated with the profile used", GF_ARG_STRING, 0, &dash_profile_extension, 0, 0), + MP4BOX_ARG("rap", "ensure that segments begin with random access points, segment durations might vary depending on the source encoding", GF_ARG_BOOL, 0, parse_rap_ref, 0, ARG_IS_FUN | ARG_EMPTY), + MP4BOX_ARG("frag-rap", "ensure that all fragments begin with random access points (duration might vary depending on the source encoding)", GF_ARG_BOOL, 0, &frag_at_rap, 0, 0), + MP4BOX_ARG("segment-name", "set the segment name for generated segments. If not set (default), segments are concatenated in output file except in `live` profile where `dash_%%s`. Supported replacement strings are:\n" "- $Number[%%0Nd]$ is replaced by the segment number, possibly prefixed with 0\n" "- $RepresentationID$ is replaced by representation name\n" "- $Time$ is replaced by segment start time\n" @@ -257,77 +564,78 @@ GF_GPACArg m4b_dash_args[] = "- $Init=NAME$ is replaced by NAME for init segment, ignored otherwise\n" "- $Index=NAME$ is replaced by NAME for index segments, ignored otherwise\n" "- $Path=PATH$ is replaced by PATH when creating segments, ignored otherwise\n" - "- $Segment=NAME$ is replaced by NAME for media segments, ignored for init segments", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("segment-ext", NULL, "set the segment extension, `null` means no extension", "m4s", NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("init-segment-ext", NULL, "set the segment extension for init, index and bitstream switching segments, `null` means no extension\n", "mp4", NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("segment-timeline", NULL, "use `SegmentTimeline` when generating segments", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("segment-marker `MARK`", NULL, "add a box of type `MARK` (4CC) at the end of each DASH segment", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("insert-utc", NULL, "insert UTC clock at the beginning of each ISOBMF segment", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("base-url", NULL, "set Base url at MPD level. Can be used several times. \nWarning: this does not modify generated files location", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mpd-title", NULL, "set MPD title", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mpd-source", NULL, "set MPD source", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mpd-info-url", NULL, "set MPD info url", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("cprt", NULL, "add copyright string to MPD", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("dash-ctx", NULL, "store/restore DASH timing from indicated file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("dynamic", NULL, "use dynamic MPD type instead of static", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("last-dynamic", NULL, "same as [-dynamic]() but close the period (insert lmsg brand if needed and update duration)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mpd-duration", NULL, "set the duration in second of a live session (if `0`, you must use [-mpd-refresh]())", "0", NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("mpd-refresh", NULL, "specify MPD update time in seconds", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("time-shift", NULL, "specify MPD time shift buffer depth in seconds, `-1` to keep all files)", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("subdur", NULL, "specify maximum duration in ms of the input file to be dashed in LIVE or context mode. This does not change the segment duration, but stops dashing once segments produced exceeded the duration. If there is not enough samples to finish a segment, data is looped unless [-no-loop]() is used which triggers a period end", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("run-for", NULL, "run for given ms the dash-live session then exits", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("min-buffer", NULL, "specify MPD min buffer time in ms", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("ast-offset", NULL, "specify MPD AvailabilityStartTime offset in ms if positive, or availabilityTimeOffset of each representation if negative", "0", NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dash-scale", NULL, "specify that timing for [-dash]() and [-frag]() are expressed in given timexale (units per seconds)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("mem-frags", NULL, "fragmentation happens in memory rather than on disk before flushing to disk", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("pssh", NULL, "set pssh store mode\n" + "- $Segment=NAME$ is replaced by NAME for media segments, ignored for init segments", GF_ARG_STRING, 0, &seg_name, 0, 0), + {"segment-ext", NULL, "set the segment extension, `null` means no extension", "m4s", NULL, GF_ARG_STRING, 0, &seg_ext, 0, 0}, + {"init-segment-ext", NULL, "set the segment extension for init, index and bitstream switching segments, `null` means no extension\n", "mp4", NULL, GF_ARG_STRING, 0, &init_seg_ext, 0, 0}, + MP4BOX_ARG("segment-timeline", "use `SegmentTimeline` when generating segments", GF_ARG_BOOL, 0, &segment_timeline, 0, 0), + MP4BOX_ARG("segment-marker", "add a box of given type (4CC) at the end of each DASH segment", GF_ARG_STRING, 0, &segment_marker, 0, ARG_IS_4CC), + MP4BOX_ARG("insert-utc", "insert UTC clock at the beginning of each ISOBMF segment", GF_ARG_BOOL, 0, &insert_utc, 0, 0), + MP4BOX_ARG("base-url", "set Base url at MPD level. Can be used several times. \nWarning: this does not modify generated files location", GF_ARG_STRING, 0, parse_base_url, 0, ARG_IS_FUN), + MP4BOX_ARG("mpd-title", "set MPD title", GF_ARG_STRING, 0, &dash_title, 0, 0), + MP4BOX_ARG("mpd-source", "set MPD source", GF_ARG_STRING, 0, &dash_source, 0, 0), + MP4BOX_ARG("mpd-info-url", "set MPD info url", GF_ARG_STRING, 0, &dash_more_info, 0, 0), + MP4BOX_ARG("cprt", "add copyright string to MPD", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &cprt, 0, 0), + MP4BOX_ARG("dash-ctx", "store/restore DASH timing from indicated file", GF_ARG_STRING, 0, &dash_ctx_file, 0, 0), + MP4BOX_ARG("dynamic", "use dynamic MPD type instead of static", GF_ARG_BOOL, 0, &dash_mode, GF_DASH_DYNAMIC, 0), + MP4BOX_ARG("last-dynamic", "same as [-dynamic]() but close the period (insert lmsg brand if needed and update duration)", GF_ARG_BOOL, 0, &dash_mode, GF_DASH_DYNAMIC_LAST, 0), + MP4BOX_ARG("mpd-duration", "set the duration in second of a live session (if `0`, you must use [-mpd-refresh]())", GF_ARG_DOUBLE, 0, &mpd_live_duration, 0, 0), + MP4BOX_ARG("mpd-refresh", "specify MPD update time in seconds", GF_ARG_DOUBLE, 0, &mpd_update_time, 0, 0), + MP4BOX_ARG("time-shift", "specify MPD time shift buffer depth in seconds, `-1` to keep all files)", GF_ARG_INT, 0, &time_shift_depth, 0, 0), + MP4BOX_ARG("subdur", "specify maximum duration in ms of the input file to be dashed in LIVE or context mode. This does not change the segment duration, but stops dashing once segments produced exceeded the duration. If there is not enough samples to finish a segment, data is looped unless [-no-loop]() is used which triggers a period end", GF_ARG_DOUBLE, 0, &dash_subduration, 0, 0), + MP4BOX_ARG("run-for", "run for given ms the dash-live session then exits", GF_ARG_INT, 0, &run_for, 0, 0), + MP4BOX_ARG("min-buffer", "specify MPD min buffer time in ms", GF_ARG_INT, 0, &min_buffer, 0, ARG_DIV_1000), + MP4BOX_ARG("ast-offset", "specify MPD AvailabilityStartTime offset in ms if positive, or availabilityTimeOffset of each representation if negative", GF_ARG_INT, 0, &ast_offset_ms, 0, 0), + MP4BOX_ARG("dash-scale", "specify that timing for [-dash](), [-dash-live](), [-subdur]() and [-do_frag]() are expressed in given timescale (units per seconds) rather than ms", GF_ARG_INT, 0, &dash_scale, 0, ARG_NON_ZERO), + MP4BOX_ARG("mem-frags", "fragmentation happens in memory rather than on disk before flushing to disk", GF_ARG_BOOL, 0, &memory_frags, 0, 0), + MP4BOX_ARG("pssh", "set pssh store mode\n" "- v: initial movie\n" "- f: movie fragments\n" "- m: MPD\n" "- mv, vm: in initial movie and MPD\n" - "- mf, fm: in movie fragments and MPD", NULL, "v|f|m|mv|vm|mf|fm", GF_ARG_INT, 0), - GF_DEF_ARG("sample-groups-traf", NULL, "store sample group descriptions in traf (duplicated for each traf). If not set, sample group descriptions are stored in the initial movie", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("mvex-after-traks", NULL, "store `mvex` box after `trak` boxes within the moov box. If not set, `mvex` is before", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("sdtp-traf", NULL, "use `sdtp` box in `traf` (Smooth-like)\n" + "- mf, fm: in movie fragments and MPD", GF_ARG_INT, 0, parse_pssh, 0, ARG_IS_FUN), + MP4BOX_ARG("sample-groups-traf", "store sample group descriptions in traf (duplicated for each traf). If not set, sample group descriptions are stored in the initial movie", GF_ARG_BOOL, 0, &samplegroups_in_traf, 0, 0), + MP4BOX_ARG("mvex-after-traks", "store `mvex` box after `trak` boxes within the moov box. If not set, `mvex` is before", GF_ARG_BOOL, 0, &mvex_after_traks, 0, 0), + MP4BOX_ARG("sdtp-traf", "use `sdtp` box in `traf` (Smooth-like)\n" "- no: do not use sdtp\n" - "- sdtp: use sdtp box to indicate sample dependencies and don't write info in trun sample flags\n" - "- both: use sdtp box to indicate sample dependencies and also write info in trun sample flags\n", NULL, "no|sdtp|both", GF_ARG_INT, 0), - GF_DEF_ARG("no-cache", NULL, "disable file cache for dash inputs", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-loop", NULL, "disable looping content in live mode and uses period switch instead", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("hlsc", NULL, "insert UTC in variant playlists for live HLS", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("bound", NULL, "segmentation will always try to split before or at, but never after, the segment boundary", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("closest", NULL, "segmentation will use the closest frame to the segment boundary (before or after)", NULL, NULL, GF_ARG_BOOL, 0), - - GF_DEF_ARG("subsegs-per-sidx", NULL, "set the number of subsegments to be written in each SIDX box\n" + "- sdtp: use sdtp box to indicate sample dependencies and do not write info in trun sample flags\n" + "- both: use sdtp box to indicate sample dependencies and also write info in trun sample flags\n", GF_ARG_INT, 0, parse_sdtp, 0, ARG_IS_FUN), + MP4BOX_ARG("no-cache", "disable file cache for dash inputs", GF_ARG_BOOL, 0, &no_cache, 0, 0), + MP4BOX_ARG("no-loop", "disable looping content in live mode and uses period switch instead", GF_ARG_BOOL, 0, &no_loop, 0, 0), + MP4BOX_ARG("hlsc", "insert UTC in variant playlists for live HLS", GF_ARG_BOOL, 0, &hls_clock, 0, 0), + MP4BOX_ARG("bound", "segmentation will always try to split before or at, but never after, the segment boundary", GF_ARG_BOOL, 0, &dash_split_mode, GF_DASH_SPLIT_IN, 0), + MP4BOX_ARG("closest", "segmentation will use the closest frame to the segment boundary (before or after)", GF_ARG_BOOL, 0, &dash_split_mode, GF_DASH_SPLIT_CLOSEST, 0), + MP4BOX_ARG_ALT("subsegs-per-sidx", "frags-per-sidx", "set the number of subsegments to be written in each SIDX box\n" "- 0: a single SIDX box is used per segment\n" - "- -1: no SIDX box is used", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("ssix", NULL, "enable SubsegmentIndexBox describing 2 ranges, first one from moof to end of first I-frame, second one unmapped. This does not work with daisy chaining mode enabled", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("url-template", NULL, "use SegmentTemplate instead of explicit sources in segments. Ignored if segments are stored in the output file", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("daisy-chain", NULL, "use daisy-chain SIDX instead of hierarchical. Ignored if frags/sidx is 0", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("single-segment", NULL, "use a single segment for the whole file (OnDemand profile)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("single-file", NULL, "use a single file for the whole file (default)", "yes", NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("bs-switching", NULL, "set bitstream switching mode\n" + "- -1: no SIDX box is used", GF_ARG_INT, GF_ARG_HINT_EXPERT, &subsegs_per_sidx, 0, 0), + MP4BOX_ARG("ssix", "enable SubsegmentIndexBox describing 2 ranges, first one from moof to end of first I-frame, second one unmapped. This does not work with daisy chaining mode enabled", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &use_ssix, 0, 0), + MP4BOX_ARG("url-template", "use SegmentTemplate instead of explicit sources in segments. Ignored if segments are stored in the output file", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &use_url_template, 1, 0), + MP4BOX_ARG("url-template-sim", "use SegmentTemplate simulation while converting HLS to MPD", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &use_url_template, 2, 0), + MP4BOX_ARG("daisy-chain", "use daisy-chain SIDX instead of hierarchical. Ignored if frags/sidx is 0", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &daisy_chain_sidx, 0, 0), + MP4BOX_ARG("single-segment", "use a single segment for the whole file (OnDemand profile)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &single_segment, 0, 0), + {"single-file", NULL, "use a single file for the whole file (default)", "yes", NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &single_file, 0, 0}, + {"bs-switching", NULL, "set bitstream switching mode\n" "- inband: use inband param set and a single init segment\n" "- merge: try to merge param sets in a single sample description, fallback to `no`\n" "- multi: use several sample description, one per quality\n" "- no: use one init segment per quality\n" - "- single: to test with single input", "inband", "inband|merge|multi|no|single", GF_ARG_STRING, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("moof-sn", NULL, "set sequence number of first moof to given value", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("tfdt", NULL, "set TFDT of first traf to given value in SCALE units (cf -dash-scale)", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("no-frags-default", NULL, "disable default fragments flags in trex (required by some dash-if profiles and CMAF/smooth streaming compatibility)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("single-traf", NULL, "use a single track fragment per moof (smooth streaming and derived specs may require this)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("tfdt-traf", NULL, "use a tfdt per track fragment (when -single-traf is used)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("dash-ts-prog", NULL, "program_number to be considered in case of an MPTS input file", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("frag-rt", NULL, "when using fragments in live mode, flush fragments according to their timing", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("cp-location", NULL, "set ContentProtection element location\n" + "- pps: use out of band VPS,SPS,DCI, inband for PPS,APS and a single init segment\n" + "- single: to test with single input", "inband", "inband|merge|multi|no|single", GF_ARG_STRING, GF_ARG_HINT_EXPERT, parse_bs_switch, 0, ARG_IS_FUN}, + MP4BOX_ARG("moof-sn", "set sequence number of first moof to given value", GF_ARG_INT, GF_ARG_HINT_EXPERT, &initial_moof_sn, 0, 0), + MP4BOX_ARG("tfdt", "set TFDT of first traf to given value in SCALE units (cf -dash-scale)", GF_ARG_INT, GF_ARG_HINT_EXPERT, &initial_tfdt, 0, ARG_64BITS), + MP4BOX_ARG("no-frags-default", "disable default fragments flags in trex (required by some dash-if profiles and CMAF/smooth streaming compatibility)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &no_fragments_defaults, 0, 0), + MP4BOX_ARG("single-traf", "use a single track fragment per moof (smooth streaming and derived specs may require this)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &single_traf_per_moof, 0, 0), + MP4BOX_ARG("tfdt-traf", "use a tfdt per track fragment (when -single-traf is used)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &tfdt_per_traf, 0, 0), + MP4BOX_ARG("dash-ts-prog", "program_number to be considered in case of an MPTS input file", GF_ARG_INT, GF_ARG_HINT_EXPERT, &program_number, 0, 0), + MP4BOX_ARG("frag-rt", "when using fragments in live mode, flush fragments according to their timing", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &frag_real_time, 0, 0), + MP4BOX_ARG("cp-location", "set ContentProtection element location\n" "- as: sets ContentProtection in AdaptationSet element\n" "- rep: sets ContentProtection in Representation element\n" - "- both: sets ContentProtection in both elements", NULL, "as|rep\both", GF_ARG_STRING, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("start-date", NULL, "for live mode, set start date (as xs:date, eg YYYY-MM-DDTHH:MM:SSZ). Default is current UTC\n" - "Warning: Do not use with multiple periods, nor when DASH duration is not a multiple of GOP size", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT), - - GF_DEF_ARG("cues", NULL, "ignore dash duration and segment according to cue times in given XML file (tests/media/dash_cues for examples)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT), - GF_DEF_ARG("strict-cues", NULL, "throw error if something is wrong while parsing cues or applying cue-based segmentation", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT), + "- both: sets ContentProtection in both elements", GF_ARG_STRING, GF_ARG_HINT_EXPERT, parse_cp_loc, 0, ARG_IS_FUN), + MP4BOX_ARG("start-date", "for live mode, set start date (as xs:date, e.g. YYYY-MM-DDTHH:MM:SSZ). Default is current UTC\n" + "Warning: Do not use with multiple periods, nor when DASH duration is not a multiple of GOP size", GF_ARG_STRING, GF_ARG_HINT_EXPERT, &dash_start_date, 0, 0), + MP4BOX_ARG("cues", "ignore dash duration and segment according to cue times in given XML file (tests/media/dash_cues for examples)", GF_ARG_STRING, GF_ARG_HINT_EXPERT, &dash_cues, 0, 0), + MP4BOX_ARG("strict-cues", "throw error if something is wrong while parsing cues or applying cue-based segmentation", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &strict_cues, 0, 0), + MP4BOX_ARG("merge-last-seg", "merge last segment if shorter than half the target duration", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &merge_last_seg, 0, 0), {0} }; @@ -337,7 +645,7 @@ void PrintDASHUsage() gf_sys_format_help(helpout, help_flags, "# DASH Options\n" "Also see:\n" "- the [dasher `gpac -h dash`](dasher) filter documentation\n" - "- [[online DASH Intro doc|DASH Introduction]].\n" + "- [[DASH wiki|DASH-intro]].\n" "\n" "# Specifying input files\n" "Input media files to dash can use the following modifiers\n" @@ -345,13 +653,13 @@ void PrintDASHUsage() "- #N: only use the track ID N from the source file (mapped to [-tkid](mp4dmx))\n" "- #video: only use the first video track from the source file\n" "- #audio: only use the first audio track from the source file\n" - "- :id=NAME: set the representation ID to NAME. Reserved value `NULL` disables representation ID for multiplexed inputs\n" - "- :dur=VALUE: process VALUE seconds from the media. If VALUE is longer than media duration, last sample duration is extended.\n" + "- :id=NAME: set the representation ID to NAME. Reserved value `NULL` disables representation ID for multiplexed inputs. If not set, a default value is computed and all selected tracks from the source will be in the same output multiplex.\n" + "- :dur=VALUE: process VALUE seconds (fraction) from the media. If VALUE is longer than media duration, last sample duration is extended.\n" "- :period=NAME: set the representation's period to NAME. Multiple periods may be used. Periods appear in the MPD in the same order as specified with this option\n" "- :BaseURL=NAME: set the BaseURL. Set multiple times for multiple BaseURLs\nWarning: This does not modify generated files location (see segment template).\n" "- :bandwidth=VALUE: set the representation's bandwidth to a given value\n" - "- :pdur=VALUE: increase the duration of this period by the given duration in seconds (alias for period_duration:VALUE). This is only used when no input media is specified (remote period insertion), eg `:period=X:xlink=Z:pdur=Y`\n" - "- :duration=VALUE: override target DASH segment duration for this input\n" + "- :pdur=VALUE: sets the duration of the associated period to VALUE seconds (fraction) (alias for period_duration:VALUE). This is only used when no input media is specified (remote period insertion), e.g. `:period=X:xlink=Z:pdur=Y`\n" + "- :ddur=VALUE: override target DASH segment duration to VALUE seconds (fraction) for this input (alias for duration:VALUE)\n" "- :xlink=VALUE: set the xlink value for the period containing this element. Only the xlink declared on the first rep of a period will be used\n" "- :asID=VALUE: set the AdaptationSet ID to NAME\n" "- :role=VALUE: set the role of this representation (cf DASH spec). Media with different roles belong to different adaptation sets.\n" @@ -361,68 +669,77 @@ void PrintDASHUsage() "- :desc_rep=VALUE: add a descriptor at the Representation level. Value must be a properly formatted XML element. Value is ignored while creating AdaptationSet elements.\n" "- :sscale: force movie timescale to match media timescale of the first track in the segment.\n" "- :trackID=N: only use the track ID N from the source file\n" - "- @@f1[:args][@@fN:args]: set a filter chain to insert between the source and the dasher. Each filter in the chain is formatted as a regular filter, see [filter doc `gpac -h doc`](filters_general). If several filters are set, they will be chained in the given order.\n" + "- @f1[:args][@fN:args][@@fK:args]: set a filter chain to insert between the source and the dasher. Each filter in the chain is formatted as a regular filter, see [filter doc `gpac -h doc`](filters_general). If several filters are set:\n" + " - they will be chained in the given order if separated by a single `@`\n" + " - a new filter chain will be created if separated by a double `@@`. In this case, no representation ID is assigned to the source.\n" + "EX source.mp4:@c=avc:b=1M@@c=avc:b=500k\n" + "This will load a filter chain with two encoders connected to the source and to the dasher.\n" + "EX source.mp4:@c=avc:b=1M@c=avc:b=500k\n" + "This will load a filter chain with the second encoder connected to the output of the first (!!).\n" "\n" - "Note: `@@f` must be placed after all other options.\n" + "Note: `@f` must be placed after all other options.\n" "\n" "# Options\n" ); while (m4b_dash_args[i].name) { - GF_GPACArg *arg = &m4b_dash_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_dash_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-dash"); } } -GF_GPACArg m4b_imp_args[] = +MP4BoxArg m4b_imp_args[] = { - GF_DEF_ARG("add", NULL, "add given file tracks to file. Multiple inputs can be specified using `+`, eg `-add url1+url2", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("cat", NULL, "concatenate given file samples to file, creating tracks if needed. Multiple inputs can be specified using `+`(eg `-cat url1+url2). \nNote: This aligns initial timestamp of the file to be concatenated", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("catx", NULL, "same as [-cat]() but new tracks can be imported before concatenation by specifying `+ADD_COMMAND` where `ADD_COMMAND` is a regular [-add]() syntax", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("catpl", NULL, "concatenate files listed in the given playlist file (one file per line, lines starting with # are comments). \nNote: Each listed file is concatenated as if called with -cat", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("unalign-cat", NULL, "do not attempt to align timestamps of samples inbetween tracks", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("force-cat", NULL, "skip media configuration check when concatenating file. \nWarning: THIS MAY BREAK THE CONCATENATED TRACK(S)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("keep-sys", NULL, "keep all MPEG-4 Systems info when using [-add]() and [-cat]() (only used when adding IsoMedia files)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dref", NULL, "keep media data in original file using `data referencing`. The resulting file only contains the meta-data of the presentation (frame sizes, timing, etc...) and references media data in the original file. This is extremely useful when developping content, since importing and storage of the MP4 file is much faster and the resulting file much smaller. \nNote: Data referencing may fail on some files because it requires the framed data (eg an IsoMedia sample) to be continuous in the original file, which is not always the case depending on the original interleaving or bitstream format (__AVC__ or __HEVC__ cannot use this option)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-drop", NULL, "force constant FPS when importing AVI video", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("packed", NULL, "force packed bitstream when importing raw MPEG-4 part 2 Advanced Simple Profile", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("sbr", NULL, "backward compatible signaling of AAC-SBR", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("sbrx", NULL, "non-backward compatible signaling of AAC-SBR", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ps", NULL, "backward compatible signaling of AAC-PS", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("psx", NULL, "non-backward compatible signaling of AAC-PS", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ovsbr", NULL, "oversample SBR import (SBR AAC, PS AAC and oversampled SBR cannot be detected at import time)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("fps", NULL, "force frame rate for video and SUB subtitles import to the given value, expressed as a number or as `timescale-increment`. \nNote: For raw H263 import, default FPS is `15`, otherwise `25`. This is ignored for ISOBMFF import, use `:rescale` option for that", "25", NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mpeg4", NULL, "force MPEG-4 sample descriptions when possible. For AAC, forces MPEG-4 AAC signaling even if MPEG-2", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("agg", NULL, "aggregate N audio frames in 1 sample (3GP media only, maximum value is 15)", NULL, NULL, GF_ARG_INT, 0), + MP4BOX_ARG("add", "add given file tracks to file. Multiple inputs can be specified using `+`, e.g. `-add url1+url2`", GF_ARG_STRING, 0, &nb_add, 0, ARG_INT_INC), + MP4BOX_ARG("cat", "concatenate given file samples to file, creating tracks if needed. Multiple inputs can be specified using `+`, e.g/ `-cat url1+url2`. \nNote: This aligns initial timestamp of the file to be concatenated", GF_ARG_STRING, 0, &nb_cat, 0, ARG_INT_INC), + MP4BOX_ARG("catx", "same as [-cat]() but new tracks can be imported before concatenation by specifying `+ADD_COMMAND` where `ADD_COMMAND` is a regular [-add]() syntax", GF_ARG_STRING, 0, &nb_cat, 0, ARG_INT_INC), + MP4BOX_ARG("catpl", "concatenate files listed in the given playlist file (one file per line, lines starting with # are comments). \nNote: Each listed file is concatenated as if called with -cat", GF_ARG_STRING, 0, &nb_cat, 0, ARG_INT_INC), + MP4BOX_ARG("unalign-cat", "do not attempt to align timestamps of samples in-between tracks", GF_ARG_BOOL, 0, &align_cat, 0, ARG_BOOL_REV), + MP4BOX_ARG("force-cat", "skip media configuration check when concatenating file. \nWarning: THIS MAY BREAK THE CONCATENATED TRACK(S)", GF_ARG_BOOL, 0, &force_cat, 0, 0), + MP4BOX_ARG("keep-sys", "keep all MPEG-4 Systems info when using [-add]() and [-cat]() (only used when adding IsoMedia files)", GF_ARG_BOOL, 0, &keep_sys_tracks, 0, 0), + MP4BOX_ARG("dref", "keep media data in original file using `data referencing`. The resulting file only contains the meta-data of the presentation (frame sizes, timing, etc...) and references media data in the original file. This is extremely useful when developing content, since importing and storage of the MP4 file is much faster and the resulting file much smaller. \nNote: Data referencing may fail on some files because it requires the framed data (e.g. an IsoMedia sample) to be continuous in the original file, which is not always the case depending on the original interleaving or bitstream format (__AVC__ or __HEVC__ cannot use this option)", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_USE_DATAREF, ARG_BIT_MASK), + MP4BOX_ARG_ALT("no-drop", "nodrop", "force constant FPS when importing AVI video", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_NO_FRAME_DROP, ARG_BIT_MASK), + MP4BOX_ARG("packed", "force packed bitstream when importing raw MPEG-4 part 2 Advanced Simple Profile", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_FORCE_PACKED, ARG_BIT_MASK), + MP4BOX_ARG("sbr", "backward compatible signaling of AAC-SBR", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_SBR_IMPLICIT, ARG_BIT_MASK), + MP4BOX_ARG("sbrx", "non-backward compatible signaling of AAC-SBR", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_SBR_EXPLICIT, ARG_BIT_MASK), + MP4BOX_ARG("ps", "backward compatible signaling of AAC-PS", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_PS_IMPLICIT, ARG_BIT_MASK), + MP4BOX_ARG("psx", "non-backward compatible signaling of AAC-PS", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_PS_EXPLICIT, ARG_BIT_MASK), + MP4BOX_ARG("ovsbr", "oversample SBR import (SBR AAC, PS AAC and oversampled SBR cannot be detected at import time)", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_OVSBR, ARG_BIT_MASK), + MP4BOX_ARG("fps", "force frame rate for video and SUB subtitles import to the given value, expressed as a number, as `TS-inc` or `TS/inc`. \nNote: For raw H263 import, default FPS is `15`, otherwise `25`. This is ignored for ISOBMFF import, use `:rescale` option for that", GF_ARG_STRING, 0, parse_fps, 0, ARG_IS_FUN), + MP4BOX_ARG("mpeg4", "force MPEG-4 sample descriptions when possible. For AAC, forces MPEG-4 AAC signaling even if MPEG-2", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_FORCE_MPEG4, ARG_BIT_MASK), + MP4BOX_ARG("agg", "aggregate N audio frames in 1 sample (3GP media only, maximum value is 15)", GF_ARG_INT, 0, &agg_samples, 0, 0), {0} }; -static GF_GPACArg ImportFileOpts [] = { - GF_DEF_ARG("dur", NULL, "`X` import only the specified duration from the media. Value can be:\n" +static MP4BoxArg m4b_imp_fileopt_args [] = { + GF_DEF_ARG("dur", NULL, "`XC` import only the specified duration from the media. Value can be:\n" " - positive float: specifies duration in seconds\n" " - fraction: specifies duration as NUM/DEN fraction\n" " - negative integer: specifies duration in number of coded frames", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("lang", NULL, "set imported media language code", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("delay", NULL, "set imported media initial delay in ms", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("par", NULL, "set visual pixel aspect ratio (see [-par](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("clap", NULL, "set visual clean aperture (see [-clap](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mx", NULL, "set track matrix (see [-mx](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("name", NULL, "set track handler name", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("start", NULL, "`C` target start time in source media, may not be supported depending on the source", NULL, NULL, GF_ARG_DOUBLE, 0), + GF_DEF_ARG("lang", NULL, "`S` set imported media language code", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("delay", NULL, "`S` set imported media initial delay (>0) or initial skip (<0) in ms or as fractional seconds (`N/D`)", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("par", NULL, "`S` set visual pixel aspect ratio (see [-par](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("clap", NULL, "`S` set visual clean aperture (see [-clap](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("mx", NULL, "`S` set track matrix (see [-mx](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("name", NULL, "`S` set track handler name", NULL, NULL, GF_ARG_STRING, 0), GF_DEF_ARG("ext", NULL, "override file extension when importing", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("hdlr", NULL, "set track handler type to the given code point (4CC)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("disable", NULL, "disable imported track(s)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("group", NULL, "add the track as part of the G alternate group. If G is 0, the first available GroupID will be picked", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("hdlr", NULL, "`S` set track handler type to the given code point (4CC)", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("stype", NULL, "`S` force sample description type to given code point (4CC), may likely break the file", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("tkhd", NULL, "`S` set track header flags has hex integer or as comma-separated list of `enable`, `movie`, `preview`, `size_ar` keywords (use `tkhd+=FLAGS` to add and `tkhd-=FLAGS` to remove)", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("disable", NULL, "`S` disable imported track(s), use `disable=no` to force enabling a disabled track", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("group", NULL, "`S` add the track as part of the G alternate group. If G is 0, the first available GroupID will be picked", NULL, NULL, GF_ARG_INT, 0), GF_DEF_ARG("fps", NULL, "same as [-fps]()", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("rap", NULL, "`D` import only RAP samples", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("refs", NULL, "`D` import only reference pictures", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("rap", NULL, "`DS` import only RAP samples", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("refs", NULL, "`DS` import only reference pictures", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("trailing", NULL, "keep trailing 0-bytes in AVC/HEVC samples", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("agg", NULL, "`X` same as [-agg]()", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dref", NULL, "`X` same as [-dref]()", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("keep_refs", NULL, "keep track reference when importing a single track", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("dref", NULL, "`XC` same as [-dref]()", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("keep_refs", NULL, "`C` keep track reference when importing a single track", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("nodrop", NULL, "same as [-nodrop]()", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("packed", NULL, "`X` same as [-packed]()", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("sbr", NULL, "same as [-sbr]()", NULL, NULL, GF_ARG_BOOL, 0), @@ -430,54 +747,55 @@ static GF_GPACArg ImportFileOpts [] = { GF_DEF_ARG("ovsbr", NULL, "same as [-ovsbr]()", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("ps", NULL, "same as [-ps]()", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("psx", NULL, "same as [-psx]()", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("asemode", NULL, "`X` set the mode to create the AudioSampleEntry. Value can be:\n" + GF_DEF_ARG("asemode", NULL, "`XS` set the mode to create the AudioSampleEntry. Value can be:\n" " - v0-bs: use MPEG AudioSampleEntry v0 and the channel count from the bitstream (even if greater than 2) - default\n" " - v0-2: use MPEG AudioSampleEntry v0 and the channel count is forced to 2\n" " - v1: use MPEG AudioSampleEntry v1 and the channel count from the bitstream\n" " - v1-qt: use QuickTime Sound Sample Description Version 1 and the channel count from the bitstream (even if greater than 2). This will also trigger using alis data references instead of url, even for non-audio tracks", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("audio_roll", NULL, "add a roll sample group with roll_distance `N`", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("audio_roll", NULL, "`S` add a roll sample group with roll_distance `N` for audio tracks", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("roll", NULL, "`S` add a roll sample group with roll_distance `N`", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("proll", NULL, "`S` add a preroll sample group with roll_distance `N`", NULL, NULL, GF_ARG_INT, 0), GF_DEF_ARG("mpeg4", NULL, "`X` same as [-mpeg4]() option", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("nosei", NULL, "discard all SEI messages during import", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("svc", NULL, "import SVC/LHVC with explicit signaling (no AVC base compatibility)", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("nosvc", NULL, "discard SVC/LHVC data when importing", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("svcmode", NULL, "`D` set SVC/LHVC import mode. Value can be:\n" + GF_DEF_ARG("svcmode", NULL, "`DS` set SVC/LHVC import mode. Value can be:\n" " - split: each layer is in its own track\n" " - merge: all layers are merged in a single track\n" " - splitbase: all layers are merged in a track, and the AVC base in another\n" " - splitnox: each layer is in its own track, and no extractors are written\n" " - splitnoxib: each layer is in its own track, no extractors are written, using inband param set signaling", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("temporal", NULL, "`D` set HEVC/LHVC temporal sublayer import mode. Value can be:\n" + GF_DEF_ARG("temporal", NULL, "`DS` set HEVC/LHVC temporal sublayer import mode. Value can be:\n" " - split: each sublayer is in its own track\n" " - splitbase: all sublayers are merged in a track, and the HEVC base in another\n" " - splitnox: each layer is in its own track, and no extractors are written", NULL, NULL, GF_ARG_STRING, 0), GF_DEF_ARG("subsamples", NULL, "add SubSample information for AVC+SVC", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("deps", NULL, "import sample dependency information for AVC and HEVC", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ccst", NULL, "add default HEIF ccst box to visual sample entry", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("forcesync", NULL, "force non IDR samples with I slices to be marked as sync points (AVC GDR)\n" + GF_DEF_ARG("ccst", NULL, "`S` add default HEIF ccst box to visual sample entry", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("forcesync", NULL, "force non IDR samples with I slices (OpenGOP or GDR) to be marked as sync points\n" "Warning: RESULTING FILE IS NOT COMPLIANT WITH THE SPEC but will fix seeking in most players", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("xps_inband", NULL, "`X` set xPS inband for AVC/H264 and HEVC (for reverse operation, re-import from raw media)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("xps_inbandx", NULL, "`X` same as xps_inband and also keep first xPS in sample desciption", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("xps_inband", NULL, "`XC` set xPS inband for AVC/H264 and HEVC (for reverse operation, re-import from raw media)", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("xps_inbandx", NULL, "`XC` same as xps_inband and also keep first xPS in sample description", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("au_delim", NULL, "keep AU delimiter NAL units in the imported file", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("max_lid", NULL, "set HEVC max layer ID to be imported to `N` (by default imports all layers)", NULL, NULL, GF_ARG_INT, 0), GF_DEF_ARG("max_tid", NULL, "set HEVC max temporal ID to be imported to `N` (by default imports all temporal sublayers)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("tiles", NULL, "add HEVC tiles signaling and NALU maps without splitting the tiles into different tile tracks", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("split_tiles", NULL, "`D` split HEVC tiles into different tile tracks, one tile (or all tiles of one slice) per track", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("negctts", NULL, "use negative CTS-DTS offsets (ISO4 brand)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("chap", NULL, "specify the track is a chapter track", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("chapter", NULL, "add a single chapter (old nero format) with given name lasting the entire file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("chapfile", NULL, "add a chapter file (old nero format)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("layout", NULL, "specify the track layout as WxHxXxY\n" - " - if W (resp H) = 0: the max width (resp height) of the tracks in the file are used\n" - " - if Y=-1: the layout is moved to the bottom of the track area\n" - " - X and Y can be omitted: `:layout=WxH`", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("rescale", NULL, "force media timescale to TS !! changes the media duration", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("timescale", NULL, "set imported media timescale to TS", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("moovts", NULL, "set movie timescale to TS. A negative value picks the media timescale of the first track imported", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("noedit", NULL, "`X` do not set edit list when importing B-frames video tracks", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("rvc", NULL, "set RVC configuration for the media", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("fmt", NULL, "override format detection with given format (cf BT/XMTA doc)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("profile", NULL, "override AVC profile", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("level", NULL, "override AVC level", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("tiles", NULL, "`S` add HEVC tiles signaling and NALU maps without splitting the tiles into different tile tracks", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("split_tiles", NULL, "`DS` split HEVC tiles into different tile tracks, one tile (or all tiles of one slice) per track", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("negctts", NULL, "`S` use negative CTS-DTS offsets (ISO4 brand). Use `negctts=no` to force using positive offset on existing track", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("chap", NULL, "`S` specify the track is a chapter track", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("chapter", NULL, "`S` add a single chapter (old nero format) with given name lasting the entire file", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("chapfile", NULL, "`S` add a chapter file (old nero format)", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("layout", NULL, "`S` specify the track layout as `WxH[xXxY][xLAYER]`. If `W` (resp `H`) is 0, the max width (resp height) of the tracks in the file are used", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("rescale", NULL, "`S` force media timescale to TS (int or fraction) and change the media duration", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("sampdur", NULL, "`S` force all samples duration (`D`) or sample durations and media timescale (`D/TS`), used to patch CFR files with broken timings", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("timescale", NULL, "`S` set imported media timescale to TS", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("moovts", NULL, "`S` set movie timescale to TS. A negative value picks the media timescale of the first track imported", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("noedit", NULL, "`XS` do not set edit list when importing B-frames video tracks", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("rvc", NULL, "`S` set RVC configuration for the media", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("fmt", NULL, "override format detection with given format - disable data probing and force `ext` option on source", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("profile", NULL, "`S` override AVC profile. Integer value, or `high444`, `high`, `extended`, `main`, `baseline`", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("level", NULL, "`S` override AVC level, if value < 6, interpreted as decimal expression", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("compat", NULL, "`S` force the profile compatibility flags for the H.264 content", NULL, NULL, GF_ARG_INT, 0), GF_DEF_ARG("novpsext", NULL, "remove VPS extensions from HEVC VPS", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("keepav1t", NULL, "keep AV1 temporal delimiter OBU in samples, might help if source file had losses", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("font", NULL, "specify font name for text import (default `Serif`)", NULL, NULL, GF_ARG_STRING, 0), @@ -497,44 +815,61 @@ static GF_GPACArg ImportFileOpts [] = { GF_DEF_ARG("swf-ic2d", NULL, "use indexed curve 2D hardcoded proto", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("swf-same-app", NULL, "appearance nodes are reused", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("swf-flatten", NULL, "complementary angle below which 2 lines are merged, `0` means no flattening", NULL, NULL, GF_ARG_DOUBLE, 0), - GF_DEF_ARG("kind", NULL, "set kind for the track as `schemeURI=value`", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("kind", NULL, "`S` set kind for the track as `schemeURI=value`", NULL, NULL, GF_ARG_STRING, 0), GF_DEF_ARG("txtflags", NULL, "set display flags (hexa number) of text track. Use `txtflags+=FLAGS` to add flags and `txtflags-=FLAGS` to remove flags", NULL, NULL, GF_ARG_INT, 0), GF_DEF_ARG("rate", NULL, "force average rate and max rate to VAL (in bps) in btrt box. If 0, removes btrt box", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("stz2", NULL, "use compact size table (for low-bitrates)", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("stz2", NULL, "`S` use compact size table (for low-bitrates)", NULL, NULL, GF_ARG_BOOL, 0), GF_DEF_ARG("bitdepth", NULL, "set bit depth to VAL for imported video content (default is 24)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("colr", NULL, "set color profile for imported video content (see ISO/IEC 23001-8). Value is formatted as:\n" - " - nclc,p,t,m: with p colour primary, t transfer characteristics and m matrix coef\n" - " - nclx,p,t,m,r: same as `nclx` with r full range flag\n" + GF_DEF_ARG("colr", NULL, "`S` set color profile for imported video content (see ISO/IEC 23001-8). Value is formatted as:\n" + " - nclc,p,t,m: with p colour primary (int or string), t transfer characteristics (int or string) and m matrix coef (int or string)\n" + " - nclx,p,t,m,r: same as `nclx` with r full range flag (`yes`, `on` or `no`, `off`)\n" " - prof,path: with path indicating the file containing the ICC color profile\n" - " - rICC,path: with path indicating the file containing the restricted ICC color profile", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("dv-profile", NULL, "set the Dolby Vision profile", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("tc", NULL, "inject a single QT timecode. Value is formated as:\n" + " - rICC,path: with path indicating the file containing the restricted ICC color profile\n" + " - 'none': removes color info", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("hdr", NULL, "`S` set HDR info on track (see [-hdr](MP4B_GEN) ), 'none' removes HDR info", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("dv-profile", NULL, "`S` set the Dolby Vision profile on imported track\n" + "- Profile is an integer, or `none` to remove DV signaling\n" + "- Profile can be suffixed with compatibility ID, e.g. `5.hdr10`\n" + "- Allowed compatibility ID are `none`, `hdr10`, `bt709`, `hlg709`, `hlg2100`, `bt2020`, `brd`, or integer value as per DV spec\n" + "- Profile can be prefixed with 'f' to force DV codec type signaling, e.g. `f8.2`", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("fullrange", NULL, "`S` force the video fullrange type in VUI for the AVC|H264 content (value `yes`, `on` or `no`, `off`)", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("videofmt", NULL, "`S` force the video format in VUI for AVC|H264 and HEVC content, value can be `component`, `pal`, `ntsc`, `secam`, `mac`, `undef`", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("colorprim", NULL, "`S` force the colour primaries in VUI for AVC|H264 and HEVC (int or string, cf `-h cicp`)", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("colortfc", NULL, "`S` force transfer characteristics in VUI for AVC|H264 and HEVC (int or string, cf `-h cicp`)", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("colormx", NULL, "`S` force the matrix coefficients in VUI for the AVC|H264 and HEVC content (int or string, cf `-h cicp`)", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("tc", NULL, "`S` inject a single QT timecode. Value is formatted as:\n" " - [d]FPS[/FPS_den],h,m,s,f[,framespertick]: optional drop flag, framerate (integer or fractional), hours, minutes, seconds and frame number\n" " - : `d` is an optional flag used to indicate that the counter is in drop-frame format\n" " - : the `framespertick` is optional and defaults to round(framerate); it indicates the number of frames per counter tick", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("lastsampdur", NULL, "set duration of the last sample. Value is formated as:\n" + GF_DEF_ARG("edits", NULL, "`S` override edit list, same syntax as [-edits]()", NULL, NULL, GF_ARG_STRING, 0), + GF_DEF_ARG("lastsampdur", NULL, "`S` set duration of the last sample. Value is formatted as:\n" " - no value: use the previous sample duration\n" " - integer: indicate the duration in milliseconds\n" " - N/D: indicate the duration as fractional second", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("fstat", NULL, "print filter session stats after import", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("fgraph", NULL, "print filter session graph after import", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("ID", NULL, "`S` set target ID\n" + " - a value of 0 (default) will try to keep source track ID\n" + " - a value of -1 will ignore source track ID\n" + " - other value will try to set track ID to this value if no other track with same ID is present" + "", NULL, NULL, GF_ARG_INT, 0), + GF_DEF_ARG("stats", "fstat", "`C` print filter session stats after import", NULL, NULL, GF_ARG_BOOL, 0), + GF_DEF_ARG("graph", "fgraph", "`C` print filter session graph after import", NULL, NULL, GF_ARG_BOOL, 0), {"sopt:[OPTS]", NULL, "set `OPTS` as additional arguments to source filter. `OPTS` can be any usual filter argument, see [filter doc `gpac -h doc`](Filters)"}, {"dopt:[OPTS]", NULL, "`X` set `OPTS` as additional arguments to [destination filter](mp4mx). OPTS can be any usual filter argument, see [filter doc `gpac -h doc`](Filters)"}, - {"@@f1[:args][@@fN:args]", NULL, "set a filter chain to insert before the muxer. Each filter in the chain is formatted as a regular filter, see [filter doc `gpac -h doc`](Filters). If several filters are set, they will be chained in the given order. The last filter shall not have any Filter ID specified"}, + {"@f1[:args][@fN:args]", NULL, "set a filter chain to insert before the multiplexer. Each filter in the chain is formatted as a regular filter, see [filter doc `gpac -h doc`](Filters). A `@@` separator starts a new chain (see DASH help). The last filter in each chain shall not have any ID specified"}, {0} }; void PrintImportUsage() { u32 i; - + gf_sys_format_help(helpout, help_flags, "# Importing Options\n" "# File importing\n" - "Syntax is [-add]() / [-cat]() `filename[#FRAGMENT][:opt1...:optN=val]`\n" + "Syntax is [-add]() / [-cat]() `URL[#FRAGMENT][:opt1...:optN=val]`\n" "This process will create the destination file if not existing, and add the track(s) to it. If you wish to always create a new destination file, add [-new](MP4B_GEN).\n" "The supported input media types depend on your installation, check [filters documentation](Filters) for more info.\n" " \n" - "To select a desired media track from a source, a fragment identifier '#' can be specified, bfore any other options. The following syntax is used:\n" + "To select a desired media track from a source, a fragment identifier '#' can be specified, before any other options. The following syntax is used:\n" "- `#video`: adds the first video track found in source\n" "- `#audio`: adds the first audio track found in source\n" "- `#auxv`: adds the first auxiliary video track found in source\n" @@ -546,52 +881,95 @@ void PrintImportUsage() " \n" "By default all imports are performed sequentially, and final interleaving is done at the end; this however requires a temporary file holding original ISOBMF file (if any) and added files before creating the final output. Since this can become quite large, it is possible to add media to a new file without temporary storage, using [-flat](MP4B_GEN) option, but this disables media interleaving.\n" " \n" - "If you wish to create an interleaved new file with no temporary storage, use the [-newfs](MP4B_GEN) option. The interleaving might not be as precise as when using [-new]() since it is dependent on muxer input scheduling (each execution might lead to a slightly different result). Additionally in this mode: \n" - " - Some muxing options (marked with `X` below) will be activated for all inputs (e.g it is not possible to import one AVC track with `xps_inband` and another without).\n" - " - Some muxing options (marked as `D` below) cannot be used as they require temporary storage for file edition.\n" - " - Usage of [-cat]() is possible, but concatenated sources will not be interleaved in the output. If you wish to perforom more complex cat/add operations without temp file, use the [gpac application](Filters).\n" + "If you wish to create an interleaved new file with no temporary storage, use the [-newfs](MP4B_GEN) option. The interleaving might not be as precise as when using [-new]() since it is dependent on multiplexer input scheduling (each execution might lead to a slightly different result). Additionally in this mode: \n" + " - Some multiplexing options (marked with `X` below) will be activated for all inputs (e.g. it is not possible to import one AVC track with `xps_inband` and another without).\n" + " - Some multiplexing options (marked as `D` below) cannot be used as they require temporary storage for file edition.\n" + " - Usage of [-cat]() is possible, but concatenated sources will not be interleaved in the output. If you wish to perform more complex cat/add operations without temp file, use a [playlist](flist).\n" + " \n" + "Source URL can be any URL supported by GPAC, not limited to local files.\n" + " \n" + "Note: When importing SRT or SUB files, MP4Box will choose default layout options to make the subtitle appear at the bottom of the video. You SHOULD NOT import such files before any video track is added to the destination file, otherwise the results will likely not be useful (default SRT/SUB importing uses default serif font, fontSize 18 and display size 400x60). For more details, check [TTXT doc](Subtitling-with-GPAC).\n" + " \n" + "When importing several tracks/sources in one pass, all options will be applied if relevant to each source. These options are set for all imported streams. If you need to specify these options per stream, set per-file options using the syntax `-add stream[:opt1:...:optN]`.\n" " \n" - "Note: MP4Box cannot start importing from a random point in the input, it always import from the begining. If you wish to import from another point in the source, use the [gpac application](Filters).\n" + "The import file name may be set to empty or `self`, indicating that the import options should be applied to the destination file track(s).\n" + "EX -add self:moovts=-1:noedit src.mp4\n" + "This will apply `moovts` and `noedit` option to all tracks in src.mp4\n" + "EX -add self#2:moovts=-1:noedit src.mp4\n" + "This will apply `moovts` and `noedit` option to track with `ID=2` in src.mp4\n" + "Only per-file options marked with a `S` are possible in this mode.\n" " \n" - "Note: When importing SRT or SUB files, MP4Box will choose default layout options to make the subtitle appear at the bottom of the video. You SHOULD NOT import such files before any video track is added to the destination file, otherwise the results will likelly not be useful (default SRT/SUB importing uses default serif font, fontSize 18 and display size 400x60). For more details, check [TTXT doc](Subtitling-with-GPAC).\n" + "When importing an ISOBMFF/QT file, only options marked as `C` or `S` can be used.\n" " \n" - "When importing several tracks/sources in one pass, all options will be applied if relevant to each source. These options are set for all imported streams. If you need to specify these options par stream, set per-file options using the syntax `-add stream[:opt1:...:optN]`. Allowed per-file options:\n\n" + "Allowed per-file options:\n\n" ); i=0; - while (ImportFileOpts[i].name) { - GF_GPACArg *arg = &ImportFileOpts[i]; + while (m4b_imp_fileopt_args[i].name) { + GF_GPACArg *arg = (GF_GPACArg *) &m4b_imp_fileopt_args[i]; i++; gf_sys_print_arg(helpout, help_flags | GF_PRINTARG_NO_DASH, arg, "mp4box-import"); } gf_sys_format_help(helpout, help_flags, "\n" - "Note: `sopt`, `dopt` and `@@f` must be placed after all other options.\n" + "Note: `sopt`, `dopt` and `@f` must be placed after all other options.\n" "# Global import options\n" ); i=0; while (m4b_imp_args[i].name) { - GF_GPACArg *arg = &m4b_imp_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_imp_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-import"); } } -GF_GPACArg m4b_senc_args[] = +Bool mp4box_check_isom_fileopt(char *opt) +{ + GF_GPACArg *arg = NULL; + u32 i=0; + + while (m4b_imp_fileopt_args[i].name) { + arg = (GF_GPACArg *) &m4b_imp_fileopt_args[i]; + i++; + if (!stricmp(arg->name, opt)) break; + arg = NULL; + } + if (!arg) { + fprintf(stderr, "Option %s not described in doc, please report to GPAC devs!\n", opt); + return GF_FALSE; + } + if (arg->description[0] != '`') + return GF_FALSE; + const char *d = arg->description+1; + while (d[0] != '`') { + if (d[0]=='S') return GF_TRUE; + if (d[0]=='C') return GF_TRUE; + d++; + } + return GF_FALSE; +} + + +MP4BoxArg m4b_senc_args[] = { - GF_DEF_ARG("mp4", NULL, "specify input file is for encoding", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("def", NULL, "encode DEF names in BIFS", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("sync", NULL, "force BIFS sync sample generation every given time in ms (cannot be used with [-shadow]() )", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("shadow", NULL, "force BIFS sync shadow sample generation every given time in ms (cannot be used with [-sync]() )", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("sclog", NULL, "generate scene codec log file if available", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ms", NULL, "import tracks from the given file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("ctx-in", NULL, "specify initial context (MP4/BT/XMT) file for chunk processing. Input file must be a commands-only file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("ctx-out", NULL, "specify storage of updated context (MP4/BT/XMT) file for chunk processing, optional", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("resolution", NULL, "resolution factor (-8 to 7, default 0) for LASeR encoding, and all coords are multiplied by `2^res` before truncation (LASeR encoding)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("coord-bits", NULL, "number of bits used for encoding truncated coordinates (0 to 31, default 12) (LASeR encoding)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("scale-bits", NULL, "extra bits used for encoding truncated scales (0 to 4, default 0) (LASeR encoding)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("auto-quant", NULL, "resolution is given as if using -resolution but coord-bits and scale-bits are infered (LASeR encoding)", NULL, NULL, GF_ARG_INT, 0), +#ifndef GPAC_DISABLE_SCENE_ENCODER + MP4BOX_ARG("mp4", "specify input file is for BIFS/LASeR encoding", GF_ARG_BOOL, 0, &encode, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("def", "encode DEF names in BIFS", GF_ARG_BOOL, 0, &smenc_opts.flags, GF_SM_ENCODE_USE_NAMES, ARG_BIT_MASK), + MP4BOX_ARG("sync", "force BIFS sync sample generation every given time in ms (cannot be used with [-shadow]() or [-carousel]() )", GF_ARG_INT, 0, parse_senc_param, 0, ARG_IS_FUN), + MP4BOX_ARG("shadow", "force BIFS sync shadow sample generation every given time in ms (cannot be used with [-sync]() or [-carousel]() )", GF_ARG_INT, 0, parse_senc_param, 1, ARG_IS_FUN), + MP4BOX_ARG("carousel", "use BIFS carousel (cannot be used with [-sync]() or [-shadow]() )", GF_ARG_INT, 0, parse_senc_param, 2, ARG_IS_FUN), + + MP4BOX_ARG("sclog", "generate scene codec log file if available", GF_ARG_BOOL, 0, &do_scene_log, 0, 0), + MP4BOX_ARG("ms", "import tracks from the given file", GF_ARG_STRING, 0, &mediaSource, 0, 0), + MP4BOX_ARG("ctx-in", "specify initial context (MP4/BT/XMT) file for chunk processing. Input file must be a commands-only file", GF_ARG_STRING, 0, parse_senc_param, 5, ARG_IS_FUN), + MP4BOX_ARG("ctx-out", "specify storage of updated context (MP4/BT/XMT) file for chunk processing, optional", GF_ARG_STRING, 0, &output_ctx, 0, 0), + MP4BOX_ARG("resolution", "resolution factor (-8 to 7, default 0) for LASeR encoding, and all coordinates are multiplied by `2^res` before truncation (LASeR encoding)", GF_ARG_INT, 0, &smenc_opts.resolution, 0, 0), + MP4BOX_ARG("coord-bits", "number of bits used for encoding truncated coordinates (0 to 31, default 12) (LASeR encoding)", GF_ARG_INT, 0, &smenc_opts.coord_bits, 0, 0), + MP4BOX_ARG("scale-bits", "extra bits used for encoding truncated scales (0 to 4, default 0) (LASeR encoding)", GF_ARG_INT, 0, &smenc_opts.scale_bits, 0, 0), + MP4BOX_ARG("auto-quant", "resolution is given as if using [-resolution]() but coord-bits and scale-bits are inferred (LASeR encoding)", GF_ARG_INT, 0, parse_senc_param, 3, ARG_IS_FUN), + MP4BOX_ARG("global-quant", "resolution is given as if using [-resolution]() but the res is inferred (BIFS encoding)", GF_ARG_INT, 0, parse_senc_param, 4, ARG_IS_FUN), +#endif {0} }; @@ -607,7 +985,7 @@ void PrintEncodeUsage() "## Scene Random Access\n" "MP4Box can encode BIFS or LASeR streams and insert random access points at a given frequency. This is useful when packaging content for broadcast, where users will not turn in the scene at the same time. In MPEG-4 terminology, this is called the __scene carousel__." "## BIFS Chunk Processing\n" - "The BIFS chunk encoding mode alows encoding single BIFS access units from an initial context and a set of commands.\n" + "The BIFS chunk encoding mode allows encoding single BIFS access units from an initial context and a set of commands.\n" "The generated AUs are raw BIFS (not SL-packetized), in files called FILE-ESID-AUIDX.bifs, with FILE the basename of the input file.\n" "Commands with a timing of 0 in the input will modify the carousel version only (i.e. output context).\n" "Commands with a timing different from 0 in the input will generate new AUs.\n" @@ -616,17 +994,17 @@ void PrintEncodeUsage() ); while (m4b_senc_args[i].name) { - GF_GPACArg *arg = &m4b_senc_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_senc_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-senc"); } } -GF_GPACArg m4b_crypt_args[] = +MP4BoxArg m4b_crypt_args[] = { - GF_DEF_ARG("crypt", NULL, "encrypt the input file using the given `CryptFile`", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("decrypt", NULL, "decrypt the input file, potentially using the given `CryptFile`. If `CryptFile` is not given, will fail if the key management system is not supported", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("set-kms", NULL, "change ISMA/OMA KMS location for all tracks, or for a given one if `ID=kms_uri` is used", NULL, NULL, GF_ARG_STRING, 0), + MP4BOX_ARG("crypt", "encrypt the input file using the given `CryptFile`", GF_ARG_STRING, 0, parse_cryp, 0, ARG_IS_FUN), + MP4BOX_ARG("decrypt", "decrypt the input file, potentially using the given `CryptFile`. If `CryptFile` is not given, will fail if the key management system is not supported", GF_ARG_STRING, 0, parse_cryp, 1, ARG_IS_FUN | ARG_EMPTY), + MP4BOX_ARG_S("set-kms", "tkID=kms_uri", "change ISMA/OMA KMS location for a given track or for all tracks if `all=` is used", 0, parse_track_action, TRACK_ACTION_SET_KMS_URI, ARG_IS_FUN), {0} }; @@ -636,36 +1014,39 @@ void PrintEncryptUsage() gf_sys_format_help(helpout, help_flags, "# Encryption/Decryption Options\n" "MP4Box supports encryption and decryption of ISMA, OMA and CENC content, see [encryption filter `gpac -h cecrypt`](cecrypt).\n" "It requires a specific XML file called `CryptFile`, whose syntax is available at https://wiki.gpac.io/Common-Encryption\n" + "Image files (HEIF) can also be crypted / decrypted, using CENC only.\n" " \n" "Options:\n" ); while (m4b_crypt_args[i].name) { - GF_GPACArg *arg = &m4b_crypt_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_crypt_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-crypt"); } } -GF_GPACArg m4b_hint_args[] = +MP4BoxArg m4b_hint_args[] = { - GF_DEF_ARG("hint", NULL, "hint the file for RTP/RTSP", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("mtu", NULL, "specify RTP MTU (max size) in bytes (this includes 12 bytes RTP header)", "1450", NULL, GF_ARG_INT, 0), - GF_DEF_ARG("copy", NULL, "copy media data to hint track rather than reference (speeds up server but takes much more space)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("multi `[maxptime]`", NULL, "enable frame concatenation in RTP packets if possible (with max duration 100 ms or `maxptime` ms if given)", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("rate", NULL, "specify rtp rate in Hz when no default for payload", "90000", NULL, GF_ARG_INT, 0), - GF_DEF_ARG("mpeg4", NULL, "force MPEG-4 generic payload whenever possible", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("latm", NULL, "force MPG4-LATM transport for AAC streams", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("static", NULL, "enable static RTP payload IDs whenever possible (by default, dynamic payloads are always used)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("add-sdp", NULL, "add given SDP string to hint track (`tkID:string`) or movie (`string`)", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("no-offset", NULL, "signal no random offset for sequence number and timestamp (support will depend on server)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("unhint", NULL, "remove all hinting information from file", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("group-single", NULL, "put all tracks in a single hint group", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ocr", NULL, "force all MPEG-4 streams to be synchronized (MPEG-4 Systems only)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("rap", NULL, "signal random access points in RTP packets (MPEG-4 Systems)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ts", NULL, "signal AU Time Stamps in RTP packets (MPEG-4 Systems)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("size", NULL, "signal AU size in RTP packets (MPEG-4 Systems)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("idx", NULL, "signal AU sequence numbers in RTP packets (MPEG-4 Systems)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("iod", NULL, "prevent systems tracks embedding in IOD (MPEG-4 Systems), not compatible with [-isma]()", NULL, NULL, GF_ARG_BOOL, 0), +#ifndef GPAC_DISABLE_STREAMING + MP4BOX_ARG("hint", "hint the file for RTP/RTSP", GF_ARG_BOOL, 0, &do_hint, 0, ARG_OPEN_EDIT), + {"mtu", NULL, "specify RTP MTU (max size) in bytes (this includes 12 bytes RTP header)", "1450", NULL, GF_ARG_INT, 0, &MTUSize, 0, 0}, + MP4BOX_ARG("copy", "copy media data to hint track rather than reference (speeds up server but takes much more space)", GF_ARG_BOOL, 0, &HintCopy, 0, 0), + MP4BOX_ARG_S("multi", "[maxptime]", "enable frame concatenation in RTP packets if possible (with max duration 100 ms or `maxptime` ms if given)", 0, parse_multi_rtp, 0, ARG_IS_FUN), + {"rate", NULL, "specify rtp rate in Hz when no default for payload", "90000", NULL, GF_ARG_INT, 0, &rtp_rate, 0, 0}, + MP4BOX_ARG("mpeg4", "force MPEG-4 generic payload whenever possible", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_FORCE_MPEG4, ARG_BIT_MASK), + MP4BOX_ARG("latm", "force MPG4-LATM transport for AAC streams", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_USE_LATM_AAC, ARG_BIT_MASK), + MP4BOX_ARG("static", "enable static RTP payload IDs whenever possible (by default, dynamic payloads are always used)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_USE_STATIC_ID, ARG_BIT_MASK), + MP4BOX_ARG("add-sdp", "add given SDP string to movie (`string`) or track (`tkID:string`), `tkID` being the track ID or the hint track ID", GF_ARG_STRING, 0, parse_sdp_ext, 0, ARG_IS_FUN), + MP4BOX_ARG("no-offset", "signal no random offset for sequence number and timestamp (support will depend on server)", GF_ARG_BOOL, 0, &hint_no_offset, 0, 0), + MP4BOX_ARG("unhint", "remove all hinting information from file", GF_ARG_BOOL, 0, &remove_hint, 0, ARG_OPEN_EDIT), + MP4BOX_ARG("group-single", "put all tracks in a single hint group", GF_ARG_BOOL, 0, &single_group, 0, 0), + MP4BOX_ARG("ocr", "force all MPEG-4 streams to be synchronized (MPEG-4 Systems only)", GF_ARG_BOOL, 0, &force_ocr, 0, 0), + MP4BOX_ARG("rap", "signal random access points in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, parse_rap_ref, 0, ARG_IS_FUN | ARG_EMPTY), + MP4BOX_ARG("ts", "signal AU Time Stamps in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_SIGNAL_TS, ARG_BIT_MASK), + MP4BOX_ARG("size", "signal AU size in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_SIGNAL_SIZE, ARG_BIT_MASK), + MP4BOX_ARG("idx", "signal AU sequence numbers in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_SIGNAL_AU_IDX, ARG_BIT_MASK), + MP4BOX_ARG("iod", "prevent systems tracks embedding in IOD (MPEG-4 Systems), not compatible with [-isma]()", GF_ARG_BOOL, 0, ®ular_iod, 0, 0), +#endif {0} }; @@ -681,29 +1062,29 @@ void PrintHintUsage() "Options:\n" ); while (m4b_hint_args[i].name) { - GF_GPACArg *arg = &m4b_hint_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_hint_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-hint"); } } -GF_GPACArg m4b_extr_args[] = +MP4BoxArg m4b_extr_args[] = { - GF_DEF_ARG("raw", NULL, "extract given track in raw format when supported. Use `tkID:output=FileName` to set output file name", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("raws", NULL, "extract each sample of the given track to a file. Use `tkID:N`to extract the Nth sample", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("nhnt", NULL, "extract given track to [NHNT](nhntr) format", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("nhml", NULL, "extract given track to [NHML](nhmlr) format. Use `tkID:full` for full NHML dump with all packet properties", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("webvtt-raw", NULL, "extract given track as raw media in WebVTT as metadata. Use `tkID:embedded` to include media data in the WebVTT file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("single", NULL, "extract given track to a new mp4 file", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("six", NULL, "extract given track as raw media in **experimental** XML streaming instructions", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("avi", NULL, "extract given track to an avi file", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("avi", NULL, "same as [-raw]() but defaults to QCP file for EVRC/SMV", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("aviraw", NULL, "extract AVI track in raw format; parameter can be `video`, `audio`or `audioN`", NULL, "video|audio", GF_ARG_STRING, 0), - GF_DEF_ARG("saf", NULL, "remux file to SAF multiplex", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dvbhdemux", NULL, "demux DVB-H file into IP Datagrams sent on the network", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("raw-layer", NULL, "same as [-raw]() but skips SVC/MVC/LHVC extractors when extracting", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("diod", NULL, "extract file IOD in raw format", NULL, NULL, GF_ARG_BOOL, 0), + MP4BOX_ARG("raw", "extract given track in raw format when supported. Use `tkID:output=FileName` to set output file name", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_NATIVE, ARG_IS_FUN), + MP4BOX_ARG("raws", "extract each sample of the given track to a file. Use `tkID:N` to extract the Nth sample", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_RAW_SAMPLES, ARG_IS_FUN), + MP4BOX_ARG("nhnt", "extract given track to [NHNT](nhntr) format", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_NHNT, ARG_IS_FUN), + MP4BOX_ARG("nhml", "extract given track to [NHML](nhmlr) format. Use `tkID:full` for full NHML dump with all packet properties", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_NHML, ARG_IS_FUN), + MP4BOX_ARG("webvtt-raw", "extract given track as raw media in WebVTT as metadata. Use `tkID:embedded` to include media data in the WebVTT file", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_WEBVTT_META, ARG_IS_FUN), + MP4BOX_ARG("single", "extract given track to a new mp4 file", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_MP4, ARG_IS_FUN), + MP4BOX_ARG("six", "extract given track as raw media in **experimental** XML streaming instructions", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_SIX, ARG_IS_FUN), + MP4BOX_ARG("mux", "multiplex input file to given destination", GF_ARG_STRING, 0, &mux_name, 0, 0), + MP4BOX_ARG("qcp", "same as [-raw]() but defaults to QCP file for EVRC/SMV", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP, ARG_IS_FUN), + MP4BOX_ARG("saf", "multiplex input file to SAF multiplex", GF_ARG_BOOL, 0, &do_saf, 0, 0), + MP4BOX_ARG("dvbhdemux", "demultiplex DVB-H file into IP Datagrams sent on the network", GF_ARG_BOOL, 0, &dvbhdemux, 0, 0), + MP4BOX_ARG("raw-layer", "same as [-raw]() but skips SVC/MVC/LHVC extractors when extracting", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER, ARG_IS_FUN), + MP4BOX_ARG("diod", "extract file IOD in raw format", GF_ARG_BOOL, 0, &dump_iod, 0, 0), + MP4BOX_ARG("mpd", "convert given HLS or smooth manifest (local or remote http) to MPD. \nWarning: This is not compatible with other DASH options and does not convert associated segments", GF_ARG_STRING, 0, &do_mpd_conv, 0, 0), {0} }; @@ -716,62 +1097,73 @@ void PrintExtractUsage() "Options:\n" ); while (m4b_extr_args[i].name) { - GF_GPACArg *arg = &m4b_extr_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_extr_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract"); } } -GF_GPACArg m4b_dump_args[] = +MP4BoxArg m4b_dump_args[] = { - GF_DEF_ARG("stdb", NULL, "dump/write to stdout and assume stdout is opened in binary mode", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("stdb", NULL, "dump/write to stdout and try to reopen stdout in binary mode", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("tracks", NULL, "print the number of tracks on stdout", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("info", NULL, "print movie info (no parameter) or track info with specified ID", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("infon", NULL, "print track info for given track number, 1 being the first track in the file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("diso", NULL, "dump IsoMedia file boxes in XML output", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dxml", NULL, "dump IsoMedia file boxes and known track samples in XML output", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("disox", NULL, "dump IsoMedia file boxes except sample tables in XML output", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("keep-ods", NULL, "do not translate ISOM ODs and ESDs tags (debug purpose only)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("bt", NULL, "dump scene to BT format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("xmt", NULL, "dump scene to XMT format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("wrl", NULL, "dump scene to VRML format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("x3d", NULL, "dump scene to X3D XML format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("x3dc", NULL, "dump scene to X3D VRML format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("lsr", NULL, "dump scene to LASeR XML (XSR) format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("drtp", NULL, "dump rtp hint samples structure to XML output", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dts", NULL, "print sample timing, size and position in file to text output", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dtsx", NULL, "same as [-dts]() but does not print offset", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dtsc", NULL, "same as [-dts]() but analyse each sample for duplicated dts/cts (__slow !__)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dtsxc", NULL, "same as [-dtsc]() but does not print offset (__slow !__)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dnal", NULL, "print NAL sample info of given track", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dnalc", NULL, "print NAL sample info of given track, adding CRC for each nal", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dnald", NULL, "print NAL sample info of given track without DTS and CTS info", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dnalx", NULL, "print NAL sample info of given track without DTS and CTS info and adding CRC for each nal", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("sdp", NULL, "dump SDP description of hinted file", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dsap", NULL, "dump DASH SAP cues (see -cues) for a given track", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dsaps", NULL, "same as [-dsap]() but only print sample number", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dsapc", NULL, "same as [-dsap]() but only print CTS", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dsapd", NULL, "same as [-dsap]() but only print DTS, `-dsapp` to only print presentation time", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dsapp", NULL, "same as [-dsap]() but only print presentation time", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("dcr", NULL, "dump ISMACryp samples structure to XML output", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dump-cover", NULL, "extract cover art", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dump-chap", NULL, "extract chapter file as TTXT format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dump-chap-ogg", NULL, "extract chapter file as OGG format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dump-chap-zoom", NULL, "extract chapter file as zoom format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("dump-udta `[tkID:]4cc`", NULL, "extract udta for the given 4CC. If `tkID` is given, dumps from UDTA of the given track ID, otherwise moov is used", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("mergevtt", NULL, "merge vtt cues while dumping", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("ttxt", NULL, "convert input subtitle to GPAC TTXT format if no parameter. Otherwise, dump given text track to GPAC TTXT format", NULL, NULL, GF_ARG_INT, 0), - GF_DEF_ARG("srt", NULL, "convert input subtitle to SRT format if no parameter. Otherwise, dump given text track to SRT format", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("rip-mpd", NULL, "download manifest and segments of an MPD. Does not work with live sessions", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("stat", NULL, "generate node/field statistics for scene", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("stats", NULL, "generate node/field statistics per Access Unit", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("statx", NULL, "generate node/field statistics for scene after each AU", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("hash", NULL, "generate SHA-1 Hash of the input file", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("comp", NULL, "replace with compressed version all top level box types given as parameter, formated as `orig_4cc_1=comp_4cc_1[,orig_4cc_2=comp_4cc_2]`", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("bin", NULL, "convert input XML file using NHML bitstream syntax to binary", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("topcount", NULL, "print to stdout the number of top-level boxes matching box types given as parameter, formated as `4cc_1,4cc_2N`", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("topsize", NULL, "print to stdout the number of bytes of top-level boxes matching types given as parameter, formated as `4cc_1,4cc_2N` or `all` for all boxes", NULL, NULL, GF_ARG_STRING, 0), + MP4BOX_ARG("std", "dump/write to stdout and assume stdout is opened in binary mode", GF_ARG_BOOL, 0, &dump_std, 2, 0), + MP4BOX_ARG("stdb", "dump/write to stdout and try to reopen stdout in binary mode", GF_ARG_BOOL, 0, &dump_std, 1, 0), + MP4BOX_ARG("tracks", "print the number of tracks on stdout", GF_ARG_BOOL, 0, &get_nb_tracks, 0, 0), + MP4BOX_ARG("info", "print movie info (no parameter) or track extended info with specified ID", GF_ARG_STRING, 0, parse_file_info, 0, ARG_IS_FUN|ARG_EMPTY), + MP4BOX_ARG("infon", "print track info for given track number, 1 being the first track in the file", GF_ARG_STRING, 0, parse_file_info, 1, ARG_IS_FUN|ARG_EMPTY), + MP4BOX_ARG("infox", "print movie and track extended info (same as -info N` for each track)", GF_ARG_BOOL, 0, parse_file_info, 2, ARG_IS_FUN|ARG_EMPTY), + MP4BOX_ARG_ALT("diso", "dmp4", "dump IsoMedia file boxes in XML output", GF_ARG_BOOL, 0, &dump_isom, 1, 0), + MP4BOX_ARG("dxml", "dump IsoMedia file boxes and known track samples in XML output", GF_ARG_BOOL, 0, &dump_isom, 2, 0), + MP4BOX_ARG("disox", "dump IsoMedia file boxes except sample tables in XML output", GF_ARG_BOOL, 0, &dump_isom, 3, 0), + MP4BOX_ARG("keep-ods", "do not translate ISOM ODs and ESDs tags (debug purpose only)", GF_ARG_BOOL, 0, &no_odf_conf, 0, 0), +#ifndef GPAC_DISABLE_SCENE_DUMP + MP4BOX_ARG("bt", "dump scene to BT format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_BT, ARG_HAS_VALUE), + MP4BOX_ARG("xmt", "dump scene to XMT format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_XMTA, 0), + MP4BOX_ARG("wrl", "dump scene to VRML format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_VRML, 0), + MP4BOX_ARG("x3d", "dump scene to X3D XML format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_X3D_XML, 0), + MP4BOX_ARG("x3dv", "dump scene to X3D VRML format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_X3D_VRML, 0), + MP4BOX_ARG("lsr", "dump scene to LASeR XML (XSR) format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_LASER, 0), + MP4BOX_ARG("svg", "dump scene to SVG", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_SVG, 0), +#endif + MP4BOX_ARG("drtp", "dump rtp hint samples structure to XML output", GF_ARG_BOOL, 0, &dump_rtp, 0, 0), + MP4BOX_ARG("dts", "print sample timing, size and position in file to text output", GF_ARG_BOOL, 0, parse_dump_ts, 0, ARG_IS_FUN), + MP4BOX_ARG("dtsx", "same as [-dts]() but does not print offset", GF_ARG_BOOL, 0, &dump_timestamps, 2, 0), + MP4BOX_ARG("dtsc", "same as [-dts]() but analyses each sample for duplicated dts/cts (__slow !__)", GF_ARG_BOOL, 0, &dump_timestamps, 3, 0), + MP4BOX_ARG("dtsxc", "same as [-dtsc]() but does not print offset (__slow !__)", GF_ARG_BOOL, 0, &dump_timestamps, 4, 0), + MP4BOX_ARG("dnal", "print NAL sample info of given track", GF_ARG_INT, 0, parse_dnal, 0, ARG_IS_FUN), + MP4BOX_ARG("dnalc", "print NAL sample info of given track, adding CRC for each nal", GF_ARG_INT, 0, parse_dnal, 1, ARG_IS_FUN), + MP4BOX_ARG("dnald", "print NAL sample info of given track without DTS and CTS info", GF_ARG_INT, 0, parse_dnal, 2, ARG_IS_FUN), + MP4BOX_ARG("dnalx", "print NAL sample info of given track without DTS and CTS info and adding CRC for each nal", GF_ARG_INT, 0, parse_dnal, 2|1, ARG_IS_FUN), + MP4BOX_ARG("sdp", "dump SDP description of hinted file", GF_ARG_BOOL, 0, &print_sdp, 0, 0), + MP4BOX_ARG("dsap", "dump DASH SAP cues (see -cues) for a given track", GF_ARG_INT, 0, parse_dsap, 0, ARG_IS_FUN), + MP4BOX_ARG("dsaps", "same as [-dsap]() but only print sample number", GF_ARG_INT, 0, parse_dsap, 1, ARG_IS_FUN), + MP4BOX_ARG("dsapc", "same as [-dsap]() but only print CTS", GF_ARG_INT, 0, parse_dsap, 2, ARG_IS_FUN), + MP4BOX_ARG("dsapd", "same as [-dsap]() but only print DTS", GF_ARG_INT, 0, parse_dsap, 3, ARG_IS_FUN), + MP4BOX_ARG("dsapp", "same as [-dsap]() but only print presentation time", GF_ARG_INT, 4, parse_dsap, 4, ARG_IS_FUN), + MP4BOX_ARG("dcr", "dump ISMACryp samples structure to XML output", GF_ARG_BOOL, 0, &dump_cr, 0, 0), + MP4BOX_ARG("dchunk", "dump chunk info", GF_ARG_BOOL, 0, &dump_chunk, 0, 0), + MP4BOX_ARG("dump-cover", "extract cover art", GF_ARG_BOOL, 0, &dump_cart, 0, 0), + MP4BOX_ARG("dump-chap", "extract chapter file as TTXT format", GF_ARG_BOOL, 0, &dump_chap, 1, 0), + MP4BOX_ARG("dump-chap-ogg", "extract chapter file as OGG format", GF_ARG_BOOL, 0, &dump_chap, 2, 0), + MP4BOX_ARG("dump-chap-zoom", "extract chapter file as zoom format", GF_ARG_BOOL, 0, &dump_chap, 3, 0), + MP4BOX_ARG_S("dump-udta", "[tkID:]4cc", "extract user data for the given 4CC. If `tkID` is given, dumps from UDTA of the given track ID, otherwise moov is used", 0, parse_dump_udta, 0, ARG_IS_FUN), + MP4BOX_ARG("mergevtt", "merge vtt cues while dumping", GF_ARG_BOOL, 0, &merge_vtt_cues, 0, 0), + MP4BOX_ARG("ttxt", "convert input subtitle to GPAC TTXT format if no parameter. Otherwise, dump given text track to GPAC TTXT format", GF_ARG_INT, 0, parse_ttxt, 0, ARG_IS_FUN), + MP4BOX_ARG("srt", "convert input subtitle to SRT format if no parameter. Otherwise, dump given text track to SRT format", GF_ARG_INT, 0, parse_ttxt, 1, ARG_IS_FUN), + MP4BOX_ARG("nstat", "generate node/field statistics for scene", GF_ARG_BOOL, 0, &stat_level, 1, 0), + MP4BOX_ARG("nstats", "generate node/field statistics per Access Unit", GF_ARG_BOOL, 0, &stat_level, 2, 0), + MP4BOX_ARG("nstatx", "generate node/field statistics for scene after each AU", GF_ARG_BOOL, 0, &stat_level, 3, 0), + MP4BOX_ARG("hash", "generate SHA-1 Hash of the input file", GF_ARG_BOOL, 0, &do_hash, 0, 0), + MP4BOX_ARG("comp", "replace with compressed version all top level box types given as parameter, formatted as `orig_4cc_1=comp_4cc_1[,orig_4cc_2=comp_4cc_2]`", GF_ARG_STRING, 0, parse_comp_box, 0, ARG_IS_FUN), + MP4BOX_ARG("topcount", "print to stdout the number of top-level boxes matching box types given as parameter, formatted as `4cc_1,4cc_2N`", GF_ARG_STRING, 0, parse_comp_box, 2, ARG_IS_FUN), + MP4BOX_ARG("topsize", "print to stdout the number of bytes of top-level boxes matching types given as parameter, formatted as `4cc_1,4cc_2N` or `all` for all boxes", GF_ARG_STRING, 0, parse_comp_box, 1, ARG_IS_FUN), + MP4BOX_ARG("bin", "convert input XML file using NHML bitstream syntax to binary", GF_ARG_BOOL, 0, &do_bin_xml, 0, 0), + MP4BOX_ARG("mpd-rip", "fetch MPD and segment to disk", GF_ARG_BOOL, 0, &do_mpd_rip, 0, 0), + //MP4BOX_ARG_S("udp-write", "IP[:port]", "write input name to UDP (default port 2345)", GF_FS_ARG_HINT_EXPERT, &udp_dest, 0, GF_ARG_STRING), + {"udp-write", NULL, "write input name to UDP (default port 2345)", "IP[:port]", NULL, GF_ARG_STRING, GF_FS_ARG_HINT_EXPERT, &udp_dest, 0, 0}, + MP4BOX_ARG("raw-cat", "raw concatenation of given file with input file", GF_ARG_STRING, GF_FS_ARG_HINT_EXPERT, &raw_cat, 0, 0), + MP4BOX_ARG("wget", "fetch resource from http(s) URL", GF_ARG_STRING, GF_FS_ARG_HINT_EXPERT, &do_wget, 0, 0), + MP4BOX_ARG("dm2ts", "dump timing of an input MPEG-2 TS stream sample timing", GF_ARG_BOOL, 0, &dump_m2ts, 0, 0), + MP4BOX_ARG("check-xml", "check XML output format for -dnal*, -diso* and -dxml options", GF_ARG_BOOL, 0, &dump_check_xml, 0, 0), {0} }; @@ -785,47 +1177,73 @@ void PrintDumpUsage() "Options:\n" ); while (m4b_dump_args[i].name) { - GF_GPACArg *arg = &m4b_dump_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_dump_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract"); } } -GF_GPACArg m4b_meta_args[] = +MP4BoxArg m4b_meta_args[] = { - GF_DEF_ARG("set-meta `ABCD[:tk=tkID]`", NULL, "set meta box type, with `ABCD` the four char meta type (NULL or 0 to remove meta)\n" + MP4BOX_ARG_S("set-meta", "ABCD[:tk=tkID]", "set meta box type, with `ABCD` the four char meta type (NULL or 0 to remove meta)\n" "- tk not set: use root (file) meta\n" "- tkID == 0: use moov meta\n" - "- tkID != 0: use meta of given track", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("add-items", NULL, "add resource to meta, with parameter syntax `file_path[:opt1:optN]`\n" + "- tkID != 0: use meta of given track", 0, parse_meta_args, META_ACTION_SET_TYPE, ARG_IS_FUN), + MP4BOX_ARG("add-item", "add resource to meta, with parameter syntax `file_path[:opt1:optN]`\n" "- file_path `this` or `self`: item is the file itself\n" "- tk=tkID: meta location (file, moov, track)\n" - "- name=str: item name\n" + "- name=str: item name, none if not set\n" "- type=itype: item 4cc type (not needed if mime is provided)\n" - "- mime=mtype: item mime type\n" - "- encoding=enctype: item content-encoding type\n" + "- mime=mtype: item mime type, none if not set\n" + "- encoding=enctype: item content-encoding type, none if not set\n" "- id=ID: item ID\n" - "- ref=4cc,id: reference of type 4cc to an other item", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("add-image", NULL, "add the given file (with parameters) as HEIF image item. Same syntax as [-add-item]()\n" - "- name=str: see [-add-item]()\n" - "- id=id: see [-add-item]()\n" - "- ref=4cc, id: see [-add-item]()\n" + "- ref=4cc,id: reference of type 4cc to an other item (can be set multiple times)\n" + "- group=id,type: indicate the id and type of an alternate group for this item\n" + "- replace: replace existing item by new item" + , GF_ARG_STRING, 0, parse_meta_args, META_ACTION_ADD_ITEM, ARG_IS_FUN), + MP4BOX_ARG("add-image", "add the given file as HEIF image item, with parameter syntax `file_path[:opt1:optN]`. If `filepath` is omitted, source is the input MP4 file\n" + "- name, id, ref: see [-add-item]()\n" "- primary: indicate that this item should be the primary item\n" - "- time=t: use the next sync sample after time t (float, in sec, default 0). A negative time imports ALL frames as items\n" + "- time=t[-e][/i]: use the next sync sample after time t (float, in sec, default 0). A negative time imports ALL intra frames as items\n" + " - If `e` is set (float, in sec), import all sync samples between `t` and `e`\n" + " - If `i` is set (float, in sec), sets time increment between samples to import\n" "- split_tiles: for an HEVC tiled image, each tile is stored as a separate item\n" + "- image-size=wxh: force setting the image size and ignoring the bitstream info, used for grid, overlay and identity derived images also\n" "- rotation=a: set the rotation angle for this image to 90*a degrees anti-clockwise\n" + "- mirror-axis=axis: set the mirror axis: vertical, horizontal\n" + "- clap=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd: see track clap\n" + "- image-pasp=axb: force the aspect ratio of the image\n" + "- image-pixi=(a|a,b,c): force the bit depth (1 or 3 channels)\n" "- hidden: indicate that this image item should be hidden\n" - "- icc_path: path to icc to add as colr\n" + "- icc_path: path to icc data to add as color info\n" "- alpha: indicate that the image is an alpha image (should use ref=auxl also)\n" - "- any other option will be passed as options to the media importer, see [-add]()", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("rem-item `item_ID[:tk=tkID]`", NULL, "remove resource from meta", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("set-primary `item_ID[:tk=tkID]`", NULL, "set item as primary for meta", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("set-xml `xml_file_path[:tk=tkID][:binary]`", NULL, "set meta XML data", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("rem-xml `[tk=tkID]`", NULL, "remove meta XML data", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("dump-xml `file_path[:tk=tkID]`", NULL, "dump meta XML to file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("dump-item `item_ID[:tk=tkID][:path=fileName]`", NULL, "dump item to file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("package", NULL, "package input XML file into an ISO container, all media referenced except hyperlinks are added to file", NULL, NULL, GF_ARG_STRING, 0), - GF_DEF_ARG("package", NULL, "package input XML file into an MPEG-U widget with ISO container, all files contained in the current folder are added to the widget package", NULL, NULL, GF_ARG_STRING, 0), + "- depth: indicate that the image is a depth image (should use ref=auxl also)\n" + "- it=ID: indicate the item ID of the source item to import\n" + "- itp=ID: same as `it=` but copy over all properties of the source item\n" + "- tk=tkID: indicate the track ID of the source sample. If 0, uses the first video track in the file\n" + "- samp=N: indicate the sample number of the source sample\n" + "- ref: do not copy the data but refer to the final sample/item location, ignored if `filepath` is set\n" + "- agrid[=AR]: creates an automatic grid from the image items present in the file, in their declaration order. The grid will **try to** have `AR` aspect ratio if specified (float), or the aspect ratio of the source otherwise. The grid will be the primary item and all other images will be hidden\n" + "- av1_op_index: select the AV1 operating point to use via a1op box\n" + "- replace: replace existing image by new image, keeping props listed in `keep_props`\n" + "- keep_props=4CCs: coma-separated list of properties types to keep when replacing the image, e.g. `keep_props=auxC`\n" + "- auxt=URN: mark image as auxiliary using given `URN`\n" + "- auxd=FILE: use data from `FILE` as auxiliary extensions (cf `auxC` box)\n" + "- any other options will be passed as options to the media importer, see [-add]()" + , GF_ARG_STRING, 0, parse_meta_args, META_ACTION_ADD_IMAGE_ITEM, ARG_IS_FUN), + MP4BOX_ARG("add-derived-image", "create an image grid, overlay or identity item, with parameter syntax `:type=(grid|iovl|iden)[:opt1:optN]`\n" + "- image-grid-size=rxc: set the number of rows and columns of the grid\n" + "- image-overlay-offsets=h,v[,h,v]*: set the horizontal and vertical offsets of the images in the overlay\n" + "- image-overlay-color=r,g,b,a: set the canvas color of the overlay [0-65535]\n" + "- any other options from [-add-image]() can be used\n", GF_ARG_STRING, 0, parse_meta_args, META_ACTION_ADD_IMAGE_DERIVED, ARG_IS_FUN), + MP4BOX_ARG_S_ALT("rem-item", "rem-image", "item_ID[:tk=tkID]", "remove resource from meta", 0, parse_meta_args, META_ACTION_REM_ITEM, ARG_IS_FUN), + MP4BOX_ARG_S("set-primary", "item_ID[:tk=tkID]", "set item as primary for meta", 0, parse_meta_args, META_ACTION_SET_PRIMARY_ITEM, ARG_IS_FUN), + MP4BOX_ARG_S("set-xml", "xml_file_path[:tk=tkID][:binary]", "set meta XML data", 0, parse_meta_args, META_ACTION_SET_XML, ARG_IS_FUN), + MP4BOX_ARG_S("rem-xml", "[tk=tkID]", "remove meta XML data", 0, parse_meta_args, META_ACTION_REM_XML, ARG_IS_FUN), + MP4BOX_ARG_S("dump-xml", "file_path[:tk=tkID]", "dump meta XML to file", 0, parse_meta_args, META_ACTION_DUMP_XML, ARG_IS_FUN), + MP4BOX_ARG_S("dump-item", "item_ID[:tk=tkID][:path=fileName]", "dump item to file", 0, parse_meta_args, META_ACTION_DUMP_ITEM, ARG_IS_FUN), + MP4BOX_ARG("package", "package input XML file into an ISO container, all media referenced except hyperlinks are added to file", GF_ARG_STRING, 0, &pack_file, 0, 0), + MP4BOX_ARG("mgt", "package input XML file into an MPEG-U widget with ISO container, all files contained in the current folder are added to the widget package", GF_ARG_STRING, 0, parse_mpegu, 0, ARG_IS_FUN), {0} }; @@ -835,26 +1253,30 @@ void PrintMetaUsage() gf_sys_format_help(helpout, help_flags, "# Meta and HEIF Options\n" "IsoMedia files can be used as generic meta-data containers, for examples storing XML information and sample images for a movie. The resulting file may not always contain a movie as is the case with some HEIF files or MPEG-21 files.\n" " \n" - "These information can be stored at the file root level, as is the case for HEIF/IFF and MPEG-21 file formats, or at the moovie or track level for a regular movie." + "These information can be stored at the file root level, as is the case for HEIF/IFF and MPEG-21 file formats, or at the movie or track level for a regular movie." " \n \n"); while (m4b_meta_args[i].name) { - GF_GPACArg *arg = &m4b_meta_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_meta_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract"); } } -GF_GPACArg m4b_swf_args[] = +MP4BoxArg m4b_swf_args[] = { - GF_DEF_ARG("global", NULL, "all SWF defines are placed in first scene replace rather than when needed", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-ctrl", NULL, "use a single stream for movie control and dictionary (this will disable ActionScript)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-text", NULL, "remove all SWF text", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-font", NULL, "remove all embedded SWF Fonts (local playback host fonts used)", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-line", NULL, "remove all lines from SWF shapes", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("no-grad", NULL, "remove all gradients from swf shapes", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("quad", NULL, "use quadratic bezier curves instead of cubic ones", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("xlp", NULL, "support for lines transparency and scalability", NULL, NULL, GF_ARG_BOOL, 0), - GF_DEF_ARG("flatten", NULL, "complementary angle below which 2 lines are merged, value `0`means no flattening", NULL, NULL, GF_ARG_DOUBLE, 0), +#ifndef GPAC_DISABLE_SCENE_ENCODER + MP4BOX_ARG("global", "all SWF defines are placed in first scene replace rather than when needed", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_STATIC_DICT, ARG_BIT_MASK), + MP4BOX_ARG("no-ctrl", "use a single stream for movie control and dictionary (this will disable ActionScript)", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_SPLIT_TIMELINE, ARG_BIT_MASK_REM), + MP4BOX_ARG("no-text", "remove all SWF text", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_TEXT, ARG_BIT_MASK), + MP4BOX_ARG("no-font", "remove all embedded SWF Fonts (local playback host fonts used)", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_FONT, ARG_BIT_MASK), + MP4BOX_ARG("no-line", "remove all lines from SWF shapes", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_LINE, ARG_BIT_MASK), + MP4BOX_ARG("no-grad", "remove all gradients from swf shapes", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_GRADIENT, ARG_BIT_MASK), + MP4BOX_ARG("quad", "use quadratic bezier curves instead of cubic ones", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_QUAD_CURVE, ARG_BIT_MASK), + MP4BOX_ARG("xlp", "support for lines transparency and scalability", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_SCALABLE_LINE, ARG_BIT_MASK), + MP4BOX_ARG("ic2d", "use indexed curve 2D hardcoded proto", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_USE_IC2D, ARG_BIT_MASK), + MP4BOX_ARG("same-app", "appearance nodes are reused", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_REUSE_APPEARANCE, ARG_BIT_MASK), + MP4BOX_ARG("flatten", "complementary angle below which 2 lines are merged, value `0` means no flattening", GF_ARG_DOUBLE, 0, &swf_flatten_angle, 0, 0), +#endif {0} }; @@ -869,14 +1291,15 @@ void PrintSWFUsage() "Options:\n" ); while (m4b_swf_args[i].name) { - GF_GPACArg *arg = &m4b_swf_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_swf_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract"); } } -GF_GPACArg m4b_liveenc_args[] = +MP4BoxArg m4b_liveenc_args[] = { + MP4BOX_ARG("live", "enable live BIFS/LASeR encoder", GF_ARG_BOOL, 0, &live_scene, 0, 0), GF_DEF_ARG("dst", NULL, "destination IP", NULL, NULL, GF_ARG_STRING, 0), GF_DEF_ARG("port", NULL, "destination port", "7000", NULL, GF_ARG_INT, 0), GF_DEF_ARG("mtu", NULL, "path MTU for RTP packets", "1450", NULL, GF_ARG_INT, 0), @@ -894,12 +1317,12 @@ void PrintLiveUsage() { u32 i=0; gf_sys_format_help(helpout, help_flags, "# Live Scene Encoder Options\n" - "The options shall be specified as òpt_name=opt_val.\n" + "The options shall be specified as `opt_name=opt_val.\n" "Options:\n" "\n" ); while (m4b_liveenc_args[i].name) { - GF_GPACArg *arg = &m4b_liveenc_args[i]; + GF_GPACArg *arg = (GF_GPACArg *) &m4b_liveenc_args[i]; i++; gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract"); } @@ -923,15 +1346,95 @@ void PrintCoreUsage() gf_sys_print_core_help(helpout, 0, GF_ARGMODE_ALL, 0); } -GF_GPACArg m4b_usage_args[] = +void PrintTags() +{ + u32 i = 0; + + gf_sys_format_help(helpout, help_flags, "# Tagging support\n" + "Tags are specified as a colon-separated list `tag_name=tag_value[:tag2=val2]`\n" + "Setting a tag with no value or value `NULL` removes the tag.\n" + "Special tag value `clear` (or `reset`) removes all tags.\n" + "Unsupported tags can be added using their four character code as a tag name, and string value will be assumed.\n" + "If the tag name length is 3, the prefix 0xA9 is used to create the four character code.\n" + " \n" + "Tags can also be loaded from a text file using `-itags filename`. The file must be in UTF8 with:\n" + "- lines starting with `tag_name=value` specify the start of a tag\n" + "- other lines specify the remainder of the last declared tag\n" + " \n" + "If tag name starts with `WM/`, the tag is added to `Xtra` box (WMA tag, string only).\n" + " \n" + "Supported tag names, values, types, aliases:\n" + ); + + while (1) { + s32 type = gf_itags_get_type(i); + if (type<0) break; + const char *name = gf_itags_get_name(i); + u32 itag = gf_itags_get_itag(i); + gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST , "%s", name); + gf_sys_format_help(helpout, help_flags, " (%s) ", gf_4cc_to_str(itag) ); + switch (type) { + case GF_ITAG_STR: + gf_sys_format_help(helpout, help_flags, "string"); break; + case GF_ITAG_INT8: + case GF_ITAG_INT16: + case GF_ITAG_INT32: + case GF_ITAG_INT64: + gf_sys_format_help(helpout, help_flags, "integer"); break; + case GF_ITAG_FRAC6: + case GF_ITAG_FRAC8: + gf_sys_format_help(helpout, help_flags, "fraction (syntax: `A/B` or `A`, B will be 0)"); break; + case GF_ITAG_BOOL: + gf_sys_format_help(helpout, help_flags, "bool (`yes` or `no`)"); break; + case GF_ITAG_ID3_GENRE: + gf_sys_format_help(helpout, help_flags, "string (ID3 genre tag)"); break; + case GF_ITAG_FILE: + gf_sys_format_help(helpout, help_flags, "file path"); break; + } + name = gf_itags_get_alt_name(i); + if (name) { + gf_sys_format_help(helpout, help_flags, " (`alias` %s)", name); + } + + gf_sys_format_help(helpout, help_flags, "\n"); + i++; + } +} + +void PrintCICP() { - GF_DEF_ARG("h", NULL, "print help\n" + u32 i; + gf_sys_format_help(helpout, help_flags, "# Video CICP (ISO/IEC 23091-2) Constants\n"); + gf_sys_format_help(helpout, help_flags, "CICP Color Primaries:\n"); + for (i=0; iname, alen) && ((arg->name[alen]==0) || (arg->name[alen]=='='))) do_match = GF_TRUE; @@ -1029,17 +1541,23 @@ static u32 PrintHelpForArgs(char *arg_name, GF_GPACArg *args, u32 search_type) i++; continue; } - if ((search_type==SEARCH_DESC) && !strstr_nocase(arg->description, arg_name, alen)) { + if ((search_type==SEARCH_DESC) && strcmp(arg->name, arg_name) && !gf_strnistr(arg->description, arg_name, alen)) { i++; continue; } an_arg = *arg; if (search_type!=SEARCH_ARG_EXACT) { - an_arg.description = NULL; + if (search_type == SEARCH_DESC) + an_arg.description = szDesc; + else + an_arg.description = NULL; an_arg.type = GF_ARG_BOOL; + gf_sys_print_arg(helpout, flags, (GF_GPACArg *) &an_arg, ""); + + } else { + gf_sys_print_arg(helpout, flags, (GF_GPACArg *) &an_arg, ""); } - gf_sys_print_arg(helpout, flags, &an_arg, ""); res++; i++; } @@ -1047,25 +1565,27 @@ static u32 PrintHelpForArgs(char *arg_name, GF_GPACArg *args, u32 search_type) } static Bool PrintHelpArg(char *arg_name, u32 search_type, GF_FilterSession *fs) { + char szDesc[100]; Bool first=GF_TRUE; GF_GPACArg an_arg; u32 i, count; u32 res = 0; u32 alen = (u32) strlen(arg_name); - res += PrintHelpForArgs(arg_name, m4b_gen_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_dash_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_imp_args, search_type); - res += PrintHelpForArgs(arg_name, ImportFileOpts, search_type); - res += PrintHelpForArgs(arg_name, m4b_senc_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_crypt_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_hint_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_extr_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_dump_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_meta_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_swf_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_liveenc_args, search_type); - res += PrintHelpForArgs(arg_name, m4b_usage_args, search_type); - res += PrintHelpForArgs(arg_name, (GF_GPACArg *) gf_sys_get_options(), search_type); + res += PrintHelpForArgs(arg_name, m4b_gen_args, NULL, search_type, "general"); + res += PrintHelpForArgs(arg_name, m4b_split_args, NULL, search_type, "split"); + res += PrintHelpForArgs(arg_name, m4b_dash_args, NULL, search_type, "dash"); + res += PrintHelpForArgs(arg_name, m4b_imp_args, NULL, search_type, "import"); + res += PrintHelpForArgs(arg_name, m4b_imp_fileopt_args, NULL, search_type, "import (per-file option)"); + res += PrintHelpForArgs(arg_name, m4b_senc_args, NULL, search_type, "encode"); + res += PrintHelpForArgs(arg_name, m4b_crypt_args, NULL, search_type, "crypt"); + res += PrintHelpForArgs(arg_name, m4b_hint_args, NULL, search_type, "hint"); + res += PrintHelpForArgs(arg_name, m4b_extr_args, NULL, search_type, "extract"); + res += PrintHelpForArgs(arg_name, m4b_dump_args, NULL, search_type, "dump"); + res += PrintHelpForArgs(arg_name, m4b_meta_args, NULL, search_type, "meta"); + res += PrintHelpForArgs(arg_name, m4b_swf_args, NULL, search_type, "swf"); + res += PrintHelpForArgs(arg_name, m4b_liveenc_args, NULL, search_type, "live"); + res += PrintHelpForArgs(arg_name, m4b_usage_args, NULL, search_type, ""); + res += PrintHelpForArgs(arg_name, NULL, (GF_GPACArg *) gf_sys_get_options(), search_type, "core"); if (!fs) return res; @@ -1085,7 +1605,7 @@ static Bool PrintHelpArg(char *arg_name, u32 search_type, GF_FilterSession *fs) if ((search_type==SEARCH_ARG_CLOSE) && !gf_sys_word_match(arg->arg_name, arg_name)) continue; if (search_type==SEARCH_DESC) { - if (!strstr_nocase(arg->arg_desc, arg_name, alen)) continue; + if (stricmp(arg->arg_name, arg_name) && !gf_strnistr(arg->arg_desc, arg_name, alen)) continue; } an_arg.name = arg->arg_name; @@ -1104,15 +1624,24 @@ static Bool PrintHelpArg(char *arg_name, u32 search_type, GF_FilterSession *fs) break; case GF_PROP_STRING_LIST: case GF_PROP_UINT_LIST: + case GF_PROP_SINT_LIST: + case GF_PROP_VEC2I_LIST: an_arg.type = GF_ARG_STRINGS; break; + case GF_PROP_4CC: + an_arg.type = GF_ARG_4CC; + break; + case GF_PROP_4CC_LIST: + an_arg.type = GF_ARG_4CCS; + break; default: an_arg.type = GF_ARG_STRING; break; } if (first) { first = GF_FALSE; - gf_sys_format_help(helpout, 0, "\nGlobal filter session arguments. Syntax is `--arg` or `--arg=VAL`. `[F]` indicates filter name. See `gpac -h` and `gpac -h F` for more info.\n"); + gf_sys_format_help(helpout, 0, "\nGlobal filter session arguments matching %s:\n", arg_name); + //. Syntax is `--arg` or `--arg=VAL`. `[F]` indicates filter name. See `gpac -h` and `gpac -h F` for more info.\n"); } fprintf(helpout, "[%s]", reg->name); len = (u32)strlen(reg->name); @@ -1121,6 +1650,9 @@ static Bool PrintHelpArg(char *arg_name, u32 search_type, GF_FilterSession *fs) fprintf(helpout, " "); } fprintf(helpout, " "); + } else if (search_type==SEARCH_DESC) { + sprintf(szDesc, "see filter %s", reg->name); + an_arg.description = szDesc; } gf_sys_print_arg(helpout, GF_PRINTARG_ADD_DASH, &an_arg, "TEST"); @@ -1144,7 +1676,7 @@ static void PrintHelp(char *arg_name, Bool search_desc, Bool no_match) if (search_desc) { char *_arg_name = gf_strdup(arg_name); strlwr(_arg_name); - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Possible options mentionning `%s`:\n", arg_name)); + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Possible options mentioning `%s`:\n", arg_name)); PrintHelpArg(_arg_name, SEARCH_DESC, fs); gf_free(_arg_name); } else { @@ -1160,561 +1692,327 @@ static void PrintHelp(char *arg_name, Bool search_desc, Bool no_match) gf_fs_del(fs); } -void scene_coding_log(void *cbk, GF_LOG_Level log_level, GF_LOG_Tool log_tool, const char *fmt, va_list vlist) -{ - FILE *logs = cbk; - if (log_tool != GF_LOG_CODING) return; - vfprintf(logs, fmt, vlist); - fflush(logs); -} -#ifndef GPAC_DISABLE_ISOM_HINTING - -/* - MP4 File Hinting -*/ - -void SetupClockReferences(GF_ISOFile *file) +u32 parse_sdp_ext(char *arg_val, u32 param) { - u32 i, count, ocr_id; - count = gf_isom_get_track_count(file); - if (count==1) return; - ocr_id = 0; - for (i=0; iOCRESID = ocr_id; - gf_isom_change_mpeg4_description(file, i+1, 1, esd); - gf_odf_desc_del((GF_Descriptor *) esd); + char *id; + sdp_lines = gf_realloc(sdp_lines, sizeof(SDPLine) * (nb_sdp_ex + 1)); + if (!sdp_lines) return 2; + id = strchr(arg_val, ':'); + if (id) { + id[0] = 0; + if (sscanf(arg_val, "%u", &sdp_lines[nb_sdp_ex].trackID) == 1) { + id[0] = ':'; + sdp_lines[nb_sdp_ex].line = id + 1; + } + else { + id[0] = ':'; + sdp_lines[nb_sdp_ex].line = arg_val; + sdp_lines[nb_sdp_ex].trackID = 0; } } + else { + sdp_lines[nb_sdp_ex].line = arg_val; + sdp_lines[nb_sdp_ex].trackID = 0; + } + open_edit = GF_TRUE; + nb_sdp_ex++; + return GF_FALSE; } -/*base RTP payload type used (you can specify your own types if needed)*/ -#define BASE_PAYT 96 -GF_Err HintFile(GF_ISOFile *file, u32 MTUSize, u32 max_ptime, u32 rtp_rate, u32 base_flags, Bool copy_data, Bool interleave, Bool regular_iod, Bool single_group, Bool hint_no_offset) +#ifndef GPAC_DISABLE_ISOM_WRITE +static u32 parse_meta_args(char *opts, MetaActionType act_type) { - GF_ESD *esd; - GF_InitialObjectDescriptor *iod; - u32 i, val, res, streamType; - u32 sl_mode, prev_ocr, single_ocr, nb_done, tot_bw, bw, flags, spec_type; - GF_Err e; - char szPayload[30]; - GF_RTPHinter *hinter; - Bool copy, has_iod, single_av; - u8 init_payt = BASE_PAYT; - u32 mtype; - GF_SDP_IODProfile iod_mode = GF_SDP_IOD_NONE; - u32 media_group = 0; - u8 media_prio = 0; + MetaAction *meta; - tot_bw = 0; - prev_ocr = 0; - single_ocr = 1; + metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); + if (!metas) return 2; + meta = &metas[nb_meta_act]; + nb_meta_act ++; - has_iod = 1; - iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file); - if (!iod) has_iod = 0; - else { - if (!gf_list_count(iod->ESDescriptors)) has_iod = 0; - gf_odf_desc_del((GF_Descriptor *) iod); - } + memset(meta, 0, sizeof(MetaAction)); + meta->act_type = act_type; + meta->trackID = 0; + meta->root_meta = 1; + open_edit = GF_TRUE; - spec_type = gf_isom_guess_specification(file); - single_av = single_group ? 1 : gf_isom_is_single_av(file); + if (!opts) return 2; - /*first make sure we use a systems track as base OCR*/ - for (i=0; iimage_props) {\ + GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);\ + if (!meta->image_props) return 2;\ + }\ - mtype = gf_isom_get_media_type(file, i+1); - switch (mtype) { - case GF_ISOM_MEDIA_VISUAL: - if (single_av) { - media_group = 2; - media_prio = 2; - } - break; - case GF_ISOM_MEDIA_AUXV: - if (single_av) { - media_group = 2; - media_prio = 3; - } - break; - case GF_ISOM_MEDIA_PICT: - if (single_av) { - media_group = 2; - media_prio = 4; - } - break; - case GF_ISOM_MEDIA_AUDIO: - if (single_av) { - media_group = 2; - media_prio = 1; - } - break; - case GF_ISOM_MEDIA_HINT: - continue; - default: - /*no hinting of systems track on isma*/ - if (spec_type==GF_ISOM_BRAND_ISMA) continue; - } - mtype = gf_isom_get_media_subtype(file, i+1, 1); - if ((mtype==GF_ISOM_SUBTYPE_MPEG4) || (mtype==GF_ISOM_SUBTYPE_MPEG4_CRYP) ) mtype = gf_isom_get_mpeg4_subtype(file, i+1, 1); + while (1) { + char *next; + char *szSlot; + if (!opts || !opts[0]) return 0; + if (opts[0]==':') opts += 1; - if (!single_av) { - /*one media per group only (we should prompt user for group selection)*/ - media_group ++; - media_prio = 1; - } + szSlot = opts; + next = gf_url_colon_suffix(opts, '='); + if (next) next[0] = 0; + if (next && !strncmp(szSlot, "auxt", 4)) { + next[0] = ':'; + char *sep = strchr(next, '='); + if (sep) { + next = sep; + while (next[0] != ':') + next--; - streamType = 0; - esd = gf_isom_get_esd(file, i+1, 1); - if (esd) { - streamType = esd->decoderConfig->streamType; - if (!prev_ocr) { - prev_ocr = esd->OCRESID; - if (!esd->OCRESID) prev_ocr = esd->ESID; - } else if (esd->OCRESID && prev_ocr != esd->OCRESID) { - single_ocr = 0; + next[0] = 0; } - /*OD MUST BE WITHOUT REFERENCES*/ - if (streamType==1) copy = 1; } - gf_odf_desc_del((GF_Descriptor *) esd); - if (!regular_iod && gf_isom_is_track_in_root_od(file, i+1)) { - /*single AU - check if base64 would fit in ESD (consider 33% overhead of base64), otherwise stream*/ - if (gf_isom_get_sample_count(file, i+1)==1) { - GF_ISOSample *samp = gf_isom_get_sample(file, i+1, 1, &val); - if (streamType) { - res = gf_hinter_can_embbed_data(samp->data, samp->dataLength, streamType); + if (!strnicmp(szSlot, "tk=", 3)) { + sscanf(szSlot, "tk=%u", &meta->trackID); + if (act_type == META_ACTION_ADD_ITEM) + meta->root_meta = 0; + } + else if (!strnicmp(szSlot, "id=", 3)) { + meta->item_id = atoi(szSlot+3); + } + else if (!strnicmp(szSlot, "type=", 5)) { + meta->item_type = GF_4CC(szSlot[5], szSlot[6], szSlot[7], szSlot[8]); + } + //"ref" (without '=') is for data reference, "ref=" is for item references + else if (!strnicmp(szSlot, "ref=", 4)) { + char type[5]; + MetaRef *ref; + if (!meta->item_refs) { + meta->item_refs = gf_list_new(); + if (!meta->item_refs) return 2; + } + GF_SAFEALLOC(ref, MetaRef); + if (!ref) return 2; + sscanf(szSlot, "ref=%4s,%u", type, &(ref->ref_item_id)); + ref->ref_type = GF_4CC(type[0], type[1], type[2], type[3]); + gf_list_add(meta->item_refs, ref); + } + else if (!strnicmp(szSlot, "name=", 5)) { + meta->szName = gf_strdup(szSlot+5); + } + else if (!strnicmp(szSlot, "path=", 5)) { + meta->szPath = gf_strdup(szSlot+5); + } + else if (!strnicmp(szSlot, "mime=", 5)) { + meta->item_type = GF_META_ITEM_TYPE_MIME; + meta->mime_type = gf_strdup(szSlot+5); + } + else if (!strnicmp(szSlot, "encoding=", 9)) { + meta->enc_type = gf_strdup(szSlot+9); + } + else if (!strnicmp(szSlot, "image-size=", 11)) { + CHECK_IMGPROP + sscanf(szSlot+11, "%dx%d", &meta->image_props->width, &meta->image_props->height); + } + else if (!strnicmp(szSlot, "image-grid-size=", 16)) { + CHECK_IMGPROP + sscanf(szSlot+16, "%dx%d", &meta->image_props->num_grid_rows, &meta->image_props->num_grid_columns); + } + else if (!strnicmp(szSlot, "image-overlay-color=", 20)) { + CHECK_IMGPROP + sscanf(szSlot+20, "%d,%d,%d,%d", &meta->image_props->overlay_canvas_fill_value_r,&meta->image_props->overlay_canvas_fill_value_g,&meta->image_props->overlay_canvas_fill_value_b,&meta->image_props->overlay_canvas_fill_value_a); + } + else if (!strnicmp(szSlot, "image-overlay-offsets=", 22)) { + CHECK_IMGPROP + u32 position = 22; + u32 comma_count = 0; + u32 offset_index = 0; + char *prev = szSlot+position; + char *sub_next = strchr(szSlot+position, ','); + while (sub_next != NULL) { + comma_count++; + sub_next++; + sub_next = strchr(sub_next, ','); + } + meta->image_props->overlay_count = comma_count/2+1; + meta->image_props->overlay_offsets = (GF_ImageItemOverlayOffset *)gf_malloc(meta->image_props->overlay_count*sizeof(GF_ImageItemOverlayOffset)); + if (!meta->image_props->overlay_offsets) { + return 0; + } + sub_next = strchr(szSlot+position, ','); + while (sub_next != NULL) { + *sub_next = 0; + meta->image_props->overlay_offsets[offset_index].horizontal = atoi(prev); + *sub_next = ','; + sub_next++; + prev = sub_next; + if (sub_next) { + sub_next = strchr(sub_next, ','); + if (sub_next) *sub_next = 0; + meta->image_props->overlay_offsets[offset_index].vertical = atoi(prev); + if (sub_next) { + *sub_next = ','; + sub_next++; + prev = sub_next; + sub_next = strchr(sub_next, ','); + } } else { - /*not a system track, we shall hint it*/ - res = 0; + meta->image_props->overlay_offsets[offset_index].vertical = 0; } - if (samp) gf_isom_sample_del(&samp); - if (res) continue; + offset_index++; } } - if (interleave) sl_mode |= GP_RTP_PCK_USE_INTERLEAVING; - - hinter = gf_hinter_track_new(file, i+1, MTUSize, max_ptime, rtp_rate, sl_mode, init_payt, copy, media_group, media_prio, &e); - - if (!hinter) { - if (e) { - fprintf(stderr, "Cannot create hinter (%s)\n", gf_error_to_string(e)); - if (!nb_done) return e; + else if (!strnicmp(szSlot, "image-pasp=", 11)) { + CHECK_IMGPROP + sscanf(szSlot+11, "%dx%d", &meta->image_props->hSpacing, &meta->image_props->vSpacing); + } + else if (!strnicmp(szSlot, "image-pixi=", 11)) { + CHECK_IMGPROP + if (strchr(szSlot+11, ',') == NULL) { + meta->image_props->num_channels = 1; + meta->image_props->bits_per_channel[0] = atoi(szSlot+11); + } else { + meta->image_props->num_channels = 3; + sscanf(szSlot+11, "%u,%u,%u", &(meta->image_props->bits_per_channel[0]), &(meta->image_props->bits_per_channel[1]), &(meta->image_props->bits_per_channel[2])); } - continue; } - - if (hint_no_offset) - gf_hinter_track_force_no_offsets(hinter); - - bw = gf_hinter_track_get_bandwidth(hinter); - tot_bw += bw; - flags = gf_hinter_track_get_flags(hinter); - - //set extraction mode for AVC/SVC - gf_isom_set_nalu_extract_mode(file, i+1, GF_ISOM_NALU_EXTRACT_LAYER_ONLY); - - gf_hinter_track_get_payload_name(hinter, szPayload); - fprintf(stderr, "Hinting track ID %d - Type \"%s:%s\" (%s) - BW %d kbps\n", gf_isom_get_track_id(file, i+1), gf_4cc_to_str(mtype), gf_4cc_to_str(mtype), szPayload, bw); - if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) fprintf(stderr, "\tMPEG-4 Systems stream carousel enabled\n"); - /* - if (flags & GP_RTP_PCK_FORCE_MPEG4) fprintf(stderr, "\tMPEG4 transport forced\n"); - if (flags & GP_RTP_PCK_USE_MULTI) fprintf(stderr, "\tRTP aggregation enabled\n"); - */ - e = gf_hinter_track_process(hinter); - - if (!e) e = gf_hinter_track_finalize(hinter, has_iod); - gf_hinter_track_del(hinter); - - if (e) { - fprintf(stderr, "Error while hinting (%s)\n", gf_error_to_string(e)); - if (!nb_done) return e; + else if (!strnicmp(szSlot, "image-rloc=", 11)) { + CHECK_IMGPROP + sscanf(szSlot+11, "%dx%d", &meta->image_props->hOffset, &meta->image_props->vOffset); } - init_payt++; - nb_done ++; - } - - if (has_iod) { - iod_mode = GF_SDP_IOD_ISMA; - if (regular_iod) iod_mode = GF_SDP_IOD_REGULAR; - } else { - iod_mode = GF_SDP_IOD_NONE; - } - gf_hinter_finalize(file, iod_mode, tot_bw); - - if (!single_ocr) - fprintf(stderr, "Warning: at least 2 timelines found in the file\nThis may not be supported by servers/players\n\n"); - - return GF_OK; -} - -#endif /*GPAC_DISABLE_ISOM_HINTING*/ - -#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_AV_PARSERS) - -static void check_media_profile(GF_ISOFile *file, u32 track) -{ - u8 PL; - GF_ESD *esd = gf_isom_get_esd(file, track, 1); - if (!esd) return; - - switch (esd->decoderConfig->streamType) { - case 0x04: - PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_VISUAL); - if (esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) { - GF_M4VDecSpecInfo vdsi; - gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &vdsi); - if (vdsi.VideoPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, vdsi.VideoPL); - } else if ((esd->decoderConfig->objectTypeIndication==GF_CODECID_AVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_SVC)) { - gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0x15); - } else if (!PL) { - gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0xFE); + else if (!strnicmp(szSlot, "rotation=", 9)) { + CHECK_IMGPROP + meta->image_props->angle = atoi(szSlot+9); } - break; - case 0x05: - PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_AUDIO); - switch (esd->decoderConfig->objectTypeIndication) { - case GF_CODECID_AAC_MPEG2_MP: - case GF_CODECID_AAC_MPEG2_LCP: - case GF_CODECID_AAC_MPEG2_SSRP: - case GF_CODECID_AAC_MPEG4: - { - GF_M4ADecSpecInfo adsi; - gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &adsi); - if (adsi.audioPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, adsi.audioPL); - } - break; - default: - if (!PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0xFE); - } - break; - } - gf_odf_desc_del((GF_Descriptor *) esd); -} -void remove_systems_tracks(GF_ISOFile *file) -{ - u32 i, count; - - count = gf_isom_get_track_count(file); - if (count==1) return; - - /*force PL rewrite*/ - gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0); - gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0); - gf_isom_set_pl_indication(file, GF_ISOM_PL_OD, 1); /*the lib always remove IOD when no profiles are specified..*/ - - for (i=0; iact_type = act_type; - meta->trackID = 0; - meta->root_meta = 1; - - if (!opts) return 0; - while (1) { - char *next; - char *szSlot; - if (!opts || !opts[0]) return ret; - if (opts[0]==':') opts += 1; - - szSlot = opts; - next = gf_url_colon_suffix(opts); - if (next) next[0] = 0; - - if (!strnicmp(szSlot, "tk=", 3)) { - sscanf(szSlot, "tk=%u", &meta->trackID); - meta->root_meta = 0; - ret = 1; - } - else if (!strnicmp(szSlot, "id=", 3)) { - meta->item_id = atoi(szSlot+3); - ret = 1; - } - else if (!strnicmp(szSlot, "type=", 5)) { - meta->item_type = GF_4CC(szSlot[5], szSlot[6], szSlot[7], szSlot[8]); - ret = 1; - } - else if (!strnicmp(szSlot, "ref=", 4)) { - char type[10]; - sscanf(szSlot, "ref=%9s,%u", type, &meta->ref_item_id); - meta->ref_type = GF_4CC(type[0], type[1], type[2], type[3]); - ret = 1; - } - else if (!strnicmp(szSlot, "name=", 5)) { - meta->szName = gf_strdup(szSlot+5); - ret = 1; - } - else if (!strnicmp(szSlot, "path=", 5)) { - meta->szPath = gf_strdup(szSlot+5); - ret = 1; - } - else if (!strnicmp(szSlot, "mime=", 5)) { - meta->item_type = GF_META_ITEM_TYPE_MIME; - meta->mime_type = gf_strdup(szSlot+5); - ret = 1; - } - else if (!strnicmp(szSlot, "encoding=", 9)) { - meta->enc_type = gf_strdup(szSlot+9); - ret = 1; - } - else if (!strnicmp(szSlot, "image-size=", 11)) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } - - sscanf(szSlot+11, "%dx%d", &meta->image_props->width, &meta->image_props->height); - ret = 1; - } - else if (!strnicmp(szSlot, "image-pasp=", 11)) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } - sscanf(szSlot+11, "%dx%d", &meta->image_props->hSpacing, &meta->image_props->vSpacing); - ret = 1; - } - else if (!strnicmp(szSlot, "image-rloc=", 11)) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } - sscanf(szSlot+11, "%dx%d", &meta->image_props->hOffset, &meta->image_props->vOffset); - ret = 1; + else if (!strnicmp(szSlot, "mirror-axis=", 12)) { + CHECK_IMGPROP + meta->image_props->mirror = (!strnicmp(szSlot+12, "vertical", 8) ? 1 : 2); } - else if (!strnicmp(szSlot, "rotation=", 9)) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } - meta->image_props->angle = atoi(szSlot+9); - ret = 1; + else if (!strnicmp(szSlot, "clap=", 5)) { + CHECK_IMGPROP + sscanf(szSlot + 5, "%d,%d,%d,%d,%d,%d,%d,%d", &meta->image_props->clap_wnum, &meta->image_props->clap_wden, + &meta->image_props->clap_hnum, &meta->image_props->clap_hden, + &meta->image_props->clap_honum, &meta->image_props->clap_hoden, + &meta->image_props->clap_vonum, &meta->image_props->clap_voden); } else if (!stricmp(szSlot, "hidden")) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } + CHECK_IMGPROP meta->image_props->hidden = GF_TRUE; - ret = 1; } else if (!stricmp(szSlot, "alpha")) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } + CHECK_IMGPROP meta->image_props->alpha = GF_TRUE; - ret = 1; + } + else if (!stricmp(szSlot, "depth")) { + CHECK_IMGPROP + meta->image_props->depth = GF_TRUE; + } + //"ref" (without '=') is for data reference, "ref=" is for item references + else if (!stricmp(szSlot, "ref")) { + CHECK_IMGPROP + meta->image_props->use_reference = GF_TRUE; + } + else if (!strnicmp(szSlot, "it=", 3)) { + CHECK_IMGPROP + meta->image_props->item_ref_id = atoi(szSlot+3); + } + else if (!strnicmp(szSlot, "itp=", 4)) { + CHECK_IMGPROP + meta->image_props->item_ref_id = atoi(szSlot+4); + meta->image_props->copy_props = 1; } else if (!strnicmp(szSlot, "time=", 5)) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } - meta->image_props->time = atof(szSlot+5); - ret = 1; + Float s=0, e=0, step=0; + CHECK_IMGPROP + if (sscanf(szSlot+5, "%f-%f/%f", &s, &e, &step)==3) { + meta->image_props->time = s; + meta->image_props->end_time = e; + meta->image_props->step_time = step; + } else if (sscanf(szSlot+5, "%f-%f", &s, &e)==2) { + meta->image_props->time = s; + meta->image_props->end_time = e; + } else if (sscanf(szSlot+5, "%f/%f", &s, &step)==2) { + meta->image_props->time = s; + meta->image_props->step_time = step; + } else if (sscanf(szSlot+5, "%f", &s)==1) { + meta->image_props->time = s; + } + } + else if (!strnicmp(szSlot, "samp=", 5)) { + CHECK_IMGPROP + meta->image_props->sample_num = atoi(szSlot+5); + meta->root_meta = 1; + } + else if (!strnicmp(szSlot, "group=", 6)) { + char type[5]; + sscanf(szSlot, "group=%4s,%u", type, &meta->group_id); + meta->group_type = GF_4CC(type[0], type[1], type[2], type[3]); } else if (!stricmp(szSlot, "split_tiles")) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } + CHECK_IMGPROP meta->image_props->tile_mode = TILE_ITEM_ALL_BASE; - ret = 1; } else if (!stricmp(szSlot, "dref")) { meta->use_dref = 1; - ret = 1; } else if (!stricmp(szSlot, "primary")) { meta->primary = 1; - ret = 1; } else if (!stricmp(szSlot, "binary")) { if (meta->act_type==META_ACTION_SET_XML) meta->act_type=META_ACTION_SET_BINARY_XML; - ret = 1; } else if (!strnicmp(szSlot, "icc_path=", 9)) { - if (!meta->image_props) { - GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); - if (!meta->image_props) return 0; - } + CHECK_IMGPROP strcpy(meta->image_props->iccPath, szSlot+9); - ret = 1; + } + else if (!stricmp(szSlot, "agrid") || !strnicmp(szSlot, "agrid=", 6)) { + CHECK_IMGPROP + meta->image_props->auto_grid = GF_TRUE; + if (!strnicmp(szSlot, "agrid=", 6)) + meta->image_props->auto_grid_ratio = atof(szSlot+6); + } + else if (!strnicmp(szSlot, "av1_op_index=", 13)) { + CHECK_IMGPROP + meta->image_props->av1_op_index = atoi(szSlot+13); + } + else if (!stricmp(szSlot, "replace")) { + meta->replace = GF_TRUE; + } + else if (!strnicmp(szSlot, "keep_props=", 11)) { + CHECK_IMGPROP + meta->keep_props = gf_strdup(szSlot+11); + } + else if (!strnicmp(szSlot, "auxt=", 5)) { + CHECK_IMGPROP + meta->image_props->aux_urn = gf_strdup(szSlot+5); + } + else if (!strnicmp(szSlot, "auxd=", 5)) { + CHECK_IMGPROP + GF_Err e = gf_file_load_data(szSlot+5, (u8 **) &meta->image_props->aux_data, &meta->image_props->aux_data_len); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Failed to load auxiliary data file %s: %s\n", szSlot+5, gf_error_to_string(e) )); + return 1; + } } else if (!strchr(szSlot, '=')) { switch (meta->act_type) { case META_ACTION_SET_TYPE: if (!stricmp(szSlot, "null") || !stricmp(szSlot, "0")) meta->meta_4cc = 0; else meta->meta_4cc = GF_4CC(szSlot[0], szSlot[1], szSlot[2], szSlot[3]); - ret = 1; break; case META_ACTION_ADD_ITEM: case META_ACTION_ADD_IMAGE_ITEM: case META_ACTION_SET_XML: case META_ACTION_DUMP_XML: - if (!strncmp(szSlot, "dopt", 4) || !strncmp(szSlot, "sopt", 4) || !strncmp(szSlot, "@@", 2)) { + if (!strncmp(szSlot, "dopt", 4) || !strncmp(szSlot, "sopt", 4) || !strncmp(szSlot, "@", 1)) { if (next) next[0]=':'; next=NULL; } //cat as -add arg gf_dynstrcat(&meta->szPath, szSlot, ":"); - ret = 1; + if (!meta->szPath) return 2; break; case META_ACTION_REM_ITEM: case META_ACTION_SET_PRIMARY_ITEM: case META_ACTION_DUMP_ITEM: meta->item_id = atoi(szSlot); - ret = 1; break; default: break; @@ -1724,30 +2022,13 @@ static Bool parse_meta_args(MetaAction *meta, MetaActionType act_type, char *opt opts += strlen(szSlot); next[0] = ':'; } - return ret; + return 0; } #endif //GPAC_DISABLE_ISOM_WRITE -typedef enum { - TSEL_ACTION_SET_PARAM = 0, - TSEL_ACTION_REMOVE_TSEL = 1, - TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP = 2, -} TSELActionType; - -typedef struct -{ - TSELActionType act_type; - GF_ISOTrackID trackID; - - GF_ISOTrackID refTrackID; - u32 criteria[30]; - u32 nb_criteria; - Bool is_switchGroup; - u32 switchGroupID; -} TSELAction; #ifndef GPAC_DISABLE_ISOM_WRITE -static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_act, TSELActionType act) +static Bool parse_tsel_args(char *opts, TSELActionType act) { GF_ISOTrackID refTrackID = 0; Bool has_switch_id; @@ -1756,18 +2037,16 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a u32 nb_criteria = 0; TSELAction *tsel_act; char szSlot[1024]; - TSELAction *tsel_list; has_switch_id = 0; - if (!opts) return 0; while (1) { char *next; - if (!opts || !opts[0]) return 1; + if (!opts || !opts[0]) return 0; if (opts[0]==':') opts += 1; strcpy(szSlot, opts); - next = gf_url_colon_suffix(szSlot); + next = gf_url_colon_suffix(szSlot, '='); if (next) next[0] = 0; @@ -1795,10 +2074,12 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a } } else if (!strnicmp(szSlot, "trackID=", 8) || !strchr(szSlot, '=') ) { - *__tsel_list = gf_realloc(*__tsel_list, sizeof(TSELAction) * (*nb_tsel_act + 1)); - tsel_list = *__tsel_list; + tsel_acts = gf_realloc(tsel_acts, sizeof(TSELAction) * (nb_tsel_acts + 1)); + if (!tsel_acts) return 2; + + tsel_act = &tsel_acts[nb_tsel_acts]; + nb_tsel_acts++; - tsel_act = &tsel_list[*nb_tsel_act]; memset(tsel_act, 0, sizeof(TSELAction)); tsel_act->act_type = act; tsel_act->trackID = strchr(szSlot, '=') ? atoi(szSlot+8) : atoi(szSlot); @@ -1811,133 +2092,45 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a if (!refTrackID) refTrackID = tsel_act->trackID; - (*nb_tsel_act) ++; + open_edit = GF_TRUE; } opts += strlen(szSlot); } - return 1; + return 0; } #endif // GPAC_DISABLE_ISOM_WRITE -#define CHECK_NEXT_ARG if (i+1==(u32)argc) {\ - fprintf(stderr, "Missing arg - please check usage\n"); return mp4box_cleanup(1);\ - } else { \ - has_next_arg = GF_TRUE;\ - } +GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *name, u32 *nb_dash_inputs) +{ + GF_DashSegmenterInput *di; + Bool skip_rep_id = GF_FALSE; + char *other_opts = NULL; + char *sep = gf_url_colon_suffix(name, '='); + dash_inputs = gf_realloc(dash_inputs, sizeof(GF_DashSegmenterInput) * (*nb_dash_inputs + 1) ); + memset(&dash_inputs[*nb_dash_inputs], 0, sizeof(GF_DashSegmenterInput) ); + di = &dash_inputs[*nb_dash_inputs]; + (*nb_dash_inputs)++; -typedef enum { - TRAC_ACTION_REM_TRACK = 0, - TRAC_ACTION_SET_LANGUAGE = 1, - TRAC_ACTION_SET_DELAY = 2, - TRAC_ACTION_SET_KMS_URI = 3, - TRAC_ACTION_SET_PAR = 4, - TRAC_ACTION_SET_HANDLER_NAME= 5, - TRAC_ACTION_ENABLE = 6, - TRAC_ACTION_DISABLE = 7, - TRAC_ACTION_REFERENCE = 8, - TRAC_ACTION_RAW_EXTRACT = 9, - TRAC_ACTION_REM_NON_RAP = 10, - TRAC_ACTION_SET_KIND = 11, - TRAC_ACTION_REM_KIND = 12, - TRAC_ACTION_SET_ID = 13, - TRAC_ACTION_SET_UDTA = 14, - TRAC_ACTION_SWAP_ID = 15, - TRAC_ACTION_REM_NON_REFS = 16, - TRAC_ACTION_SET_CLAP = 17, - TRAC_ACTION_SET_MX = 18, -} TrackActionType; - -typedef struct -{ - TrackActionType act_type; - GF_ISOTrackID trackID; - char lang[10]; - s32 delay_ms; - const char *kms; - const char *hdl_name; - s32 par_num, par_den; - u8 force_par, rewrite_bs; - u32 dump_type, sample_num; - char *out_name; - char *src_name; - u32 udta_type; - char *kind_scheme, *kind_value; - u32 newTrackID; - s32 clap_wnum, clap_wden, clap_hnum, clap_hden, clap_honum, clap_hoden, clap_vonum, clap_voden; - s32 mx[9]; -} TrackAction; - -enum -{ - GF_ISOM_CONV_TYPE_ISMA = 1, - GF_ISOM_CONV_TYPE_ISMA_EX, - GF_ISOM_CONV_TYPE_3GPP, - GF_ISOM_CONV_TYPE_IPOD, - GF_ISOM_CONV_TYPE_PSP, - GF_ISOM_CONV_TYPE_MOV -}; - - - -GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *name, u32 *nb_dash_inputs) -{ - GF_DashSegmenterInput *di; - char *other_opts = NULL; - char *sep = gf_url_colon_suffix(name); - - dash_inputs = gf_realloc(dash_inputs, sizeof(GF_DashSegmenterInput) * (*nb_dash_inputs + 1) ); - memset(&dash_inputs[*nb_dash_inputs], 0, sizeof(GF_DashSegmenterInput) ); - di = &dash_inputs[*nb_dash_inputs]; - (*nb_dash_inputs)++; - - if (sep) { - char *opts, *first_opt; - opts = first_opt = sep; - while (opts) { - sep = gf_url_colon_suffix(opts); - while (sep) { - /* this is a real separator if it is followed by a keyword we are looking for */ - if (!strnicmp(sep, ":id=", 4) || - !strnicmp(sep, ":dur=", 5) || - !strnicmp(sep, ":period=", 8) || - !strnicmp(sep, ":BaseURL=", 9) || - !strnicmp(sep, ":bandwidth=", 11) || - !strnicmp(sep, ":role=", 6) || - !strnicmp(sep, ":desc", 5) || - !strnicmp(sep, ":sscale", 7) || - !strnicmp(sep, ":duration=", 10) || - !strnicmp(sep, ":period_duration=", 10) || - !strnicmp(sep, ":pdur=", 6) || - !strnicmp(sep, ":xlink=", 7) || - !strnicmp(sep, ":asID=", 6) || - !strnicmp(sep, ":sn=", 4) || - !strnicmp(sep, ":tpl=", 5) || - !strnicmp(sep, ":hls=", 5) || - !strnicmp(sep, ":trackID=", 9) || - !strnicmp(sep, ":@@", 3) - ) { - break; - } else { - char *nsep = gf_url_colon_suffix(sep+1); - if (nsep) nsep[0] = 0; - - gf_dynstrcat(&other_opts, sep, ":"); - - if (nsep) nsep[0] = ':'; - - sep = strchr(sep+1, ':'); - } - } - if (sep && !strncmp(sep, "://", 3) && strnicmp(sep, ":@@", 3)) sep = gf_url_colon_suffix(sep+3); - if (sep) sep[0] = 0; + if (sep) { + char *opts, *first_opt; + first_opt = sep; + opts = sep+1; + while (opts) { + //none of our options use filenames, so don't check for '=' + sep = gf_url_colon_suffix(opts, 0); + if (sep && !strncmp(sep, "://", 3) && strncmp(sep, ":@", 2)) sep = gf_url_colon_suffix(sep+3, 0); + if (sep) sep[0] = 0; if (!strnicmp(opts, "id=", 3)) { - di->representationID = gf_strdup(opts+3); + if (!stricmp(opts+3, "NULL")) + skip_rep_id = GF_TRUE; + else + di->representationID = gf_strdup(opts+3); /*we allow the same repID to be set to force muxed representations*/ } - else if (!strnicmp(opts, "dur=", 4)) di->media_duration = (Double)atof(opts+4); + else if (!strnicmp(opts, "dur=", 4)) gf_parse_lfrac(opts+4, &di->media_duration); else if (!strnicmp(opts, "period=", 7)) di->periodID = gf_strdup(opts+7); else if (!strnicmp(opts, "BaseURL=", 8)) { di->baseURL = (char **)gf_realloc(di->baseURL, (di->nb_baseURL+1)*sizeof(char *)); @@ -1976,25 +2169,32 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * len = (u32) strlen(opts); (*descs) = (char **)gf_realloc((*descs), (*nb_descs)*sizeof(char *)); (*descs)[(*nb_descs)-1] = (char *)gf_malloc((len+1)*sizeof(char)); - strncpy((*descs)[(*nb_descs)-1], opts, len); + memcpy((*descs)[(*nb_descs)-1], opts, len); (*descs)[(*nb_descs)-1][len] = 0; } } else if (!strnicmp(opts, "xlink=", 6)) di->xlink = gf_strdup(opts+6); else if (!strnicmp(opts, "sscale", 6)) di->sscale = GF_TRUE; - else if (!strnicmp(opts, "pdur=", 5)) di->period_duration = (Double) atof(opts+5); - else if (!strnicmp(opts, "period_duration=", 16)) di->period_duration = (Double) atof(opts+16); - else if (!strnicmp(opts, "duration=", 9)) di->dash_duration = (Double) atof(opts+9); + else if (!strnicmp(opts, "pdur=", 5)) gf_parse_frac(opts+5, &di->period_duration); + else if (!strnicmp(opts, "period_duration=", 16)) gf_parse_frac(opts+16, &di->period_duration); + else if (!strnicmp(opts, "ddur=", 5)) gf_parse_frac(opts+5, &di->dash_duration); + else if (!strnicmp(opts, "duration=", 9)) gf_parse_frac(opts+9, &di->dash_duration); else if (!strnicmp(opts, "asID=", 5)) di->asID = atoi(opts+5); else if (!strnicmp(opts, "sn=", 3)) di->startNumber = atoi(opts+3); else if (!strnicmp(opts, "tpl=", 4)) di->seg_template = gf_strdup(opts+4); else if (!strnicmp(opts, "hls=", 4)) di->hls_pl = gf_strdup(opts+4); else if (!strnicmp(opts, "trackID=", 8)) di->track_id = atoi(opts+8); - else if (!strnicmp(opts, "@@", 2)) { - di->filter_chain = gf_strdup(opts+2); + else if (!strnicmp(opts, "@", 1)) { + Bool old_syntax = (opts[1]=='@') ? GF_TRUE : GF_FALSE; if (sep) sep[0] = ':'; + di->filter_chain = gf_strdup(opts + (old_syntax ? 2 : 1) ); sep = NULL; + if (!old_syntax && (strstr(di->filter_chain, "@@")!=NULL)) { + skip_rep_id = GF_TRUE; + } + } else { + gf_dynstrcat(&other_opts, opts, ":"); } if (!sep) break; @@ -2006,7 +2206,7 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * di->file_name = name; di->source_opts = other_opts; - if (!di->representationID) { + if (!skip_rep_id && !di->representationID) { char szRep[100]; sprintf(szRep, "%d", *nb_dash_inputs); di->representationID = gf_strdup(szRep); @@ -2015,2474 +2215,3476 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * return dash_inputs; } -static GF_Err parse_track_action_params(char *string, TrackAction *action) +static Bool create_new_track_action(char *arg_val, u32 act_type, u32 dump_type) { - char *param = string; - if (!action || !string) return GF_BAD_PARAM; + TrackAction *tka; + char *param = arg_val; + tracks = (TrackAction *)gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); + if (!tracks) return GF_FALSE; + + tka = & tracks[nb_track_act]; + nb_track_act++; + + memset(tka, 0, sizeof(TrackAction) ); + tka->act_type = act_type; + tka->dump_type = dump_type; + if (act_type != TRACK_ACTION_RAW_EXTRACT) { + open_edit = GF_TRUE; + do_save = GF_TRUE; + } + + if ((act_type==TRACK_ACTION_SET_ID) || (act_type==TRACK_ACTION_SWAP_ID)) { + if (sscanf(param, "%d:%u", &tka->trackID, &tka->newTrackID) != 2) { + M4_LOG(GF_LOG_ERROR, ("Bad format for -set-track-id - expecting \"id1:id2\" got \"%s\"\n", param)); + return GF_FALSE; + } + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_PAR) { + char *ext; + ext = strchr(param, '='); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track par - expecting tkID=none or tkID=PAR_NUM:PAR_DEN got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + + if (!stricmp(ext+1, "none")) + tka->par_num = tka->par_den = 0; + else if (!stricmp(ext+1, "auto")) { + tka->par_num = tka->par_den = -1; + tka->force_par = 1; + } + else if (!stricmp(ext+1, "force")) { + tka->par_num = tka->par_den = 1; + tka->force_par = 1; + } + else { + if (ext[1]=='w') { + tka->rewrite_bs = 1; + ext++; + } + if (sscanf(ext+1, "%d:%d", &tka->par_num, &tka->par_den) != 2) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track par - expecting tkID=PAR_NUM:PAR_DEN got %s\n", param)); + return GF_FALSE; + } + } + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_CLAP) { + char *ext = strchr(param, '='); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track clap - expecting tkID=none or tkID=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + if (stricmp(ext + 1, "none")) { + if (sscanf(ext + 1, "%d,%d,%d,%d,%d,%d,%d,%d", &tka->clap_wnum, &tka->clap_wden, &tka->clap_hnum, &tka->clap_hden, &tka->clap_honum, &tka->clap_hoden, &tka->clap_vonum, &tka->clap_voden) != 8) { + + M4_LOG(GF_LOG_ERROR, ("Bad format for track clap - expecting tkID=none or tkID=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd got %s\n", param)); + return GF_FALSE; + } + } + return GF_TRUE; + } + + if (act_type==TRACK_ACTION_SET_MX) { + char *ext = strchr(param, '='); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track matrix - expecting ID=none or ID=M1:M2:M3:M4:M5:M6:M7:M8:M9 got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + if (!stricmp(ext + 1, "none")) { + memset(tka->mx, 0, sizeof(s32)*9); + tka->mx[0] = tka->mx[4] = tka->mx[8] = 1; + } else { + s32 res; + if (strstr(ext+1, "0x")) { + res = sscanf(ext + 1, "0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d", &tka->mx[0], &tka->mx[1], &tka->mx[2], &tka->mx[3], &tka->mx[4], &tka->mx[5], &tka->mx[6], &tka->mx[7], &tka->mx[8]); + } else { + res = sscanf(ext + 1, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &tka->mx[0], &tka->mx[1], &tka->mx[2], &tka->mx[3], &tka->mx[4], &tka->mx[5], &tka->mx[6], &tka->mx[7], &tka->mx[8]); + } + if (res != 9) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track matrix - expecting ID=none or ID=M1:M2:M3:M4:M5:M6:M7:M8:M9 got %s\n", param)); + return GF_FALSE; + } + } + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_EDITS) { + char *ext = strchr(param, '='); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track edits - expecting ID=EDITS got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + tka->string = gf_strdup(ext+1); + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_LANGUAGE) { + char *ext = strchr(param, '='); + if (!strnicmp(param, "all=", 4)) { + strncpy(tka->lang, param + 4, 10-1); + } + else if (!ext) { + strncpy(tka->lang, param, 10-1); + } else { + strncpy(tka->lang, ext + 1, 10-1); + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + } + return GF_TRUE; + } + if ((act_type==TRACK_ACTION_SET_KIND) || (act_type==TRACK_ACTION_REM_KIND)) { + char *ext; + char *scheme_start = NULL; + + //extract trackID + if (!strnicmp(param, "all=", 4)) { + scheme_start = param + 4; + } else { + ext = strchr(param, '='); + if (ext) { + ext[0] = 0; + if (sscanf(param, "%d", &tka->trackID) == 1) { + scheme_start = ext + 1; + } else { + scheme_start = param; + } + ext[0] = '='; + } else { + scheme_start = param; + } + } + + //extract scheme and value - if not, remove kind + if (!scheme_start || !scheme_start[0]) { + M4_LOG(GF_LOG_ERROR, ("Missing kind scheme - expecting ID=schemeURI=value got %s\n", param)); + return GF_FALSE; + } else { + ext = strchr(scheme_start, '='); + if (!ext) { + tka->kind_scheme = gf_strdup(scheme_start); + } else { + ext[0] = 0; + tka->kind_scheme = gf_strdup(scheme_start); + ext[0] = '='; + tka->kind_value = gf_strdup(ext + 1); + } + } + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_DELAY) { + char *ext = strchr(param, '='); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track delay - expecting tkID=DLAY got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + if (sscanf(ext+1, "%d/%u", &tka->delay.num, &tka->delay.den) != 2) { + tka->delay.num = atoi(ext + 1); + tka->delay.den = 1000; + } + return GF_TRUE; + } + if (act_type==TRACK_ACTION_REFERENCE) { + char *ext = strchr(param, '='); + if (!ext) ext = strchr(param, ':'); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track reference - expecting tkID:XXXX:refID got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + + char *ext2 = strchr(ext, ':'); + if (!ext2) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track reference - expecting tkID:XXXX:refID got %s\n", param)); + return GF_FALSE; + } + ext2[0] = 0; + strncpy(tka->lang, ext+1, 9); + ext2[0] = ':'; + tka->newTrackID = (s32) atoi(ext2 + 1); + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_HANDLER_NAME) { + char *ext = strchr(param, '='); + if (!ext) { + M4_LOG(GF_LOG_ERROR, ("Bad format for track name - expecting tkID=name got %s\n", param)); + return GF_FALSE; + } + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + tka->hdl_name = ext + 1; + return GF_TRUE; + } + if (act_type==TRACK_ACTION_SET_KMS_URI) { + char *ext = strchr(param, '='); + + if (!strnicmp(param, "all=", 4)) { + tka->kms = param + 4; + } else if (!ext) { + tka->kms = param; + } else { + tka->kms = ext + 1; + ext[0] = 0; + tka->trackID = atoi(param); + ext[0] = '='; + } + return GF_TRUE; + } + if ((act_type==TRACK_ACTION_SET_TIME) || (act_type==TRACK_ACTION_SET_MEDIA_TIME)) { + struct tm time; + char *ext = strchr(arg_val, '='); + if (ext) { + ext[0] = 0; + tka->trackID = atoi(arg_val); + ext[0] = '='; + arg_val = ext+1; + } + memset(&time, 0, sizeof(struct tm)); + sscanf(arg_val, "%d/%d/%d-%d:%d:%d", &time.tm_mday, &time.tm_mon, &time.tm_year, &time.tm_hour, &time.tm_min, &time.tm_sec); + time.tm_isdst = 0; + time.tm_year -= 1900; + time.tm_mon -= 1; + tka->time = 2082758400; + tka->time += mktime(&time); + return GF_TRUE; + } while (param) { - param = gf_url_colon_suffix(param); + param = gf_url_colon_suffix(param, '='); if (param) { *param = 0; param++; #ifndef GPAC_DISABLE_MEDIA_EXPORT if (!strncmp("vttnomerge", param, 10)) { - action->dump_type |= GF_EXPORT_WEBVTT_NOMERGE; + tka->dump_type |= GF_EXPORT_WEBVTT_NOMERGE; } else if (!strncmp("layer", param, 5)) { - action->dump_type |= GF_EXPORT_SVC_LAYER; + tka->dump_type |= GF_EXPORT_SVC_LAYER; } else if (!strncmp("full", param, 4)) { - action->dump_type |= GF_EXPORT_NHML_FULL; + tka->dump_type |= GF_EXPORT_NHML_FULL; } else if (!strncmp("embedded", param, 8)) { - action->dump_type |= GF_EXPORT_WEBVTT_META_EMBEDDED; + tka->dump_type |= GF_EXPORT_WEBVTT_META_EMBEDDED; } else if (!strncmp("output=", param, 7)) { - action->out_name = gf_strdup(param+7); + tka->out_name = gf_strdup(param+7); } else if (!strncmp("src=", param, 4)) { - action->src_name = gf_strdup(param+4); + tka->src_name = gf_strdup(param+4); + } else if (!strncmp("str=", param, 4)) { + tka->string = gf_strdup(param+4); } else if (!strncmp("box=", param, 4)) { - action->src_name = gf_strdup(param+4); - action->sample_num = 1; + tka->src_name = gf_strdup(param+4); + tka->sample_num = 1; } else if (!strncmp("type=", param, 4)) { - action->udta_type = GF_4CC(param[5], param[6], param[7], param[8]); - } else if (action->dump_type == GF_EXPORT_RAW_SAMPLES) { - action->sample_num = atoi(param); + tka->udta_type = GF_4CC(param[5], param[6], param[7], param[8]); + } else if (tka->dump_type == GF_EXPORT_RAW_SAMPLES) { + tka->sample_num = atoi(param); } #endif } } - if (!strcmp(string, "*")) { - action->trackID = (u32) -1; - } else { - action->trackID = atoi(string); + if (arg_val) { + if (!strcmp(arg_val, "*")) { + tka->trackID = (u32) -1; + } else { + if (act_type==TRACK_ACTION_RAW_EXTRACT) { + if (!strncmp(arg_val, "video", 5)) { + arg_val += 5; + tka->dump_track_type = 1; + } + else if (!strncmp(arg_val, "audio", 5)) { + arg_val += 5; + tka->dump_track_type = 2; + } + } + if (arg_val[0]) + tka->trackID = atoi(arg_val); + } } - return GF_OK; + return GF_TRUE; } -static u32 create_new_track_action(char *string, TrackAction **actions, u32 *nb_track_act, u32 dump_type) +u32 parse_track_dump(char *arg, u32 dump_type) +{ + if (!create_new_track_action(arg, TRACK_ACTION_RAW_EXTRACT, dump_type)) + return 2; + track_dump_type = dump_type; + return 0; +} +u32 parse_track_action(char *arg, u32 act_type) { - *actions = (TrackAction *)gf_realloc(*actions, sizeof(TrackAction) * (*nb_track_act+1)); - memset(&(*actions)[*nb_track_act], 0, sizeof(TrackAction) ); - (*actions)[*nb_track_act].act_type = TRAC_ACTION_RAW_EXTRACT; - (*actions)[*nb_track_act].dump_type = dump_type; - parse_track_action_params(string, &(*actions)[*nb_track_act]); - (*nb_track_act)++; - return dump_type; + if (!create_new_track_action(arg, act_type, 0)) { + return 2; + } + return 0; } -#ifndef GPAC_DISABLE_CORE_TOOLS -static GF_Err xml_bs_to_bin(char *inName, char *outName, u32 dump_std) +u32 parse_comp_box(char *arg_val, u32 opt) { - GF_Err e; - GF_XMLNode *root; - u8 *data = NULL; - u32 data_size; + compress_top_boxes = arg_val; + size_top_box = opt; + return 0; +} +u32 parse_dnal(char *arg_val, u32 opt) +{ + dump_nal = atoi(arg_val); + dump_nal_type = opt; + return 0; +} +u32 parse_dsap(char *arg_val, u32 opt) +{ + dump_saps = atoi(arg_val); + dump_saps_mode = opt; + return 0; +} - GF_DOMParser *dom = gf_xml_dom_new(); - e = gf_xml_dom_parse(dom, inName, NULL, NULL); - if (e) { - gf_xml_dom_del(dom); - fprintf(stderr, "Failed to parse XML file: %s\n", gf_error_to_string(e)); - return e; +u32 parse_bs_switch(char *arg_val, u32 opt) +{ + if (!stricmp(arg_val, "no") || !stricmp(arg_val, "off")) bitstream_switching_mode = GF_DASH_BSMODE_NONE; + else if (!stricmp(arg_val, "merge")) bitstream_switching_mode = GF_DASH_BSMODE_MERGED; + else if (!stricmp(arg_val, "multi")) bitstream_switching_mode = GF_DASH_BSMODE_MULTIPLE_ENTRIES; + else if (!stricmp(arg_val, "single")) bitstream_switching_mode = GF_DASH_BSMODE_SINGLE; + else if (!stricmp(arg_val, "inband")) bitstream_switching_mode = GF_DASH_BSMODE_INBAND; + else if (!stricmp(arg_val, "pps")) bitstream_switching_mode = GF_DASH_BSMODE_INBAND_PPS; + else { + M4_LOG(GF_LOG_ERROR, ("Unrecognized bitstream switching mode \"%s\" - please check usage\n", arg_val)); + return 2; } - root = gf_xml_dom_get_root_idx(dom, 0); - if (!root) { - gf_xml_dom_del(dom); - return GF_OK; + return 0; +} + +u32 parse_cp_loc(char *arg_val, u32 opt) +{ + if (!strcmp(arg_val, "both")) cp_location_mode = GF_DASH_CPMODE_BOTH; + else if (!strcmp(arg_val, "as")) cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET; + else if (!strcmp(arg_val, "rep")) cp_location_mode = GF_DASH_CPMODE_REPRESENTATION; + else { + M4_LOG(GF_LOG_ERROR, ("Unrecognized ContentProtection loction mode \"%s\" - please check usage\n", arg_val)); + return 2; } + return 0; +} - e = gf_xml_parse_bit_sequence(root, inName, &data, &data_size); - gf_xml_dom_del(dom); +u32 parse_pssh(char *arg_val, u32 opt) +{ + if (!strcmp(arg_val, "f")) pssh_mode = GF_DASH_PSSH_MOOF; + else if (!strcmp(arg_val, "v")) pssh_mode = GF_DASH_PSSH_MOOV; + else if (!strcmp(arg_val, "m")) pssh_mode = GF_DASH_PSSH_MPD; + else if (!strcmp(arg_val, "mf") || !strcmp(arg_val, "fm")) pssh_mode = GF_DASH_PSSH_MOOF_MPD; + else if (!strcmp(arg_val, "mv") || !strcmp(arg_val, "vm")) pssh_mode = GF_DASH_PSSH_MOOV_MPD; + else pssh_mode = GF_DASH_PSSH_MOOV; + return 0; +} +u32 parse_sdtp(char *arg_val, u32 opt) +{ + if (!stricmp(arg_val, "both")) sdtp_in_traf = 2; + else if (!stricmp(arg_val, "sdtp")) sdtp_in_traf = 1; + else sdtp_in_traf = 0; + return 0; +} - if (e) { - fprintf(stderr, "Failed to parse binary sequence: %s\n", gf_error_to_string(e)); - return e; +u32 parse_rap_ref(char *arg_val, u32 opt) +{ + if (arg_val) { + if (sscanf(arg_val, "%d", &trackID) == 1) { + parse_track_action(arg_val, opt ? TRACK_ACTION_REM_NON_REFS : TRACK_ACTION_REM_NON_RAP); + } + } +#ifndef GPAC_DISABLE_STREAMING + hint_flags |= GP_RTP_PCK_SIGNAL_RAP; +#endif + seg_at_rap = 1; + return 0; +} +u32 parse_store_mode(char *arg_val, u32 opt) +{ + do_save = GF_TRUE; + if ((opt == 0) || (opt == 1)) { + interleaving_time = atof(arg_val) / 1000; + if (!interleaving_time) do_flat = 2; + open_edit = GF_TRUE; + no_inplace = GF_TRUE; + if (opt==1) old_interleave = 1; + } else if (opt==2) { + interleaving_time = atof(arg_val); + do_frag = GF_TRUE; + } else { + force_new = 2; + interleaving_time = 0.5; + do_flat = 1; } + return 0; +} +u32 parse_base_url(char *arg_val, u32 opt) +{ + mpd_base_urls = gf_realloc(mpd_base_urls, (nb_mpd_base_urls + 1)*sizeof(char**)); + if (!mpd_base_urls) return 2; + mpd_base_urls[nb_mpd_base_urls] = arg_val; + nb_mpd_base_urls++; + return 0; +} +u32 parse_multi_rtp(char *arg_val, u32 opt) +{ +#ifndef GPAC_DISABLE_STREAMING + hint_flags |= GP_RTP_PCK_USE_MULTI; +#endif + if (arg_val) + max_ptime = atoi(arg_val); + return 0; +} - if (dump_std) { - gf_fwrite(data, data_size, stdout); + +u32 parse_senc_param(char *arg_val, u32 opt) +{ +#ifndef GPAC_DISABLE_SCENE_ENCODER + switch (opt) { + case 0: //-sync + smenc_opts.flags |= GF_SM_ENCODE_RAP_INBAND; + smenc_opts.rap_freq = atoi(arg_val); + break; + case 1: //-shadow + smenc_opts.flags &= ~GF_SM_ENCODE_RAP_INBAND; + smenc_opts.flags |= GF_SM_ENCODE_RAP_SHADOW; + smenc_opts.rap_freq = atoi(arg_val); + break; + case 2: //-carousel + smenc_opts.flags &= ~(GF_SM_ENCODE_RAP_INBAND | GF_SM_ENCODE_RAP_SHADOW); + smenc_opts.rap_freq = atoi(arg_val); + break; + case 3: //-auto-quant + smenc_opts.resolution = atoi(arg_val); + smenc_opts.auto_quant = 1; + break; + case 4: //-global-quant + smenc_opts.resolution = atoi(arg_val); + smenc_opts.auto_quant = 2; + break; + case 5: //-ctx-in or -inctx + chunk_mode = GF_TRUE; + input_ctx = arg_val; + } +#endif + return 0; +} +u32 parse_cryp(char *arg_val, u32 opt) +{ + open_edit = GF_TRUE; + if (!opt) { + crypt = 1; + drm_file = arg_val; + open_edit = GF_TRUE; + return 0; + } + crypt = 2; + if (arg_val && get_file_type_by_ext(arg_val) != 1) { + drm_file = arg_val; + return 0; + } + return 3; +} + +u32 parse_dash_profile(char *arg_val, u32 opt) +{ + if (!stricmp(arg_val, "live") || !stricmp(arg_val, "simple")) dash_profile = GF_DASH_PROFILE_LIVE; + else if (!stricmp(arg_val, "onDemand")) dash_profile = GF_DASH_PROFILE_ONDEMAND; + else if (!stricmp(arg_val, "hbbtv1.5:live") || !stricmp(arg_val, "hbbtv1.5.live")) + dash_profile = GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE; + else if (!stricmp(arg_val, "dashavc264:live") || !stricmp(arg_val, "dashavc264.live")) + dash_profile = GF_DASH_PROFILE_AVC264_LIVE; + else if (!stricmp(arg_val, "dashavc264:onDemand") || !stricmp(arg_val, "dashavc264.onDemand")) + dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND; + else if (!stricmp(arg_val, "dashif.ll")) dash_profile = GF_DASH_PROFILE_DASHIF_LL; + else if (!stricmp(arg_val, "main")) dash_profile = GF_DASH_PROFILE_MAIN; + else if (!stricmp(arg_val, "full")) dash_profile = GF_DASH_PROFILE_FULL; + else { + M4_LOG(GF_LOG_ERROR, ("Unrecognized DASH profile \"%s\" - please check usage\n", arg_val)); + return 2; + } + return 0; +} + +u32 parse_fps(char *arg_val, u32 opt) +{ + u32 ticks, dts_inc; + if (!strcmp(arg_val, "auto")) { + M4_LOG(GF_LOG_WARNING, ("Warning, fps=auto option is deprecated\n")); + } + else if ((sscanf(arg_val, "%u-%u", &ticks, &dts_inc)==2) || (sscanf(arg_val, "%u/%u", &ticks, &dts_inc)==2) ) { + if (!dts_inc) dts_inc = 1; + import_fps.num = ticks; + import_fps.den = dts_inc; } else { - FILE *t; - char szFile[GF_MAX_PATH]; - if (outName) { - strcpy(szFile, outName); + gf_parse_frac(arg_val, &import_fps); + } + return 0; +} + +u32 parse_split(char *arg_val, u32 opt) +{ + u32 scale=1; + char *unit; + switch (opt) { + case 0://-split + unit = arg_val + (u32) (strlen(arg_val) - 1); + if (strchr("Mm", unit[0])) scale = 60; + else if (strchr("Hh", unit[0])) scale = 3600; + if (scale > 1) { + char c = unit[0]; + unit[0] = 0; + split_duration = scale * atof(arg_val); + unit[0] = c; } else { - strcpy(szFile, inName); - strcat(szFile, ".bin"); + split_duration = atof(arg_val); } - t = gf_fopen(szFile, "wb"); - if (!t) { - fprintf(stderr, "Failed to open file %s\n", szFile); - e = GF_IO_ERR; + if (split_duration < 0) split_duration = 0; + split_size = 0; + break; + case 1: //-split-rap, -splitr + split_duration = -1; + split_size = -1; + break; + case 2: //-split-size, -splits + unit = arg_val + (u32) (strlen(arg_val) - 1); + if (strchr("Mm", unit[0])) scale = 1000; + else if (strchr("Gg", unit[0])) scale = 1000000; + if (scale > 1) { + char c = unit[0]; + unit[0] = 0; + split_size = scale * (u32)atoi(arg_val); + unit[0] = c; } else { - if (gf_fwrite(data, data_size, t) != data_size) { - fprintf(stderr, "Failed to write output to file %s\n", szFile); - e = GF_IO_ERR; + split_size = (u32)atoi(arg_val); + } + split_duration = 0; + break; + case 3: //-split-chunk, -splitx + case 4: //-splitz + case 5: //-splitg + case 6: //-splitf + adjust_split_end = opt-3; + if (!strstr(arg_val, ":") && !strstr(arg_val, "-")) { + M4_LOG(GF_LOG_ERROR, ("Chunk extraction usage: \"-split* start:end\" expressed in seconds\n")); + return 2; + } + if (strstr(arg_val, "end")) { + if (strstr(arg_val, "end-")) { + Double dur_end=0; + sscanf(arg_val, "%lf:end-%lf", &split_start, &dur_end); + split_duration = -2 - dur_end; + } else { + sscanf(arg_val, "%lf:end", &split_start); + split_duration = -2; } - gf_fclose(t); + } else { + split_range_str = arg_val; } + split_size = 0; + break; } - gf_free(data); - return e; + return 0; } -#endif /*GPAC_DISABLE_CORE_TOOLS*/ -static u64 do_size_top_boxes(char *inName, char *compress_top_boxes, u32 mode) +u32 parse_brand(char *b, u32 opt) { - FILE *in; - u64 top_size = 0; - Bool do_all = GF_FALSE; - GF_BitStream *bs_in; - if (!compress_top_boxes) return GF_BAD_PARAM; - if (!strcmp(compress_top_boxes, "all")) - do_all = GF_TRUE; - - in = gf_fopen(inName, "rb"); - if (!in) return GF_URL_ERROR; - bs_in = gf_bs_from_file(in, GF_BITSTREAM_READ); - while (gf_bs_available(bs_in)) { - const char *stype; - u32 hdr_size = 8; - u64 lsize = gf_bs_read_u32(bs_in); - u32 type = gf_bs_read_u32(bs_in); - - if (lsize==1) { - lsize = gf_bs_read_u64(bs_in); - hdr_size = 16; - } else if (lsize==0) { - lsize = gf_bs_available(bs_in) + 8; + open_edit = GF_TRUE; + switch (opt) { + case 0: //-brand + major_brand = GF_4CC(b[0], b[1], b[2], b[3]); + if (b[4] == ':') { + if (!strncmp(b+5, "0x", 2)) + sscanf(b+5, "0x%x", &minor_version); + else + minor_version = atoi(b + 5); } - stype = gf_4cc_to_str(type); - if (do_all || strstr(compress_top_boxes, stype)) { - //only count boxes - if (mode==2) { - top_size += 1; - } else { - top_size += lsize; - } + break; + case 1: //-ab + brand_add = (u32*)gf_realloc(brand_add, sizeof(u32) * (nb_alt_brand_add + 1)); + if (!brand_add) return 2; + brand_add[nb_alt_brand_add] = GF_4CC(b[0], b[1], b[2], b[3]); + nb_alt_brand_add++; + break; + case 2: //-rb + brand_rem = (u32*)gf_realloc(brand_rem, sizeof(u32) * (nb_alt_brand_rem + 1)); + if (!brand_rem) return 2; + brand_rem[nb_alt_brand_rem] = GF_4CC(b[0], b[1], b[2], b[3]); + nb_alt_brand_rem++; + break; + } + return 0; +} + +u32 parse_mpegu(char *arg_val, u32 opt) +{ + pack_file = arg_val; + pack_wgt = GF_TRUE; + return 0; +} + +u32 parse_file_info(char *arg_val, u32 opt) +{ + print_info = opt ? 2 : 1; + if (opt==2) { + print_info = 2; + if (arg_val) return 3; + return 0; + } + if (arg_val) { + if (sscanf(arg_val, "%u", &info_track_id) == 1) { + char szTk[20]; + sprintf(szTk, "%u", info_track_id); + if (strcmp(szTk, arg_val)) info_track_id = 0; } - gf_bs_skip_bytes(bs_in, lsize - hdr_size); + if (!info_track_id) return 3; + } + return 0; +} +u32 parse_boxpatch(char *arg_val, u32 opt) +{ + box_patch_filename = arg_val; + char *sep = strchr(box_patch_filename, '='); + if (sep) { + sep[0] = 0; + box_patch_trackID = atoi(box_patch_filename); + sep[0] = '='; + box_patch_filename = sep+1; + } + open_edit = GF_TRUE; + return 0; +} +u32 parse_compress(char *arg_val, u32 opt) +{ + compress_moov = opt ? 2 : 1; + open_edit = GF_TRUE; + return 0; +} + + +u32 parse_dump_udta(char *code, u32 opt) +{ + char *sep; + sep = strchr(code, ':'); + if (sep) { + sep[0] = 0; + dump_udta_track = atoi(code); + sep[0] = ':'; + code = sep + 1; } - gf_bs_del(bs_in); - gf_fclose(in); - return top_size; + if (strlen(code) == 4) { + dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]); + } else if (strlen(code) == 8) { + // hex representation on 8 chars + u32 hex1, hex2, hex3, hex4; + if (sscanf(code, "%02x%02x%02x%02x", &hex1, &hex2, &hex3, &hex4) != 4) { + M4_LOG(GF_LOG_ERROR, ("udta code is either a 4CC or 8 hex chars for non-printable 4CC\n")); + return 2; + } + dump_udta_type = GF_4CC(hex1, hex2, hex3, hex4); + } else { + M4_LOG(GF_LOG_ERROR, ("udta code is either a 4CC or 8 hex chars for non-printable 4CC\n")); + return 2; + } + return 0; } -static GF_Err do_compress_top_boxes(char *inName, char *outName, char *compress_top_boxes, u32 comp_top_box_version, Bool use_lzma) +u32 parse_dump_ts(char *arg_val, u32 opt) { - FILE *in, *out; - u8 *buf; - u32 buf_alloc, comp_size, start_offset; - s32 bytes_comp=0; - s32 bytes_uncomp=0; - GF_Err e = GF_OK; - u64 source_size, dst_size; - u32 orig_box_overhead; - u32 final_box_overhead; - u32 gzip_code = use_lzma ? GF_4CC('l','z','m','a') : GF_4CC('g','z','i','p') ; - u32 nb_added_box_bytes=0; - Bool has_mov = GF_FALSE; - u32 range_idx, nb_ranges=0; - Bool replace_all = !strcmp(compress_top_boxes, "*"); - Bool requires_byte_ranges=GF_FALSE; - GF_BitStream *bs_in, *bs_out; - u32 idx_size=0, nb_moof; - struct _ranges { - u32 size, csize; - } *ranges=NULL; + dump_timestamps = 1; + if (arg_val) { + if (isdigit(arg_val[0])) { + program_number = atoi(arg_val); + } else { + return 3; + } + } + return 0; +} - if (!outName) { - fprintf(stderr, "Missing output file name\n"); - return GF_BAD_PARAM; +u32 parse_ttxt(char *arg_val, u32 opt) +{ + if (opt) //-srt + dump_srt = GF_TRUE; + else + dump_ttxt = GF_TRUE; + + import_subtitle = 1; + trackID = 0; + + if (arg_val && (!strcmp(arg_val, "*") || !strcmp(arg_val, "@") || !strcmp(arg_val, "all")) ) { + trackID = (u32)-1; + } else if (arg_val) { + if (sscanf(arg_val, "%u", &trackID) == 1) { + char szTk[20]; + sprintf(szTk, "%d", trackID); + if (strcmp(szTk, arg_val)) + trackID = 0; + } + if (!trackID) return 3; } + return 0; +} - in = gf_fopen(inName, "rb"); - if (!in) return GF_URL_ERROR; - out = gf_fopen(outName, "wb"); - if (!out) return GF_IO_ERR; +u32 parse_dashlive(char *arg, char *arg_val, u32 opt) +{ + dash_mode = opt ? GF_DASH_DYNAMIC_DEBUG : GF_DASH_DYNAMIC; + dash_live = 1; + if (arg[10] == '=') { + dash_ctx_file = arg + 11; + } + dash_duration = atof(arg_val); + return 0; +} - buf_alloc = 4096; - buf = gf_malloc(buf_alloc); +u32 parse_help(char *arg_val, u32 opt) +{ + if (!arg_val) PrintUsage(); + else if (opt) PrintHelp(arg_val, GF_TRUE, GF_FALSE); + else if (!strcmp(arg_val, "general")) PrintGeneralUsage(); + else if (!strcmp(arg_val, "extract")) PrintExtractUsage(); + else if (!strcmp(arg_val, "split")) PrintSplitUsage(); + else if (!strcmp(arg_val, "dash")) PrintDASHUsage(); + else if (!strcmp(arg_val, "dump")) PrintDumpUsage(); + else if (!strcmp(arg_val, "import")) PrintImportUsage(); + else if (!strcmp(arg_val, "format")) { + M4_LOG(GF_LOG_WARNING, ("deprecated, see [filters documentation](Filters)\n")); + } + else if (!strcmp(arg_val, "hint")) PrintHintUsage(); + else if (!strcmp(arg_val, "encode")) PrintEncodeUsage(); + else if (!strcmp(arg_val, "crypt")) PrintEncryptUsage(); + else if (!strcmp(arg_val, "meta")) PrintMetaUsage(); + else if (!strcmp(arg_val, "swf")) PrintSWFUsage(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + else if (!strcmp(arg_val, "rtp")) { + M4_LOG(GF_LOG_WARNING, ("RTP streaming deprecated in MP4Box, use gpac application\n")); + } + else if (!strcmp(arg_val, "live")) PrintLiveUsage(); +#endif + else if (!strcmp(arg_val, "core")) PrintCoreUsage(); + else if (!strcmp(arg_val, "tags")) PrintTags(); + else if (!strcmp(arg_val, "cicp")) PrintCICP(); + else if (!strcmp(arg_val, "all")) { + PrintGeneralUsage(); + PrintExtractUsage(); + PrintDASHUsage(); + PrintSplitUsage(); + PrintDumpUsage(); + PrintImportUsage(); + PrintHintUsage(); + PrintEncodeUsage(); + PrintEncryptUsage(); + PrintMetaUsage(); + PrintSWFUsage(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + PrintLiveUsage(); +#endif + PrintCoreUsage(); + PrintTags(); + PrintCICP(); + } else if (!strcmp(arg_val, "opts")) { + PrintHelp("@", GF_FALSE, GF_FALSE); + } else { + PrintHelp(arg_val, GF_FALSE, GF_FALSE); + } + return 1; +} - bs_in = gf_bs_from_file(in, GF_BITSTREAM_READ); - source_size = gf_bs_get_size(bs_in); +u32 parse_gendoc(char *name, u32 opt) +{ + u32 i=0; + //gen MD + if (!opt) { + help_flags = GF_PRINTARG_MD | GF_PRINTARG_IS_APP; + helpout = gf_fopen("mp4box-gen-opts.md", "w"); + + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » General"); + fprintf(helpout, "\n"); + fprintf(helpout, "# Syntax\n"); + gf_sys_format_help(helpout, help_flags, "MP4Box [option] input [option] [other_dash_inputs]\n" + " \n" + ); + PrintGeneralUsage(); + PrintEncryptUsage(); + fprintf(helpout, "# Help Options\n"); + while (m4b_usage_args[i].name) { + GF_GPACArg *g_arg = (GF_GPACArg *) &m4b_usage_args[i]; + i++; + gf_sys_print_arg(helpout, help_flags, g_arg, "mp4box-general"); + } + + gf_fclose(helpout); + + helpout = gf_fopen("mp4box-import-opts.md", "w"); + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media Import"); + fprintf(helpout, "\n"); + PrintImportUsage(); + gf_fclose(helpout); + + helpout = gf_fopen("mp4box-dash-opts.md", "w"); + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media DASH"); + fprintf(helpout, "\n"); + PrintDASHUsage(); + gf_fclose(helpout); + + helpout = gf_fopen("mp4box-dump-opts.md", "w"); + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media Dump and Export"); + fprintf(helpout, "\n"); + PrintExtractUsage(); + PrintDumpUsage(); + PrintSplitUsage(); + gf_fclose(helpout); + + helpout = gf_fopen("mp4box-meta-opts.md", "w"); + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Meta and HEIF/IFF"); + fprintf(helpout, "\n"); + PrintMetaUsage(); + gf_fclose(helpout); + + + helpout = gf_fopen("mp4box-scene-opts.md", "w"); + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Scene Description"); + fprintf(helpout, "\n"); + PrintEncodeUsage(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + PrintLiveUsage(); +#endif + PrintSWFUsage(); + gf_fclose(helpout); + + helpout = gf_fopen("mp4box-other-opts.md", "w"); + fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Other Features"); + fprintf(helpout, "\n"); + PrintHintUsage(); + PrintTags(); + gf_fclose(helpout); + } + //gen man + else { + help_flags = GF_PRINTARG_MAN; + helpout = gf_fopen("mp4box.1", "w"); + + + fprintf(helpout, ".TH MP4Box 1 2019 MP4Box GPAC\n"); + fprintf(helpout, ".\n.SH NAME\n.LP\nMP4Box \\- GPAC command-line media packager\n.SH SYNOPSIS\n.LP\n.B MP4Box\n.RI [options] \\ [file] \\ [options]\n.br\n.\n"); + + PrintGeneralUsage(); + PrintExtractUsage(); + PrintDASHUsage(); + PrintSplitUsage(); + PrintDumpUsage(); + PrintImportUsage(); + PrintHintUsage(); + PrintEncodeUsage(); + PrintEncryptUsage(); + PrintMetaUsage(); + PrintSWFUsage(); + PrintTags(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + PrintLiveUsage(); +#endif - bs_out = gf_bs_from_file(out, GF_BITSTREAM_WRITE); + fprintf(helpout, ".SH EXAMPLES\n.TP\nBasic and advanced examples are available at https://wiki.gpac.io/MP4Box\n"); + fprintf(helpout, ".SH MORE\n.LP\nAuthors: GPAC developers, see git repo history (-log)\n" + ".br\nFor bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac\n" + ".br\nbuild: %s\n" + ".br\nCopyright: %s\n.br\n" + ".SH SEE ALSO\n" + ".LP\ngpac(1), MP4Client(1)\n", gf_gpac_version(), gf_gpac_copyright()); - start_offset = 0; - nb_moof = 0; - if (comp_top_box_version==2) { - u32 i; - while (gf_bs_available(bs_in)) { - u32 size = gf_bs_read_u32(bs_in); - u32 type = gf_bs_read_u32(bs_in); - const char *b4cc = gf_4cc_to_str(type); - const char *replace = strstr(compress_top_boxes, b4cc); - - if (start_offset) { - Bool compress = (replace || replace_all) ? 1 : 0; - ranges = gf_realloc(ranges, sizeof(struct _ranges)*(nb_ranges+1)); - ranges[nb_ranges].csize = compress; - ranges[nb_ranges].size = size-8; - nb_ranges++; - } - if (!strcmp(b4cc, "ftyp") || !strcmp(b4cc, "styp")) { - if (!start_offset) start_offset = (u32) gf_bs_get_position(bs_in) + size-8; - } - if (!strcmp(b4cc, "sidx") || !strcmp(b4cc, "ssix")) { - requires_byte_ranges = GF_TRUE; - } - if (!strcmp(b4cc, "moof")) - nb_moof++; + gf_fclose(helpout); + } + return 1; +} - gf_bs_skip_bytes(bs_in, size-8); - } +static Bool arg_parse_res = 0; +u32 mp4box_parse_single_arg_class(int argc, char **argv, char *arg, u32 *arg_index, MP4BoxArg *arg_class) +{ + MP4BoxArg *arg_desc = NULL; + char *arg_val = NULL; + u32 i=0; + while (arg_class[i].name) { + arg_desc = (MP4BoxArg *) &arg_class[i]; + i++; - gf_bs_seek(bs_in, 0); - if (buf_allocname, ' '); + if (sep) { + M4_LOG(GF_LOG_ERROR, ("Invalid arg %s, space not allowed\n", arg_desc->name)); + exit(1); } - gf_bs_read_data(bs_in, buf, start_offset); - gf_bs_write_data(bs_out, buf, start_offset); +#endif + if (!strcmp(arg_desc->name, arg+1)) + break; + if (arg_desc->altname && !strcmp(arg_desc->altname, arg+1)) + break; - if (!requires_byte_ranges) { - nb_ranges = 0; - gf_free(ranges); - ranges = NULL; - } - idx_size = 8 + 4 + 4; - for (i=0; iparse_flags & ARG_IS_FUN2) { + if (!strncmp(arg_desc->name, arg+1, strlen(arg_desc->name) )) + break; } + arg_desc = NULL; } + if (!arg_desc) + return GF_FALSE; - range_idx = 0; - orig_box_overhead = 0; - final_box_overhead = 0; - while (gf_bs_available(bs_in)) { - u32 size = gf_bs_read_u32(bs_in); - u32 type = gf_bs_read_u32(bs_in); - const char *b4cc = gf_4cc_to_str(type); - const u8 *replace = (const u8 *) strstr(compress_top_boxes, b4cc); - if (!strcmp(b4cc, "moov")) has_mov = GF_TRUE; + if (arg_desc->parse_flags & ARG_OPEN_EDIT) open_edit = GF_TRUE; + if (arg_desc->parse_flags & ARG_NEED_SAVE) do_save = GF_TRUE; + if (arg_desc->parse_flags & ARG_NO_INPLACE) no_inplace = GF_TRUE; - if (!replace && !replace_all) { - if (ranges) { - assert(! ranges[range_idx].csize); - range_idx++; - } - gf_bs_write_u32(bs_out, size); - gf_bs_write_u32(bs_out, type); + if (arg_desc->type != GF_ARG_BOOL) { + Bool has_next = GF_TRUE; + if (*arg_index + 1 == (u32) argc) + has_next = GF_FALSE; + else if (argv[*arg_index + 1][0] == '-') { + s32 v; + if (sscanf(argv[*arg_index + 1], "%d", &v)!=1) + has_next = GF_FALSE; + } + if (!has_next && ! (arg_desc->parse_flags & ARG_EMPTY) ) { + M4_LOG(GF_LOG_ERROR, ("Missing argument value for %s - please check usage\n", arg)); + arg_parse_res = 2; + return GF_TRUE; + } - size-=8; - while (size) { - u32 nbytes = size; - if (nbytes>buf_alloc) nbytes=buf_alloc; - gf_bs_read_data(bs_in, buf, nbytes); - gf_bs_write_data(bs_out, buf, nbytes); - size-=nbytes; + if (has_next && (arg_desc->parse_flags & ARG_EMPTY) && (arg_desc->type==GF_ARG_INT)) { + s32 ival; + if (sscanf(argv[*arg_index + 1], "%d", &ival) != 1) { + has_next = GF_FALSE; + arg_val = NULL; } - continue; } - orig_box_overhead += size; - - if (comp_top_box_version != 1) - size-=8; - - if (size>buf_alloc) { - buf_alloc = size; - buf = gf_realloc(buf, buf_alloc); + if (has_next) { + has_next_arg = GF_TRUE; + *arg_index += 1; + arg_val = argv[*arg_index]; } - gf_bs_read_data(bs_in, buf, size); - - if (comp_top_box_version != 1) - replace+=5; + } + if (!arg_desc->arg_ptr) return GF_TRUE; - comp_size = buf_alloc; + if (arg_desc->parse_flags & (ARG_IS_FUN|ARG_IS_FUN2) ) { + u32 res; + if (arg_desc->parse_flags & ARG_PUSH_SYSARGS) + gf_sys_set_args(argc, (const char**) argv); - if (use_lzma) { - e = gf_lz_compress_payload(&buf, size, &comp_size); + if (arg_desc->parse_flags & ARG_IS_FUN) { + parse_arg_fun fun = (parse_arg_fun) arg_desc->arg_ptr; + res = fun(arg_val, arg_desc->argv_val); } else { - e = gf_gz_compress_payload(&buf, size, &comp_size); + parse_arg_fun2 fun2 = (parse_arg_fun2) arg_desc->arg_ptr; + res = fun2(arg, arg_val, arg_desc->argv_val); } - if (e) break; - - if (comp_size>buf_alloc) { - buf_alloc = comp_size; + //rewind, not our arg + if ((res==3) && argv) { + *arg_index -= 1; + res = 0; } - bytes_uncomp += size; - bytes_comp += comp_size; - if (comp_top_box_version==1) - nb_added_box_bytes +=8; - - //write size - gf_bs_write_u32(bs_out, comp_size+8); - //write type - if (comp_top_box_version==1) - gf_bs_write_u32(bs_out, gzip_code); - else - gf_bs_write_data(bs_out, replace, 4); - //write data - gf_bs_write_data(bs_out, buf, comp_size); + arg_parse_res = res; + return GF_TRUE; + } - final_box_overhead += 8+comp_size; + if (arg_desc->parse_flags & ARG_INT_INC) { + * (u32 *) arg_desc->arg_ptr += 1; + return GF_TRUE; + } - if (ranges) { - assert(ranges[range_idx].size == size); - ranges[range_idx].csize = comp_size; - range_idx++; + if (arg_desc->type == GF_ARG_BOOL) { + if (!arg_desc->parse_flags) { + if (arg_desc->argv_val) { + * (u32 *) arg_desc->arg_ptr = arg_desc->argv_val; + } else { + * (Bool *) arg_desc->arg_ptr = GF_TRUE; + } + } else if (arg_desc->parse_flags & ARG_BOOL_REV) { + * (Bool *) arg_desc->arg_ptr = GF_FALSE; + } else if (arg_desc->parse_flags & ARG_HAS_VALUE) { + * (u32 *) arg_desc->arg_ptr = 0; + } else if (arg_desc->parse_flags & ARG_BIT_MASK) { + * (u32 *) arg_desc->arg_ptr |= arg_desc->argv_val; + } else if (arg_desc->parse_flags & ARG_BIT_MASK_REM) { + * (u32 *) arg_desc->arg_ptr &= ~arg_desc->argv_val; + } else if (arg_desc->argv_val) { + * (u32 *) arg_desc->arg_ptr = arg_desc->argv_val; + } else { + * (u32 *) arg_desc->arg_ptr = GF_TRUE; } + return GF_TRUE; } - dst_size = gf_bs_get_position(bs_out); - if (comp_top_box_version==2) { - u32 i; - gf_bs_seek(bs_out, start_offset); - gf_bs_write_u32(bs_out, idx_size); - gf_bs_write_u32(bs_out, GF_4CC('c','m','a','p')); - gf_bs_write_u32(bs_out, gzip_code); - gf_bs_write_u32(bs_out, nb_ranges); - for (i=0; i0xFFFF ? 1 : 0; - gf_bs_write_int(bs_out, ranges[i].csize ? 1 : 0, 1); - gf_bs_write_int(bs_out, large_size ? 1 : 0, 1); - gf_bs_write_int(bs_out, 0, 6); - large_size = large_size ? 32 : 16; - - gf_bs_write_int(bs_out, ranges[i].size, large_size); - if (ranges[i].csize) - gf_bs_write_int(bs_out, ranges[i].csize, large_size); - } - final_box_overhead += idx_size; - nb_added_box_bytes += idx_size; + if (arg_desc->type == GF_ARG_STRING) { + if (arg_desc->parse_flags & ARG_IS_4CC) { + u32 alen = arg_val ? (u32) strlen(arg_val) : 0; + if ((alen<3) || (alen>4)) { + M4_LOG(GF_LOG_ERROR, ("Value for %s must be a 4CC, %s is not - please check usage\n", arg, arg_val)); + arg_parse_res = 2; + return GF_TRUE; + } + * (u32 *) arg_desc->arg_ptr = GF_4CC(arg_val[0], arg_val[1], arg_val[2], arg_val[3]); + return GF_TRUE; + } + * (char **) arg_desc->arg_ptr = arg_val; + return GF_TRUE; } - gf_bs_del(bs_in); - gf_bs_del(bs_out); - gf_fclose(in); - gf_fclose(out); - if (e) { - fprintf(stderr, "Error compressing: %s\n", gf_error_to_string(e)); - return e; + if (!arg_val) { + M4_LOG(GF_LOG_ERROR, ("Missing value for %s - please check usage\n", arg)); + arg_parse_res = 2; + return GF_TRUE; } - if (has_mov) { - u32 i, nb_tracks, nb_samples; - GF_ISOFile *mov; - Double rate, new_rate, duration; - - mov = gf_isom_open(inName, GF_ISOM_OPEN_READ, NULL); - duration = (Double) gf_isom_get_duration(mov); - duration /= gf_isom_get_timescale(mov); - - nb_samples = 0; - nb_tracks = gf_isom_get_track_count(mov); - for (i=0; itype == GF_ARG_DOUBLE) { + Double v = atof(arg_val); + if (arg_desc->parse_flags & ARG_DIV_1000) { + v /= 1000; } - gf_isom_close(mov); - - rate = (Double) source_size; - rate /= duration; - rate /= 1000; - - new_rate = (Double) dst_size; - new_rate /= duration; - new_rate /= 1000; - - - fprintf(stderr, "Log format:\nname\torig\tcomp\tgain\tadded_bytes\torate\tcrate\tsamples\tduration\tobbps\tcbbps\n"); - fprintf(stdout, "%s\t%d\t%d\t%g\t%d\t%g\t%g\t%d\t%g\t%g\t%g\n", inName, bytes_uncomp, bytes_comp, ((Double)(bytes_uncomp-bytes_comp)*100)/bytes_uncomp, nb_added_box_bytes, rate, new_rate, nb_samples, duration, ((Double)orig_box_overhead)/nb_samples, ((Double)final_box_overhead)/nb_samples ); - - fprintf(stderr, "%s Compressing top-level boxes saved %d bytes out of %d (reduced by %g %%) additional bytes %d original rate %g kbps new rate %g kbps, orig %g box bytes/sample final %g bytes/sample\n", inName, bytes_uncomp-bytes_comp, bytes_uncomp, ((Double)(bytes_uncomp-bytes_comp)*100)/bytes_uncomp, nb_added_box_bytes, rate, new_rate, ((Double)orig_box_overhead)/nb_samples, ((Double)final_box_overhead)/nb_samples ); + if ((arg_desc->parse_flags & ARG_NON_ZERO) && !v) { + M4_LOG(GF_LOG_ERROR, ("Value for %s shall not be 0 - please check usage\n", arg)); + arg_parse_res = 2; + return GF_TRUE; + } + * (Double *) arg_desc->arg_ptr = v; + return GF_TRUE; + } + if (arg_desc->type != GF_ARG_INT) { + M4_LOG(GF_LOG_ERROR, ("Unsupported argument type for %s - please report to gpac devs\n", arg)); + arg_parse_res = 2; + return GF_TRUE; + } + if (arg_desc->parse_flags & ARG_64BITS) { + u64 v; + sscanf(arg_val, LLU, &v); + if (arg_desc->parse_flags & ARG_DIV_1000) { + v /= 1000; + } + if ((arg_desc->parse_flags & ARG_NON_ZERO) && !v) { + M4_LOG(GF_LOG_ERROR, ("Value for %s shall not be 0 - please check usage\n", arg)); + arg_parse_res = 2; + return GF_TRUE; + } + * (u64 *) arg_desc->arg_ptr = v; } else { - fprintf(stderr, "Log format:\nname\torig\tcomp\tgain\tadded_bytes\n"); - fprintf(stdout, "%s\t%d\t%d\t%g\t%d\n", inName, bytes_uncomp, bytes_comp, ((Double) (bytes_uncomp - bytes_comp)*100)/(bytes_uncomp), nb_added_box_bytes); + u32 v = atoi(arg_val); + if (arg_desc->parse_flags & ARG_DIV_1000) { + v /= 1000; + } + if ((arg_desc->parse_flags & ARG_NON_ZERO) && !v) { + M4_LOG(GF_LOG_ERROR, ("Value for %s shall not be 0 - please check usage\n", arg)); + arg_parse_res = 2; + return GF_TRUE; + } + * (s32 *) arg_desc->arg_ptr = v; + } + return GF_TRUE; +} - fprintf(stderr, "%s Compressing top-level boxes saved %d bytes out of %d (reduced by %g %%) additional bytes %d\n", inName, bytes_uncomp-bytes_comp, bytes_uncomp, ((Double)(bytes_uncomp-bytes_comp)*100)/bytes_uncomp, nb_added_box_bytes); +Bool mp4box_parse_single_arg(int argc, char **argv, char *arg, u32 *arg_index) +{ + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_gen_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_split_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_dash_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_imp_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_senc_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_crypt_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_hint_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_extr_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_dump_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_meta_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_swf_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_liveenc_args)) return GF_TRUE; + if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_usage_args)) return GF_TRUE; - } - return GF_OK; + return GF_FALSE; } -static GF_Err hash_file(char *name, u32 dump_std) + +u32 mp4box_parse_args(int argc, char **argv) { u32 i; - u8 hash[20]; - GF_Err e = gf_media_get_file_hash(name, hash); - if (e) return e; - if (dump_std==2) { - gf_fwrite(hash, 20, stdout); - } else if (dump_std==1) { - for (i=0; i<20; i++) fprintf(stdout, "%02X", hash[i]); - } - fprintf(stderr, "File hash (SHA-1): "); - for (i=0; i<20; i++) fprintf(stderr, "%02X", hash[i]); - fprintf(stderr, "\n"); - - return GF_OK; -} - - -char outfile[GF_MAX_PATH]; -#ifndef GPAC_DISABLE_SCENE_ENCODER -GF_SMEncodeOptions smenc_opts; -#endif -SDPLine *sdp_lines = NULL; -Double interleaving_time, split_duration, split_start, dash_duration, dash_subduration; -GF_Fraction import_fps; -Bool dash_duration_strict; -MetaAction *metas = NULL; -TrackAction *tracks = NULL; -TSELAction *tsel_acts = NULL; -u64 movie_time, initial_tfdt; -s32 subsegs_per_sidx; -u32 *brand_add = NULL; -u32 *brand_rem = NULL; -const char *split_range_str = NULL; -GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_DEFAULT; -u32 stat_level, hint_flags, info_track_id, import_flags, nb_add, nb_cat, crypt, agg_samples, nb_sdp_ex, max_ptime, split_size, nb_meta_act, nb_track_act, rtp_rate, major_brand, nb_alt_brand_add, nb_alt_brand_rem, old_interleave, car_dur, minor_version, conv_type, nb_tsel_acts, program_number, dump_nal, time_shift_depth, initial_moof_sn, dump_std, import_subtitle, dump_saps, dump_saps_mode, force_new; -GF_DashDynamicMode dash_mode=GF_DASH_STATIC; -#ifndef GPAC_DISABLE_SCENE_DUMP -GF_SceneDumpFormat dump_mode; -#endif -Double mpd_live_duration = 0; -Bool HintIt, needSave, FullInter, Frag, HintInter, dump_rtp, regular_iod, remove_sys_tracks, remove_hint, remove_root_od; -Bool print_sdp, open_edit, dump_cr, force_ocr, encode, do_scene_log, dump_srt, dump_ttxt, do_saf, dump_m2ts, dump_cart, do_hash, verbose, force_cat, align_cat, pack_wgt, single_group, clean_groups, dash_live, no_fragments_defaults, single_traf_per_moof, tfdt_per_traf, hls_clock, do_mpd_rip, merge_vtt_cues, compress_moov, get_nb_tracks; -static char *inName, *outName, *mediaSource, *tmpdir, *input_ctx, *output_ctx, *drm_file, *avi2raw, *cprt, *chap_file, *pes_dump, *itunes_tags, *pack_file, *raw_cat, *seg_name, *dash_ctx_file, *compress_top_boxes, *high_dynamc_range_filename, *use_init_seg, *box_patch_filename; -u32 track_dump_type, dump_isom, dump_timestamps, dump_nal_type; -GF_ISOTrackID trackID; -u32 do_flat, box_patch_trackID=0, print_info; -Bool comp_lzma=GF_FALSE; -Bool freeze_box_order=GF_FALSE; -Bool chap_qt=GF_FALSE; -Bool no_odf_conf=GF_FALSE; -Double min_buffer = 1.5; -u32 comp_top_box_version = 0; -u32 size_top_box = 0; -s32 ast_offset_ms = 0; -u32 fs_dump_flags = 0; -u32 dump_chap = 0; -u32 dump_udta_type = 0; -u32 dump_udta_track = 0; -char **mpd_base_urls = NULL; -u32 nb_mpd_base_urls = 0; -u32 dash_scale = 1000; -Bool insert_utc = GF_FALSE; -const char *udp_dest = NULL; -#ifndef GPAC_DISABLE_MPD -Bool do_mpd = GF_FALSE; -#endif -#ifndef GPAC_DISABLE_SCENE_ENCODER -Bool chunk_mode = GF_FALSE; -#endif -#ifndef GPAC_DISABLE_ISOM_HINTING -Bool HintCopy = GF_FALSE; -Bool hint_no_offset = GF_FALSE; -u32 MTUSize = 1450; -#endif -#ifndef GPAC_DISABLE_CORE_TOOLS -Bool do_bin_xml = GF_FALSE; -#endif -GF_ISOFile *file; -Bool frag_real_time = GF_FALSE; -const char *dash_start_date=NULL; -GF_DASH_ContentLocationMode cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET; -Double mpd_update_time = GF_FALSE; -Bool force_co64 = GF_FALSE; -Bool live_scene = GF_FALSE; -Bool use_mfra = GF_FALSE; -GF_MemTrackerType mem_track = GF_MemTrackerNone; - -Bool dump_iod = GF_FALSE; -GF_DASHPSSHMode pssh_mode = 0; -Bool samplegroups_in_traf = GF_FALSE; -Bool mvex_after_traks = GF_FALSE; -u32 sdtp_in_traf = 0; -Bool daisy_chain_sidx = GF_FALSE; -Bool use_ssix = GF_FALSE; -Bool single_segment = GF_FALSE; -Bool single_file = GF_FALSE; -Bool segment_timeline = GF_FALSE; -u32 segment_marker = GF_FALSE; -GF_DashProfile dash_profile = GF_DASH_PROFILE_AUTO; -const char *dash_profile_extension = NULL; -const char *dash_cues = NULL; -Bool strict_cues = GF_FALSE; -Bool use_url_template = GF_FALSE; -Bool seg_at_rap = GF_FALSE; -Bool frag_at_rap = GF_FALSE; -Bool adjust_split_end = GF_FALSE; -Bool memory_frags = GF_TRUE; -Bool keep_utc = GF_FALSE; -u32 timescale = 0; -Bool has_next_arg=GF_FALSE; -const char *do_wget = NULL; -GF_DashSegmenterInput *dash_inputs = NULL; -u32 nb_dash_inputs = 0; -char *seg_ext = NULL; -char *init_seg_ext = NULL; -const char *dash_title = NULL; -const char *dash_source = NULL; -const char *dash_more_info = NULL; - -FILE *logfile = NULL; -static u32 run_for=0; -static u32 dash_cumulated_time,dash_prev_time,dash_now_time; -static Bool no_cache=GF_FALSE; -static Bool no_loop=GF_FALSE; -static GF_DASH_SplitMode dash_split_mode = GF_DASH_SPLIT_OUT; - -u32 mp4box_cleanup(u32 ret_code) { - if (mpd_base_urls) { - gf_free(mpd_base_urls); - mpd_base_urls = NULL; - } - if (sdp_lines) { - gf_free(sdp_lines); - sdp_lines = NULL; - } - if (metas) { - u32 i; - for (i=0; inb_baseURL) { - for (j = 0; jnb_baseURL; j++) { - gf_free(di->baseURL[j]); - } - gf_free(di->baseURL); - } - if (di->rep_descs) { - for (j = 0; jnb_rep_descs; j++) { - gf_free(di->rep_descs[j]); - } - gf_free(di->rep_descs); - } - if (di->as_descs) { - for (j = 0; jnb_as_descs; j++) { - gf_free(di->as_descs[j]); - } - gf_free(di->as_descs); - } - if (di->as_c_descs) { - for (j = 0; jnb_as_c_descs; j++) { - gf_free(di->as_c_descs[j]); - } - gf_free(di->as_c_descs); - } - if (di->p_descs) { - for (j = 0; jnb_p_descs; j++) { - gf_free(di->p_descs[j]); - } - gf_free(di->p_descs); - } - if (di->representationID) gf_free(di->representationID); - if (di->periodID) gf_free(di->periodID); - if (di->xlink) gf_free(di->xlink); - if (di->seg_template) gf_free(di->seg_template); - if (di->hls_pl) gf_free(di->hls_pl); - if (di->source_opts) gf_free(di->source_opts); - if (di->filter_chain) gf_free(di->filter_chain); - - if (di->roles) { - for (j = 0; jnb_roles; j++) { - gf_free(di->roles[j]); - } - gf_free(di->roles); - } - } - gf_free(dash_inputs); - dash_inputs = NULL; - } - if (logfile) gf_fclose(logfile); - gf_sys_close(); - return ret_code; -} - -u32 mp4box_parse_args_continue(int argc, char **argv, u32 *current_index) -{ - u32 i = *current_index; /*parse our args*/ - { + for (i = 1; i < (u32)argc; i++) { char *arg = argv[i]; - if (!stricmp(arg, "-itags")) { - CHECK_NEXT_ARG - itunes_tags = argv[i + 1]; - i++; - open_edit = GF_TRUE; - } -#ifndef GPAC_DISABLE_ISOM_HINTING - else if (!stricmp(arg, "-hint")) { - open_edit = GF_TRUE; - HintIt = 1; - } - else if (!stricmp(arg, "-unhint")) { - open_edit = GF_TRUE; - remove_hint = 1; - } - else if (!stricmp(arg, "-copy")) HintCopy = 1; - else if (!stricmp(arg, "-no-offset")) hint_no_offset = GF_TRUE; - else if (!stricmp(arg, "-tight")) { - FullInter = 1; - open_edit = GF_TRUE; - needSave = GF_TRUE; - } - else if (!stricmp(arg, "-ocr")) force_ocr = 1; - else if (!stricmp(arg, "-latm")) hint_flags |= GP_RTP_PCK_USE_LATM_AAC; - else if (!stricmp(arg, "-rap") || !stricmp(arg, "-refonly")) { - if ((i + 1 < (u32)argc) && (argv[i + 1][0] != '-')) { - if (sscanf(argv[i + 1], "%d", &trackID) == 1) { - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - tracks[nb_track_act].act_type = !stricmp(arg, "-rap") ? TRAC_ACTION_REM_NON_RAP : TRAC_ACTION_REM_NON_REFS; - tracks[nb_track_act].trackID = trackID; - nb_track_act++; - i++; - open_edit = GF_TRUE; + /*input file(s)*/ + if ((arg[0] != '-') || !stricmp(arg, "--")) { + char *arg_val = arg; + if (!stricmp(arg, "--")) { + if (i+1==(u32)argc) { + M4_LOG(GF_LOG_ERROR, ("Missing arg for `--` - please check usage\n")); + return 2; } + has_next_arg = GF_TRUE; + arg_val = argv[i + 1]; + i++; } - hint_flags |= GP_RTP_PCK_SIGNAL_RAP; - seg_at_rap = 1; - } - else if (!stricmp(arg, "-frag-rap")) { - frag_at_rap = 1; - } - else if (!stricmp(arg, "-mfra")) { - use_mfra = GF_TRUE; - } - else if (!stricmp(arg, "-ts")) hint_flags |= GP_RTP_PCK_SIGNAL_TS; - else if (!stricmp(arg, "-size")) hint_flags |= GP_RTP_PCK_SIGNAL_SIZE; - else if (!stricmp(arg, "-idx")) hint_flags |= GP_RTP_PCK_SIGNAL_AU_IDX; - else if (!stricmp(arg, "-static")) hint_flags |= GP_RTP_PCK_USE_STATIC_ID; - else if (!stricmp(arg, "-multi")) { - hint_flags |= GP_RTP_PCK_USE_MULTI; - if ((i + 1 < (u32)argc) && (sscanf(argv[i + 1], "%u", &max_ptime) == 1)) { - char szPt[20]; - sprintf(szPt, "%u", max_ptime); - if (!strcmp(szPt, argv[i + 1])) i++; - else max_ptime = 0; + if (argc < 3) { + M4_LOG(GF_LOG_ERROR, ("Error - only one input file found as argument, please check usage\n")); + return 2; } - } -#endif - else if (!stricmp(arg, "-mpeg4")) { -#ifndef GPAC_DISABLE_ISOM_HINTING - hint_flags |= GP_RTP_PCK_FORCE_MPEG4; -#endif -#ifndef GPAC_DISABLE_MEDIA_IMPORT - import_flags |= GF_IMPORT_FORCE_MPEG4; -#endif - } -#ifndef GPAC_DISABLE_ISOM_HINTING - else if (!stricmp(arg, "-mtu")) { - CHECK_NEXT_ARG - MTUSize = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-cardur")) { - CHECK_NEXT_ARG - car_dur = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-rate")) { - CHECK_NEXT_ARG - rtp_rate = atoi(argv[i + 1]); - i++; - } -#ifndef GPAC_DISABLE_SENG - else if (!stricmp(arg, "-add-sdp") || !stricmp(arg, "-sdp_ex")) { - char *id; - CHECK_NEXT_ARG - sdp_lines = gf_realloc(sdp_lines, sizeof(SDPLine) * (nb_sdp_ex + 1)); - - id = strchr(argv[i + 1], ':'); - if (id) { - id[0] = 0; - if (sscanf(argv[i + 1], "%u", &sdp_lines[0].trackID) == 1) { - id[0] = ':'; - sdp_lines[nb_sdp_ex].line = id + 1; + else if (inName) { + if (dash_duration) { + if (!nb_dash_inputs) { + dash_inputs = set_dash_input(dash_inputs, inName, &nb_dash_inputs); + } + dash_inputs = set_dash_input(dash_inputs, arg_val, &nb_dash_inputs); } else { - id[0] = ':'; - sdp_lines[nb_sdp_ex].line = argv[i + 1]; - sdp_lines[nb_sdp_ex].trackID = 0; + M4_LOG(GF_LOG_ERROR, ("Error - 2 input names specified, please check usage\n")); + return 2; } } else { - sdp_lines[nb_sdp_ex].line = argv[i + 1]; - sdp_lines[nb_sdp_ex].trackID = 0; + inName = arg_val; } - open_edit = GF_TRUE; - nb_sdp_ex++; - i++; } -#endif /*GPAC_DISABLE_SENG*/ -#endif /*GPAC_DISABLE_ISOM_HINTING*/ - - else if (!stricmp(arg, "-single")) { -#ifndef GPAC_DISABLE_MEDIA_EXPORT - CHECK_NEXT_ARG - track_dump_type = GF_EXPORT_MP4; - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - tracks[nb_track_act].act_type = TRAC_ACTION_RAW_EXTRACT; - tracks[nb_track_act].trackID = atoi(argv[i + 1]); - tracks[nb_track_act].dump_type = GF_EXPORT_MP4; - nb_track_act++; - i++; -#endif + //all deprecated options + else if (!stricmp(arg, "-grab-ts") || !stricmp(arg, "-atsc") || !stricmp(arg, "-rtp")) { + M4_LOG(GF_LOG_ERROR, ("Deprecated fuctionnality `%s` - use gpac application\n", arg)); + return 2; } - else if (!stricmp(arg, "-iod")) regular_iod = 1; - else if (!stricmp(arg, "-flat")) { - open_edit = GF_TRUE; - do_flat = 1; - } - else if (!stricmp(arg, "-keep-utc")) keep_utc = GF_TRUE; - else if (!stricmp(arg, "-new")) force_new = 1; - else if (!stricmp(arg, "-newfs")) { - force_new = 2; - interleaving_time = 0.5; - do_flat = 1; - } - else if (!stricmp(arg, "-timescale")) { - CHECK_NEXT_ARG - timescale = atoi(argv[i + 1]); - open_edit = GF_TRUE; + else if (!stricmp(arg, "-write-buffer")) { + M4_LOG(GF_LOG_WARNING, ("`%s` option deprecated, use `-bs-cache-size`", arg)); + gf_opts_set_key("temp", "bs-cache-size", argv[i + 1]); i++; } - else if (!stricmp(arg, "-udta")) { - CHECK_NEXT_ARG - create_new_track_action(argv[i + 1], &tracks, &nb_track_act, 0); - tracks[nb_track_act - 1].act_type = TRAC_ACTION_SET_UDTA; - open_edit = GF_TRUE; - i++; + else if (!stricmp(arg, "-pssh-moof")) { + M4_LOG(GF_LOG_ERROR, ("`-pssh-moof` option deprecated , use `-pssh` option\n")); + return 2; } - else if (!stricmp(arg, "-add") || !stricmp(arg, "-import") || !stricmp(arg, "-convert")) { - CHECK_NEXT_ARG - if (!stricmp(arg, "-import")) fprintf(stderr, "\tWARNING: \"-import\" is deprecated - use \"-add\"\n"); - else if (!stricmp(arg, "-convert")) fprintf(stderr, "\tWARNING: \"-convert\" is deprecated - use \"-add\"\n"); - nb_add++; - i++; + else if (!stricmp(arg, "-tag-list")) { + M4_LOG(GF_LOG_ERROR, ("`-tag-list` option deprecated, use `-h tags`\n")); + return 2; } - else if (!stricmp(arg, "-cat") || !stricmp(arg, "-catx") || !stricmp(arg, "-catpl")) { - CHECK_NEXT_ARG - nb_cat++; - i++; + else if (!stricmp(arg, "-aviraw")) { + M4_LOG(GF_LOG_ERROR, ("`-aviraw` option deprecated, use `-raw`\n")); + return 2; } - else if (!stricmp(arg, "-time")) { - struct tm time; - CHECK_NEXT_ARG - memset(&time, 0, sizeof(struct tm)); - sscanf(argv[i + 1], "%d/%d/%d-%d:%d:%d", &time.tm_mday, &time.tm_mon, &time.tm_year, &time.tm_hour, &time.tm_min, &time.tm_sec); - time.tm_isdst = 0; - time.tm_year -= 1900; - time.tm_mon -= 1; - open_edit = GF_TRUE; - movie_time = 2082758400; - movie_time += mktime(&time); - i++; + else if (!stricmp(arg, "-avi")) { + M4_LOG(GF_LOG_ERROR, ("`-avi` option deprecated, use `-mux`\n")); + return 2; } - else if (!stricmp(arg, "-force-cat")) force_cat = 1; - else if (!stricmp(arg, "-align-cat")) align_cat = 1; - else if (!stricmp(arg, "-unalign-cat")) align_cat = 0; - else if (!stricmp(arg, "-raw-cat")) { - CHECK_NEXT_ARG - raw_cat = argv[i + 1]; - i++; + else if (!strncmp(arg, "-p=", 3)) { + continue; } - else if (!stricmp(arg, "-rem") || !stricmp(arg, "-disable") || !stricmp(arg, "-enable")) { - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - if (!stricmp(arg, "-enable")) tracks[nb_track_act].act_type = TRAC_ACTION_ENABLE; - else if (!stricmp(arg, "-disable")) tracks[nb_track_act].act_type = TRAC_ACTION_DISABLE; - else tracks[nb_track_act].act_type = TRAC_ACTION_REM_TRACK; - tracks[nb_track_act].trackID = atoi(argv[i + 1]); - open_edit = GF_TRUE; - nb_track_act++; - i++; + + //parse argument + else if (mp4box_parse_single_arg(argc, argv, arg, &i)) { + if (arg_parse_res) + return mp4box_cleanup(arg_parse_res); } - else if (!stricmp(arg, "-set-track-id") || !stricmp(arg, "-swap-track-id")) { - char *sep; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - tracks[nb_track_act].act_type = !stricmp(arg, "-set-track-id") ? TRAC_ACTION_SET_ID : TRAC_ACTION_SWAP_ID; - sep = strchr(argv[i + 1], ':'); - if (!sep) { - fprintf(stderr, "Bad format for -set-track-id - expecting \"id1:id2\" got \"%s\"\n", argv[i + 1]); + //not a MP4Box arg + else { + u32 res = gf_sys_is_gpac_arg(arg); + if (res==0) { + PrintHelp(arg, GF_FALSE, GF_TRUE); return 2; + } else if (res==2) { + i++; } - *sep = 0; - tracks[nb_track_act].trackID = atoi(argv[i + 1]); - *sep = ':'; - sep++; - tracks[nb_track_act].newTrackID = atoi(sep); - open_edit = GF_TRUE; - nb_track_act++; - i++; } - else if (!stricmp(arg, "-par")) { - char szTK[20], *ext; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); + //live scene encoder does not use the unified parsing and should be moved as a scene encoder filter + if (live_scene) return 0; + } + return 0; +} - tracks[nb_track_act].act_type = TRAC_ACTION_SET_PAR; - assert(strlen(argv[i + 1]) + 1 <= sizeof(szTK)); - strncpy(szTK, argv[i + 1], sizeof(szTK)); - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track par - expecting tkID=none or tkID=PAR_NUM:PAR_DEN got %s\n", argv[i + 1]); - return 2; - } - if (!stricmp(ext + 1, "none")) { - tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = 0; - } - else if (!stricmp(ext + 1, "auto")) { - tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = -1; - tracks[nb_track_act].force_par = 1; - } - else if (!stricmp(ext + 1, "force")) { - tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = 1; - tracks[nb_track_act].force_par = 1; - } - else { - if (ext[1]=='w') { - tracks[nb_track_act].rewrite_bs = 1; - ext++; - } - sscanf(ext + 1, "%d", &tracks[nb_track_act].par_num); - ext = strchr(ext + 1, ':'); - if (!ext) { - fprintf(stderr, "Bad format for track par - expecting tkID=PAR_NUM:PAR_DEN got %s\n", argv[i + 1]); - return 2; - } - sscanf(ext + 1, "%d", &tracks[nb_track_act].par_den); - } - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - open_edit = GF_TRUE; - nb_track_act++; - i++; - } - else if (!stricmp(arg, "-clap")) { - char szTK[200], *ext; - TrackAction *tka; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - - tracks[nb_track_act].act_type = TRAC_ACTION_SET_CLAP; - assert(strlen(argv[i + 1]) + 1 <= sizeof(szTK)); - strncpy(szTK, argv[i + 1], sizeof(szTK)); - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track clap - expecting tkID=none or tkID=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd got %s\n", argv[i + 1]); - return 2; - } - tka = &tracks[nb_track_act]; - if (!stricmp(ext + 1, "none")) { - tka->clap_wnum= tka->clap_wden = tka->clap_hnum = tka->clap_hden = tka->clap_honum = tka->clap_hoden = tka->clap_vonum = tka->clap_voden = 0; - } else { - if (sscanf(ext + 1, "%d,%d,%d,%d,%d,%d,%d,%d", &tka->clap_wnum, &tka->clap_wden, &tka->clap_hnum, &tka->clap_hden, &tka->clap_honum, &tka->clap_hoden, &tka->clap_vonum, &tka->clap_voden) != 8) { +/* + END OF OPTION PARSING CODE +*/ - fprintf(stderr, "Bad format for track clap - expecting tkID=none or tkID=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd got %s\n", argv[i + 1]); - return 2; - } - } - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - open_edit = GF_TRUE; - nb_track_act++; - i++; + + +void scene_coding_log(void *cbk, GF_LOG_Level log_level, GF_LOG_Tool log_tool, const char *fmt, va_list vlist) +{ + FILE *logs = cbk; + if (log_tool != GF_LOG_CODING) return; + vfprintf(logs, fmt, vlist); + fflush(logs); +} + + +#ifndef GPAC_DISABLE_ISOM_HINTING + +/* + MP4 File Hinting +*/ + +void SetupClockReferences(GF_ISOFile *file) +{ + u32 i, count, ocr_id; + count = gf_isom_get_track_count(file); + if (count==1) return; + ocr_id = 0; + for (i=0; iOCRESID = ocr_id; + gf_isom_change_mpeg4_description(file, i+1, 1, esd); + gf_odf_desc_del((GF_Descriptor *) esd); + } + } +} + +/*base RTP payload type used (you can specify your own types if needed)*/ +#define BASE_PAYT 96 + +GF_Err HintFile(GF_ISOFile *file, u32 MTUSize, u32 max_ptime, u32 rtp_rate, u32 base_flags, Bool copy_data, Bool interleave, Bool regular_iod, Bool single_group, Bool hint_no_offset) +{ + GF_ESD *esd; + GF_InitialObjectDescriptor *iod; + u32 i, val, res, streamType; + u32 sl_mode, prev_ocr, single_ocr, nb_done, tot_bw, bw, flags, spec_type; + GF_Err e; + char szPayload[30]; + GF_RTPHinter *hinter; + Bool copy, has_iod, single_av; + u8 init_payt = BASE_PAYT; + u32 mtype; + GF_SDP_IODProfile iod_mode = GF_SDP_IOD_NONE; + u32 media_group = 0; + u8 media_prio = 0; + + tot_bw = 0; + prev_ocr = 0; + single_ocr = 1; + + has_iod = 1; + iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file); + if (!iod) has_iod = 0; + else { + if (!gf_list_count(iod->ESDescriptors)) has_iod = 0; + gf_odf_desc_del((GF_Descriptor *) iod); + } + + spec_type = gf_isom_guess_specification(file); + single_av = single_group ? 1 : gf_isom_is_single_av(file); + + /*first make sure we use a systems track as base OCR*/ + for (i=0; idecoderConfig) { + streamType = esd->decoderConfig->streamType; + if (!prev_ocr) { + prev_ocr = esd->OCRESID; + if (!esd->OCRESID) prev_ocr = esd->ESID; + } else if (esd->OCRESID && prev_ocr != esd->OCRESID) { + single_ocr = 0; + } + /*OD MUST BE WITHOUT REFERENCES*/ + if (streamType==1) copy = 1; + } + gf_odf_desc_del((GF_Descriptor *) esd); + + if (!regular_iod && gf_isom_is_track_in_root_od(file, i+1)) { + /*single AU - check if base64 would fit in ESD (consider 33% overhead of base64), otherwise stream*/ + if (gf_isom_get_sample_count(file, i+1)==1) { + GF_ISOSample *samp = gf_isom_get_sample(file, i+1, 1, &val); + if (streamType && samp) { + res = gf_hinter_can_embbed_data(samp->data, samp->dataLength, streamType); + } else { + /*not a system track, we shall hint it*/ + res = 0; + } + if (samp) gf_isom_sample_del(&samp); + if (res) continue; + } + } + if (interleave) sl_mode |= GP_RTP_PCK_USE_INTERLEAVING; + + hinter = gf_hinter_track_new(file, i+1, MTUSize, max_ptime, rtp_rate, sl_mode, init_payt, copy, media_group, media_prio, &e); + + if (!hinter) { + if (e) { + M4_LOG(nb_done ? GF_LOG_WARNING : GF_LOG_ERROR, ("Cannot create hinter (%s)\n", gf_error_to_string(e) )); + if (!nb_done) return e; + } + continue; + } + + if (hint_no_offset) + gf_hinter_track_force_no_offsets(hinter); + + bw = gf_hinter_track_get_bandwidth(hinter); + tot_bw += bw; + flags = gf_hinter_track_get_flags(hinter); + + //set extraction mode for AVC/SVC + gf_isom_set_nalu_extract_mode(file, i+1, GF_ISOM_NALU_EXTRACT_LAYER_ONLY); + + gf_hinter_track_get_payload_name(hinter, szPayload); + M4_LOG(GF_LOG_INFO, ("Hinting track ID %d - Type \"%s:%s\" (%s) - BW %d kbps\n", gf_isom_get_track_id(file, i+1), gf_4cc_to_str(mtype), gf_4cc_to_str(mtype), szPayload, bw)); + if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) M4_LOG(GF_LOG_INFO, ("\tMPEG-4 Systems stream carousel enabled\n")); + e = gf_hinter_track_process(hinter); + + if (!e) e = gf_hinter_track_finalize(hinter, has_iod); + gf_hinter_track_del(hinter); + + if (e) { + M4_LOG(GF_LOG_ERROR, ("Error while hinting (%s)\n", gf_error_to_string(e))); + if (!nb_done) return e; + } + init_payt++; + nb_done ++; + } + + if (has_iod) { + iod_mode = GF_SDP_IOD_ISMA; + if (regular_iod) iod_mode = GF_SDP_IOD_REGULAR; + } else { + iod_mode = GF_SDP_IOD_NONE; + } + gf_hinter_finalize(file, iod_mode, tot_bw); + + if (!single_ocr) + M4_LOG(GF_LOG_WARNING, ("Warning: at least 2 timelines found in the file\nThis may not be supported by servers/players\n\n")); + + return GF_OK; +} + +#endif /*GPAC_DISABLE_ISOM_HINTING*/ + +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_AV_PARSERS) + +static void check_media_profile(GF_ISOFile *file, u32 track) +{ + u8 PL; + GF_ESD *esd = gf_isom_get_esd(file, track, 1); + if (!esd) return; + + switch (esd->decoderConfig->streamType) { + case 0x04: + PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_VISUAL); + if (esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) { + GF_M4VDecSpecInfo vdsi; + gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &vdsi); + if (vdsi.VideoPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, vdsi.VideoPL); + } else if ((esd->decoderConfig->objectTypeIndication==GF_CODECID_AVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_SVC)) { + gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0x15); + } else if (!PL) { + gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0xFE); + } + break; + case 0x05: + PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_AUDIO); + switch (esd->decoderConfig->objectTypeIndication) { + case GF_CODECID_AAC_MPEG2_MP: + case GF_CODECID_AAC_MPEG2_LCP: + case GF_CODECID_AAC_MPEG2_SSRP: + case GF_CODECID_AAC_MPEG4: + { + GF_M4ADecSpecInfo adsi; + gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &adsi); + if (adsi.audioPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, adsi.audioPL); + } + break; + default: + if (!PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0xFE); + } + break; + } + gf_odf_desc_del((GF_Descriptor *) esd); +} +void remove_systems_tracks(GF_ISOFile *file) +{ + u32 i, count; + + count = gf_isom_get_track_count(file); + if (count==1) return; + + /*force PL rewrite*/ + gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0); + gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0); + gf_isom_set_pl_indication(file, GF_ISOM_PL_OD, 1); /*the lib always remove IOD when no profiles are specified..*/ + + for (i=0; ibuf_alloc) nbytes=buf_alloc; + gf_bs_read_data(bs_in, buf, nbytes); + gf_bs_write_data(bs_out, buf, nbytes); + size-=nbytes; + } + continue; + } + orig_box_overhead += size; + + size-=8; + + if (size>buf_alloc) { + buf_alloc = size; + buf = gf_realloc(buf, buf_alloc); + } + gf_bs_read_data(bs_in, buf, size); + + replace+=5; + + comp_size = buf_alloc; + + e = gf_gz_compress_payload(&buf, size, &comp_size); + if (e) break; + + if (comp_size>buf_alloc) { + buf_alloc = comp_size; + } + bytes_uncomp += size; + bytes_comp += comp_size; + + //write size + gf_bs_write_u32(bs_out, comp_size+8); + //write type + gf_bs_write_data(bs_out, replace, 4); + //write data + gf_bs_write_data(bs_out, buf, comp_size); + + final_box_overhead += 8+comp_size; + } + dst_size = gf_bs_get_position(bs_out); + + if (buf) gf_free(buf); + gf_bs_del(bs_in); + gf_bs_del(bs_out); + gf_fclose(in); + gf_fclose(out); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Error compressing: %s\n", gf_error_to_string(e))); + return e; + } + + if (has_mov) { + u32 i, nb_tracks, nb_samples; + GF_ISOFile *mov; + Double rate, new_rate, duration; + + mov = gf_isom_open(inName, GF_ISOM_OPEN_READ, NULL); + duration = (Double) gf_isom_get_duration(mov); + duration /= gf_isom_get_timescale(mov); + + nb_samples = 0; + nb_tracks = gf_isom_get_track_count(mov); + for (i=0; i= to_copy) break; + } + gf_fclose(fin); + gf_fclose(fout); + return mp4box_cleanup(0); +} + +static u32 do_write_udp() +{ + GF_Err e; + u32 res = 0; + GF_Socket *sock = gf_sk_new(GF_SOCK_TYPE_UDP); + u16 port = 2345; + char *sep = strrchr(udp_dest, ':'); + if (sep) { + sep[0] = 0; + port = atoi(sep+1); + } + e = gf_sk_bind( sock, NULL, port, udp_dest, port, 0); + if (sep) sep[0] = ':'; + if (e) { + M4_LOG(GF_LOG_ERROR, ("Failed to bind socket to %s: %s\n", udp_dest, gf_error_to_string(e) )); + res = 1; + } else { + e = gf_sk_send(sock, (u8 *) inName, (u32)strlen(inName)); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Failed to send datagram: %s\n", gf_error_to_string(e) )); + res = 1; } - else if (!stricmp(arg, "-mx")) { - char szTK[200], *ext; - TrackAction *tka; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - - tracks[nb_track_act].act_type = TRAC_ACTION_SET_MX; - assert(strlen(argv[i + 1]) + 1 <= sizeof(szTK)); - strncpy(szTK, argv[i + 1], sizeof(szTK)); - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track matrix - expecting ID=none or ID=M1:M2:M3:M4:M5:M6:M7:M8:M9 got %s\n", argv[i + 1]); - return 2; - } - tka = &tracks[nb_track_act]; - if (!stricmp(ext + 1, "none")) { - memset(tka->mx, 0, sizeof(s32)*9); + } + gf_sk_del(sock); + return res; +} + +#ifndef GPAC_DISABLE_MPD +static u32 convert_mpd() +{ + GF_Err e; + Bool remote = GF_FALSE; + GF_MPD *mpd; + char *mpd_base_url = NULL; + if (!strnicmp(inName, "http://", 7) || !strnicmp(inName, "https://", 8)) { +#if !defined(GPAC_DISABLE_CORE_TOOLS) + e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0, &mpd_base_url); + if (e != GF_OK) { + M4_LOG(GF_LOG_ERROR, ("Cannot retrieve M3U8 (%s): %s\n", inName, gf_error_to_string(e))); + if (mpd_base_url) gf_free(mpd_base_url); + return mp4box_cleanup(1); + } + remote = GF_TRUE; +#else + gf_free(mpd_base_url); + M4_LOG(GF_LOG_ERROR, ("HTTP Downloader disabled in this build\n")); + return mp4box_cleanup(1); +#endif + + if (outName) + strcpy(outfile, outName); + else { + const char *sep = gf_file_basename(inName); + char *ext = gf_file_ext_start(sep); + if (ext) ext[0] = 0; + sprintf(outfile, "%s.mpd", sep); + if (ext) ext[0] = '.'; + } + } else { + if (outName) + strcpy(outfile, outName); + else { + char *dst = strdup(inName); + char *ext = strstr(dst, ".m3u8"); + if (ext) ext[0] = 0; + sprintf(outfile, "%s.mpd", dst); + gf_free(dst); + } + } + + mpd = gf_mpd_new(); + if (!mpd) { + e = GF_OUT_OF_MEM; + M4_LOG(GF_LOG_ERROR, ("[DASH] Error: MPD creation problem %s\n", gf_error_to_string(e))); + mp4box_cleanup(1); + } + FILE *f = gf_fopen(remote ? "tmp_main.m3u8" : inName, "r"); + u32 manif_type = 0; + if (f) { + char szDATA[1000]; + s32 read; + szDATA[999]=0; + read = (s32) gf_fread(szDATA, 999, f); + if (read<0) read = 0; + szDATA[read]=0; + gf_fclose(f); + if (strstr(szDATA, "SmoothStreamingMedia")) + manif_type = 2; + else if (strstr(szDATA, "#EXTM3U")) + manif_type = 1; + } + + if (manif_type==1) { + e = gf_m3u8_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd_base_url ? mpd_base_url : inName, outfile, 0, "video/mp2t", GF_TRUE, use_url_template, segment_timeline, NULL, mpd, GF_TRUE, GF_TRUE); + } else if (manif_type==2) { + e = gf_mpd_smooth_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd, mpd_base_url ? mpd_base_url : inName); + } else { + e = GF_NOT_SUPPORTED; + } + if (!e) + gf_mpd_write_file(mpd, outfile); + + if (mpd) + gf_mpd_del(mpd); + if (mpd_base_url) + gf_free(mpd_base_url); + + if (remote) { + gf_file_delete("tmp_main.m3u8"); + } + if (e != GF_OK) { + M4_LOG(GF_LOG_ERROR, ("Error converting %s (%s) to MPD (%s): %s\n", (manif_type==1) ? "HLS" : "Smooth", inName, outfile, gf_error_to_string(e))); + return mp4box_cleanup(1); + } else { + M4_LOG(GF_LOG_INFO, ("Done converting %s (%s) to MPD (%s)\n", (manif_type==1) ? "HLS" : "Smooth", inName, outfile)); + return mp4box_cleanup(0); + } +} +#endif + +static u32 do_import_sub() +{ + /* We import the subtitle file, + i.e. we parse it and store the content as samples of a 3GPP Timed Text track in an ISO file, + possibly for later export (e.g. when converting SRT to TTXT, ...) */ +#ifndef GPAC_DISABLE_MEDIA_IMPORT + GF_Err e; + GF_MediaImporter import; + /* Prepare the importer */ + file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL); + if (timescale && file) gf_isom_set_timescale(file, timescale); + + memset(&import, 0, sizeof(GF_MediaImporter)); + import.dest = file; + import.in_name = inName; + /* Start the import */ + e = gf_media_import(&import); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Error importing %s: %s\n", inName, gf_error_to_string(e))); + gf_isom_delete(file); + gf_file_delete("ttxt_convert"); + return mp4box_cleanup(1); + } + /* Prepare the export */ + strcpy(outfile, inName); + if (strchr(outfile, '.')) { + while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; + outfile[strlen(outfile)-1] = 0; + } +#ifndef GPAC_DISABLE_ISOM_DUMP + /* Start the export of the track #1, in the appropriate dump type, indicating it's a conversion */ + dump_isom_timed_text(file, gf_isom_get_track_id(file, 1), + dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, + GF_TRUE, + (import_subtitle==2) ? GF_TEXTDUMPTYPE_SVG : (dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT)); +#endif + /* Clean the importer */ + gf_isom_delete(file); + gf_file_delete("ttxt_convert"); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Error converting %s: %s\n", inName, gf_error_to_string(e))); + return mp4box_cleanup(1); + } + return mp4box_cleanup(0); +#else + M4_LOG(GF_LOG_ERROR, ("Feature not supported\n")); + return mp4box_cleanup(1); +#endif +} + +#if !defined(GPAC_DISABLE_MEDIA_IMPORT) && !defined(GPAC_DISABLE_ISOM_WRITE) +static u32 do_add_cat(int argc, char **argv) +{ + GF_Err e; + u32 i, ipass, nb_pass = 1; + char *mux_args=NULL; + char *mux_sid=NULL; + GF_FilterSession *fs = NULL; + if (nb_add) { + + GF_ISOOpenMode open_mode = GF_ISOM_OPEN_EDIT; + if (force_new) { + open_mode = (do_flat || (force_new==2)) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + } else { + FILE *test = gf_fopen(inName, "rb"); + if (!test) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + if (!outName) outName = inName; } else { - s32 res; - if (strstr(ext+1, "0x")) { - res = sscanf(ext + 1, "0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d", &tka->mx[0], &tka->mx[1], &tka->mx[2], &tka->mx[3], &tka->mx[4], &tka->mx[5], &tka->mx[6], &tka->mx[7], &tka->mx[8]); - } else { - res = sscanf(ext + 1, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &tka->mx[0], &tka->mx[1], &tka->mx[2], &tka->mx[3], &tka->mx[4], &tka->mx[5], &tka->mx[6], &tka->mx[7], &tka->mx[8]); - } - if (res != 9) { - fprintf(stderr, "Bad format for track matrix - expecting ID=none or ID=M1:M2:M3:M4:M5:M6:M7:M8:M9 got %s\n", argv[i + 1]); - return 2; + gf_fclose(test); + if (! gf_isom_probe_file(inName) ) { + open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; + if (!outName) outName = inName; } } - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - open_edit = GF_TRUE; - nb_track_act++; - i++; } - else if (!stricmp(arg, "-hdr")) { - CHECK_NEXT_ARG - high_dynamc_range_filename = argv[i + 1]; - i++; + open_edit = do_flat ? GF_FALSE : GF_TRUE; + file = gf_isom_open(inName, open_mode, NULL); + if (!file) { + M4_LOG(GF_LOG_ERROR, ("Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) )); + return mp4box_cleanup(1); } - else if (!stricmp(arg, "-bo")) { - freeze_box_order = GF_TRUE; + + if (freeze_box_order) + gf_isom_freeze_order(file); + + if (do_flat) { + if (major_brand) + gf_isom_set_brand_info(file, major_brand, minor_version); + for (i=0; i0) && (dash_duration > dash_subduration)) { + M4_LOG(GF_LOG_WARNING, ("Warning: -subdur parameter (%g s) should be greater than segment duration (%g s), using segment duration instead\n", dash_subduration, dash_duration)); + dash_subduration = dash_duration; + } + + if (dash_mode && dash_live) + M4_LOG(GF_LOG_INFO, ("Live DASH-ing - press 'q' to quit, 's' to save context and quit\n")); + + if (!dash_ctx_file && dash_live) { + u32 r1; + u64 add = (u64) (intptr_t) &dasher; + add ^= gf_net_get_utc(); + r1 = (u32) add ^ (u32) (add/0xFFFFFFFF); + r1 ^= gf_rand(); + sprintf(szStateFile, "%s/dasher_%X.xml", gf_get_default_cache_directory(), r1 ); + dash_ctx_file = szStateFile; + dyn_state_file = GF_TRUE; + } else if (dash_ctx_file) { + if (force_new) + gf_file_delete(dash_ctx_file); + } + + if (dash_profile==GF_DASH_PROFILE_AUTO) + dash_profile = dash_mode ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_FULL; + + if (!dash_mode) { + time_shift_depth = 0; + mpd_update_time = 0; + } else if ((dash_profile>=GF_DASH_PROFILE_MAIN) && !use_url_template && !mpd_update_time) { + /*use a default MPD update of dash_duration sec*/ + mpd_update_time = (Double) (dash_subduration ? dash_subduration : dash_duration); + M4_LOG(GF_LOG_INFO, ("Using default MPD refresh of %g seconds\n", mpd_update_time)); + } + + if (file && do_save) { + gf_isom_close(file); + file = NULL; + del_file = GF_TRUE; + } + + /*setup dash*/ + dasher = gf_dasher_new(szMPD, dash_profile, NULL, dash_scale, dash_ctx_file); + if (!dasher) { + return mp4box_cleanup(1); + } + e = gf_dasher_set_info(dasher, dash_title, cprt, dash_more_info, dash_source, NULL); + if (e) { + M4_LOG(GF_LOG_ERROR, ("DASH Error: %s\n", gf_error_to_string(e))); + gf_dasher_del(dasher); + return e; + } + + gf_dasher_set_start_date(dasher, dash_start_date); + gf_dasher_set_location(dasher, dash_source); + for (i=0; i < nb_mpd_base_urls; i++) { + e = gf_dasher_add_base_url(dasher, mpd_base_urls[i]); + if (e) { + M4_LOG(GF_LOG_ERROR, ("DASH Error: %s\n", gf_error_to_string(e))); + gf_dasher_del(dasher); + return e; + } + } + + if (segment_timeline && !use_url_template) { + M4_LOG(GF_LOG_WARNING, ("DASH Warning: using -segment-timeline with no -url-template. Forcing URL template.\n")); + use_url_template = GF_TRUE; + } + + e = gf_dasher_enable_url_template(dasher, (Bool) use_url_template, seg_name, seg_ext, init_seg_ext); + if (!e) e = gf_dasher_enable_segment_timeline(dasher, segment_timeline); + if (!e) e = gf_dasher_enable_single_segment(dasher, single_segment); + if (!e) e = gf_dasher_enable_single_file(dasher, single_file); + if (!e) e = gf_dasher_set_switch_mode(dasher, bitstream_switching_mode); + if (!e) e = gf_dasher_set_durations(dasher, dash_duration, interleaving_time, dash_subduration); + if (!e) e = gf_dasher_enable_rap_splitting(dasher, seg_at_rap, frag_at_rap); + if (!e) e = gf_dasher_set_segment_marker(dasher, segment_marker); + if (!e) e = gf_dasher_enable_sidx(dasher, (subsegs_per_sidx>=0) ? 1 : 0, (u32) subsegs_per_sidx, daisy_chain_sidx, use_ssix); + if (!e) e = gf_dasher_set_dynamic_mode(dasher, dash_mode, mpd_update_time, time_shift_depth, mpd_live_duration); + if (!e) e = gf_dasher_set_min_buffer(dasher, min_buffer); + if (!e) e = gf_dasher_set_ast_offset(dasher, ast_offset_ms); + if (!e) e = gf_dasher_enable_memory_fragmenting(dasher, memory_frags); + if (!e) e = gf_dasher_set_initial_isobmf(dasher, initial_moof_sn, initial_tfdt); + if (!e) e = gf_dasher_configure_isobmf_default(dasher, no_fragments_defaults, pssh_mode, samplegroups_in_traf, single_traf_per_moof, tfdt_per_traf, mvex_after_traks, sdtp_in_traf); + if (!e) e = gf_dasher_enable_utc_ref(dasher, insert_utc); + if (!e) e = gf_dasher_enable_real_time(dasher, frag_real_time); + if (!e) e = gf_dasher_set_content_protection_location_mode(dasher, cp_location_mode); + if (!e) e = gf_dasher_set_profile_extension(dasher, dash_profile_extension); + if (!e) e = gf_dasher_enable_cached_inputs(dasher, no_cache); + if (!e) e = gf_dasher_enable_loop_inputs(dasher, ! no_loop); + if (!e) e = gf_dasher_set_split_mode(dasher, dash_split_mode); + if (!e) e = gf_dasher_set_last_segment_merge(dasher, merge_last_seg); + if (!e) e = gf_dasher_set_hls_clock(dasher, hls_clock); + if (!e && dash_cues) e = gf_dasher_set_cues(dasher, dash_cues, strict_cues); + if (!e) e = gf_dasher_print_session_info(dasher, fs_dump_flags); + if (!e) e = gf_dasher_keep_source_utc(dasher, keep_utc); + + for (i=0; i < nb_dash_inputs; i++) { + if (!e) e = gf_dasher_add_input(dasher, &dash_inputs[i]); + } + if (e) { + M4_LOG(GF_LOG_ERROR, ("DASH Setup Error: %s\n", gf_error_to_string(e))); + gf_dasher_del(dasher); + return e; + } + + dash_cumulated_time=0; + + while (1) { + if (run_for && (dash_cumulated_time >= run_for)) { + M4_LOG(GF_LOG_INFO, ("Done running, computing static MPD\n")); + do_abort = 3; + } + + dash_prev_time=gf_sys_clock(); + if (do_abort>=2) { + e = gf_dasher_set_dynamic_mode(dasher, GF_DASH_DYNAMIC_LAST, 0, time_shift_depth, mpd_live_duration); + } + + if (!e) e = gf_dasher_process(dasher); + if (!dash_live && (e==GF_EOS) ) { + M4_LOG(GF_LOG_INFO, ("Nothing to dash, too early ...\n")); + e = GF_OK; + } + + if (do_abort) + break; + + //this happens when reading file while writing them (local playback of the live session ...) + if (dash_live && (e==GF_IO_ERR) ) { + M4_LOG(GF_LOG_WARNING, ("Error dashing file (%s) but continuing ...\n", gf_error_to_string(e) )); + e = GF_OK; + } + + if (e) break; + + if (dash_live) { + u64 ms_in_session=0; + u32 slept = gf_sys_clock(); + u32 sleep_for = gf_dasher_next_update_time(dasher, &ms_in_session); + M4_LOG(GF_LOG_INFO, ("Next generation scheduled in %u ms (DASH time "LLU" ms)\r", sleep_for, ms_in_session)); + if (run_for && (ms_in_session>=run_for)) { + dash_cumulated_time = 1+run_for; + continue; } - if (!scheme_start) { - if (strlen(argv[i + 1]) > 200) { - GF_LOG(GF_LOG_WARNING, GF_LOG_ALL, ("Warning: track kind parameter is too long!")); - } - strncpy(szTK, argv[i + 1], 200); - ext = strchr(szTK, '='); - if (ext && !has_track_id) { - ext[0] = 0; - has_track_id = (sscanf(szTK, "%d", &tracks[nb_track_act].trackID) == 1 ? GF_TRUE : GF_FALSE); - if (has_track_id) { - scheme_start = ext + 1; + + while (1) { + if (gf_prompt_has_input()) { + char c = (char) gf_prompt_get_char(); + if (c=='X') { + do_abort = 1; + break; + } + if (c=='q') { + do_abort = 2; + break; } - else { - scheme_start = szTK; + if (c=='s') { + do_abort = 3; + break; } - ext[0] = '='; } - else { - scheme_start = szTK; + + if (dash_mode == GF_DASH_DYNAMIC_DEBUG) { + break; + } + if (!sleep_for) break; + + gf_sleep(sleep_for/10); + sleep_for = gf_dasher_next_update_time(dasher, NULL); + if (sleep_for<=1) { + dash_now_time=gf_sys_clock(); + dash_cumulated_time+=(dash_now_time-dash_prev_time); + M4_LOG(GF_LOG_INFO, ("Slept for %d ms before generation, dash cumulated time %d\n", dash_now_time - slept, dash_cumulated_time)); + break; } } - ext = strchr(scheme_start, '='); - if (!ext) { - tracks[nb_track_act].kind_scheme = gf_strdup(scheme_start); - } - else { - ext[0] = 0; - tracks[nb_track_act].kind_scheme = gf_strdup(scheme_start); - ext[0] = '='; - tracks[nb_track_act].kind_value = gf_strdup(ext + 1); - } - open_edit = GF_TRUE; - nb_track_act++; - i++; + } else { + break; } - else if (!stricmp(arg, "-delay")) { - char szTK[20], *ext; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); + } - strncpy(szTK, argv[i + 1], sizeof(szTK)-1); - szTK[sizeof(szTK)-1] = 0; - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track delay - expecting tkID=DLAY got %s\n", argv[i + 1]); - return 2; - } - tracks[nb_track_act].act_type = TRAC_ACTION_SET_DELAY; - tracks[nb_track_act].delay_ms = atoi(ext + 1); - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - open_edit = GF_TRUE; - nb_track_act++; - i++; - } - else if (!stricmp(arg, "-ref")) { - char *szTK, *ext; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); + gf_dasher_del(dasher); - szTK = argv[i + 1]; - ext = strchr(szTK, ':'); - if (!ext) { - fprintf(stderr, "Bad format for track reference - expecting tkID:XXXX:refID got %s\n", argv[i + 1]); - return 2; - } - tracks[nb_track_act].act_type = TRAC_ACTION_REFERENCE; - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - ext[0] = ':'; - szTK = ext + 1; - ext = strchr(szTK, ':'); - if (!ext) { - fprintf(stderr, "Bad format for track reference - expecting tkID:XXXX:refID got %s\n", argv[i + 1]); - return 2; - } - ext[0] = 0; - strncpy(tracks[nb_track_act].lang, szTK, 10); - ext[0] = ':'; - tracks[nb_track_act].delay_ms = (s32)atoi(ext + 1); - open_edit = GF_TRUE; - nb_track_act++; - i++; + if (!run_for && dash_ctx_file && (do_abort==3) && (dyn_state_file) && !gf_sys_is_test_mode() ) { + char szName[1024]; + M4_LOG(GF_LOG_INFO, ("Enter file name to save dash context:\n")); + if (scanf("%1023s", szName) == 1) { + gf_file_move(dash_ctx_file, szName); } - else if (!stricmp(arg, "-name")) { - char szTK[GF_MAX_PATH], *ext; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); + } + if (e) M4_LOG(GF_LOG_ERROR, ("Error DASHing file: %s\n", gf_error_to_string(e))); + if (file) gf_isom_delete(file); + if (del_file) + gf_file_delete(inName); - strncpy(szTK, argv[i + 1], sizeof(szTK)-1); - szTK[sizeof(szTK)-1] = 0; - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track name - expecting tkID=name got %s\n", argv[i + 1]); - return 2; - } - tracks[nb_track_act].act_type = TRAC_ACTION_SET_HANDLER_NAME; - tracks[nb_track_act].hdl_name = strchr(argv[i + 1], '=') + 1; - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - ext[0] = '='; - open_edit = GF_TRUE; - nb_track_act++; - i++; + return e; +} + + +static GF_Err do_export_tracks_non_isobmf() +{ + u32 i; + + GF_MediaExporter mdump; + char szFile[GF_MAX_PATH+24]; + for (i=0; iact_type != TRACK_ACTION_RAW_EXTRACT) continue; + memset(&mdump, 0, sizeof(mdump)); + mdump.in_name = inName; + mdump.flags = tka->dump_type; + mdump.trackID = tka->trackID; + mdump.track_type = tka->dump_track_type; + mdump.sample_num = tka->sample_num; + + if (dump_std) { + mdump.out_name = "std"; + } + else if (outName) { + mdump.out_name = outName; + mdump.flags |= GF_EXPORT_MERGE; + } else if (nb_track_act>1) { + sprintf(szFile, "%s_track%d", outfile, mdump.trackID); + mdump.out_name = szFile; + } else { + mdump.out_name = outfile; } -#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_MEDIA_IMPORT) - else if (!stricmp(arg, "-dref")) import_flags |= GF_IMPORT_USE_DATAREF; - else if (!stricmp(arg, "-no-drop") || !stricmp(arg, "-nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; - else if (!stricmp(arg, "-packed")) import_flags |= GF_IMPORT_FORCE_PACKED; - else if (!stricmp(arg, "-sbr")) import_flags |= GF_IMPORT_SBR_IMPLICIT; - else if (!stricmp(arg, "-sbrx")) import_flags |= GF_IMPORT_SBR_EXPLICIT; - else if (!stricmp(arg, "-ps")) import_flags |= GF_IMPORT_PS_IMPLICIT; - else if (!stricmp(arg, "-psx")) import_flags |= GF_IMPORT_PS_EXPLICIT; - else if (!stricmp(arg, "-ovsbr")) import_flags |= GF_IMPORT_OVSBR; - else if (!stricmp(arg, "-fps")) { - CHECK_NEXT_ARG - if (!strcmp(argv[i + 1], "auto")) { fprintf(stderr, "Warning, fps=auto option is deprecated\n"); } - else if (strchr(argv[i + 1], '-')) { - u32 ticks, dts_inc; - sscanf(argv[i + 1], "%u-%u", &ticks, &dts_inc); - if (!dts_inc) dts_inc = 1; - import_fps.num = ticks; - import_fps.den = dts_inc; + mdump.print_stats_graph = fs_dump_flags; + e = gf_media_export(&mdump); + if (e) return e; + } + return GF_OK; +} + + +static GF_Err do_dump_iod() +{ + GF_Err e = GF_OK; + GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)gf_isom_get_root_od(file); + if (!iod) { + M4_LOG(GF_LOG_WARNING, ("File %s has no IOD\n", inName)); + } else { + char szName[GF_MAX_PATH+10]; + FILE *iodf; + sprintf(szName, "%s.iod", outfile); + iodf = gf_fopen(szName, "wb"); + if (!iodf) { + M4_LOG(GF_LOG_ERROR, ("Cannot open destination %s\n", szName)); + e = GF_IO_ERR; + } else { + u8 *desc; + u32 size; + GF_BitStream *bs = gf_bs_from_file(iodf, GF_BITSTREAM_WRITE); + if (gf_odf_desc_write((GF_Descriptor *)iod, &desc, &size)==GF_OK) { + gf_fwrite(desc, size, iodf); + gf_free(desc); } else { - import_fps.num = (s32) (1000 * atof(argv[i + 1])); - import_fps.den = 1000; + M4_LOG(GF_LOG_ERROR, ("Error writing IOD %s\n", szName)); + e = GF_IO_ERR; } - i++; - } - else if (!stricmp(arg, "-agg")) { - CHECK_NEXT_ARG agg_samples = atoi(argv[i + 1]); - i++; - } -#endif /*!defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_MEDIA_IMPORT*/ - else if (!stricmp(arg, "-keep-sys") || !stricmp(arg, "-keepsys")) keep_sys_tracks = 1; - else if (!stricmp(arg, "-ms")) { - CHECK_NEXT_ARG mediaSource = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-mp4")) { - encode = GF_TRUE; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-saf")) { - do_saf = GF_TRUE; - } - else if (!stricmp(arg, "-sclog")) { - do_scene_log = GF_TRUE; - } -#ifndef GPAC_DISABLE_MPD - else if (!stricmp(arg, "-mpd")) { - do_mpd = GF_TRUE; - CHECK_NEXT_ARG - inName = argv[i + 1]; - i++; + gf_bs_del(bs); + gf_fclose(iodf); } -#endif + gf_odf_desc_del((GF_Descriptor*)iod); + } + return e; +} -#ifndef GPAC_DISABLE_SCENE_ENCODER - else if (!stricmp(arg, "-def")) smenc_opts.flags |= GF_SM_ENCODE_USE_NAMES; - else if (!stricmp(arg, "-sync")) { - CHECK_NEXT_ARG - smenc_opts.flags |= GF_SM_ENCODE_RAP_INBAND; - smenc_opts.rap_freq = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-shadow")) { - CHECK_NEXT_ARG - smenc_opts.flags &= ~GF_SM_ENCODE_RAP_INBAND; - smenc_opts.flags |= GF_SM_ENCODE_RAP_SHADOW; - smenc_opts.rap_freq = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-carousel")) { - CHECK_NEXT_ARG - smenc_opts.flags &= ~(GF_SM_ENCODE_RAP_INBAND | GF_SM_ENCODE_RAP_SHADOW); - smenc_opts.rap_freq = atoi(argv[i + 1]); - i++; - } - /*LASeR options*/ - else if (!stricmp(arg, "-resolution")) { - CHECK_NEXT_ARG - smenc_opts.resolution = atoi(argv[i + 1]); - i++; +static GF_Err do_export_tracks() +{ + GF_Err e; + u32 i; + char szFile[GF_MAX_PATH+24]; + GF_MediaExporter mdump; + for (i=0; iact_type != TRACK_ACTION_RAW_EXTRACT) continue; + memset(&mdump, 0, sizeof(mdump)); + mdump.file = file; + mdump.flags = tka->dump_type; + mdump.trackID = tka->trackID; + mdump.sample_num = tka->sample_num; + if (tka->out_name) { + mdump.out_name = tka->out_name; + } else if (outName) { + mdump.out_name = outName; + mdump.flags |= GF_EXPORT_MERGE; + /*don't infer extension on user-given filename*/ + mdump.flags |= GF_EXPORT_NO_FILE_EXT; + } else if (mdump.trackID) { + sprintf(szFile, "%s_track%d", outfile, mdump.trackID); + mdump.out_name = szFile; + } else { + sprintf(szFile, "%s_export", outfile); + mdump.out_name = szFile; } -#ifndef GPAC_DISABLE_SCENE_STATS - else if (!stricmp(arg, "-auto-quant")) { - CHECK_NEXT_ARG - smenc_opts.resolution = atoi(argv[i + 1]); - smenc_opts.auto_quant = 1; - i++; + if (tka->trackID==(u32) -1) { + for (j=0; jtrackID) tk = gf_isom_get_track_by_id(file, meta->trackID); + + switch (meta->act_type) { #ifndef GPAC_DISABLE_ISOM_WRITE - else if (!strcmp(arg, "-crypt")) { - CHECK_NEXT_ARG - crypt = 1; - drm_file = argv[i + 1]; - open_edit = GF_TRUE; - i += 1; - } - else if (!strcmp(arg, "-decrypt")) { - CHECK_NEXT_ARG - crypt = 2; - if (get_file_type_by_ext(argv[i + 1]) != 1) { - drm_file = argv[i + 1]; - i += 1; - } - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-set-kms")) { - char szTK[20], *ext; - CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); - - strncpy(szTK, argv[i + 1], 19); - ext = strchr(szTK, '='); - tracks[nb_track_act].act_type = TRAC_ACTION_SET_KMS_URI; - tracks[nb_track_act].trackID = 0; - if (!strnicmp(argv[i + 1], "all=", 4)) { - tracks[nb_track_act].kms = argv[i + 1] + 4; - } - else if (!ext) { - tracks[nb_track_act].kms = argv[i + 1]; - } - else { - tracks[nb_track_act].kms = ext + 1; - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - ext[0] = '='; + case META_ACTION_SET_TYPE: + /*note: we don't handle file brand modification, this is an author stuff and cannot be guessed from meta type*/ + e = gf_isom_set_meta_type(file, meta->root_meta, tk, meta->meta_4cc); + gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO2, GF_TRUE); + do_save = GF_TRUE; + break; + case META_ACTION_ADD_ITEM: + + if (meta->replace) { + if (!gf_isom_get_meta_item_by_id(file, meta->root_meta, tk, meta->item_id)) { + M4_LOG(GF_LOG_WARNING, ("No item with ID %d, ignoring replace\n", meta->item_id)); + meta->item_id = 0; + } else { + e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id, GF_TRUE, meta->keep_props); + if (e) break; + } } - open_edit = GF_TRUE; - nb_track_act++; - i++; - } - else if (!stricmp(arg, "-split")) { - CHECK_NEXT_ARG - split_duration = atof(argv[i + 1]); - if (split_duration < 0) split_duration = 0; - i++; - split_size = 0; - } - else if (!stricmp(arg, "-split-rap") || !stricmp(arg, "-splitr")) { - CHECK_NEXT_ARG - split_duration = -1; - split_size = -1; - } - else if (!stricmp(arg, "-split-size") || !stricmp(arg, "-splits")) { - CHECK_NEXT_ARG - split_size = (u32)atoi(argv[i + 1]); - i++; - split_duration = 0; - } - else if (!stricmp(arg, "-split-chunk") || !stricmp(arg, "-splitx") || !stricmp(arg, "-splitz")) { - CHECK_NEXT_ARG - if (!strstr(argv[i + 1], ":")) { - fprintf(stderr, "Chunk extraction usage: \"-splitx start:end\" expressed in seconds\n"); - return 2; + + self_ref = !stricmp(meta->szPath, "NULL") || !stricmp(meta->szPath, "this") || !stricmp(meta->szPath, "self"); + e = gf_isom_add_meta_item(file, meta->root_meta, tk, self_ref, self_ref ? NULL : meta->szPath, + meta->szName, + meta->item_id, + meta->item_type, + meta->mime_type, + meta->enc_type, + meta->use_dref ? meta->szPath : NULL, NULL, + meta->image_props); + if (meta->item_refs && gf_list_count(meta->item_refs)) { + u32 ref_i; + for (ref_i = 0; ref_i < gf_list_count(meta->item_refs); ref_i++) { + MetaRef *ref_entry = gf_list_get(meta->item_refs, ref_i); + e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, ref_entry->ref_item_id, ref_entry->ref_type, NULL); + } } - if (strstr(argv[i + 1], "end")) { - if (strstr(argv[i + 1], "end-")) { - Double dur_end=0; - sscanf(argv[i + 1], "%lf:end-%lf", &split_start, &dur_end); - split_duration = -2 - dur_end; + do_save = GF_TRUE; + break; + case META_ACTION_ADD_IMAGE_ITEM: + { + u32 old_tk_count = gf_isom_get_track_count(file); + u32 src_tk_id = 1; + GF_Fraction _frac = {0,0}; + GF_ISOFile *fsrc = file; + self_ref = GF_FALSE; + + tk = 0; + if (meta->image_props && meta->image_props->auto_grid) { + e = GF_OK; + self_ref = GF_TRUE; + } else if (!meta->szPath || (meta->image_props && meta->image_props->sample_num && meta->image_props->use_reference)) { + e = GF_OK; + self_ref = GF_TRUE; + src_tk_id = meta->trackID; + } else if (meta->szPath) { + if (meta->image_props && gf_isom_probe_file(meta->szPath) && !meta->image_props->tile_mode) { + meta->image_props->src_file = gf_isom_open(meta->szPath, GF_ISOM_OPEN_READ, NULL); + e = gf_isom_last_error(meta->image_props->src_file); + fsrc = meta->image_props->src_file; + if (meta->image_props->item_ref_id) + src_tk_id = 0; } else { - sscanf(argv[i + 1], "%lf:end", &split_start); - split_duration = -2; + gf_isom_disable_brand_rewrite(file, GF_TRUE); + e = import_file(file, meta->szPath, 0, _frac, 0, NULL, NULL, NULL, 0); + gf_isom_disable_brand_rewrite(file, GF_FALSE); } + } else { + M4_LOG(GF_LOG_ERROR, ("Missing file name to import\n")); + e = GF_BAD_PARAM; } - else { - if (strchr(argv[i + 1], '-')) { - split_range_str = argv[i + 1]; + if (e == GF_OK) { + u32 meta_type = gf_isom_get_meta_type(file, meta->root_meta, tk); + if (!meta_type) { + e = gf_isom_set_meta_type(file, meta->root_meta, tk, GF_META_ITEM_TYPE_PICT); } else { - sscanf(argv[i + 1], "%lf:%lf", &split_start, &split_duration); - split_duration -= split_start; + if (meta_type != GF_META_ITEM_TYPE_PICT) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Warning: file already has a root 'meta' box of type %s\n", gf_4cc_to_str(meta_type))); + e = GF_BAD_PARAM; + } + } + if (e == GF_OK) { + if (!meta->item_id) { + e = gf_isom_meta_get_next_item_id(file, meta->root_meta, tk, &meta->item_id); + } + if (e == GF_OK) { + if (!src_tk_id && (!meta->image_props || !meta->image_props->item_ref_id) ) { + u32 j; + for (j=0; jreplace) { + if (!gf_isom_get_meta_item_by_id(file, meta->root_meta, tk, meta->item_id)) { + M4_LOG(GF_LOG_WARNING, ("No item with ID %d, ignoring replace\n", meta->item_id)); + meta->item_id = 0; + } else { + e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id, GF_TRUE, meta->keep_props); + } + } + if (e==GF_OK) + e = gf_isom_iff_create_image_item_from_track(file, meta->root_meta, tk, src_tk_id, meta->szName, meta->item_id, meta->image_props, NULL); + + if (e == GF_OK && meta->primary) { + e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); + } + if (e == GF_OK && meta->item_refs && gf_list_count(meta->item_refs)) { + u32 ref_i; + for (ref_i = 0; ref_i < gf_list_count(meta->item_refs); ref_i++) { + MetaRef *ref_entry = gf_list_get(meta->item_refs, ref_i); + e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, ref_entry->ref_item_id, ref_entry->ref_type, NULL); + } + } + if (e == GF_OK && meta->group_type) { + e = gf_isom_meta_add_item_group(file, meta->root_meta, tk, meta->item_id, meta->group_id, meta->group_type); + } + } } } - split_size = 0; - if (!stricmp(arg, "-splitz")) adjust_split_end = 1; - i++; - } - /*meta*/ - else if (!stricmp(arg, "-set-meta")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_TYPE, argv[i + 1]); - nb_meta_act++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-add-item")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_ADD_ITEM, argv[i + 1]); - nb_meta_act++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-add-image")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_ADD_IMAGE_ITEM, argv[i + 1]); - nb_meta_act++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-rem-item")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_REM_ITEM, argv[i + 1]); - nb_meta_act++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-set-primary")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_PRIMARY_ITEM, argv[i + 1]); - nb_meta_act++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-set-xml")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_XML, argv[i + 1]); - nb_meta_act++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-rem-xml")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - if (parse_meta_args(&metas[nb_meta_act], META_ACTION_REM_XML, argv[i + 1])) i++; - nb_meta_act++; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-dump-xml")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_DUMP_XML, argv[i + 1]); - nb_meta_act++; - i++; - } - else if (!stricmp(arg, "-dump-item")) { - metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1)); - parse_meta_args(&metas[nb_meta_act], META_ACTION_DUMP_ITEM, argv[i + 1]); - nb_meta_act++; - i++; - } - else if (!stricmp(arg, "-group-add") || !stricmp(arg, "-group-rem-track") || !stricmp(arg, "-group-rem") ) { - TSELActionType act_type; - if (!stricmp(arg, "-group-rem")) { - act_type = TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP; - } - else if (!stricmp(arg, "-group-rem-track")) { - act_type = TSEL_ACTION_REMOVE_TSEL; - } - else { - act_type = TSEL_ACTION_SET_PARAM; - } - if (parse_tsel_args(&tsel_acts, argv[i + 1], &nb_tsel_acts, act_type) == 0) { - fprintf(stderr, "Invalid group syntax - check usage\n"); - return 2; - } - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-group-clean")) { - clean_groups = 1; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-group-single")) { - single_group = 1; - } - else if (!stricmp(arg, "-package")) { - CHECK_NEXT_ARG - pack_file = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-zmov")) { - compress_moov = GF_TRUE; - } - else if (!stricmp(arg, "-mgt")) { - CHECK_NEXT_ARG - pack_file = argv[i + 1]; - pack_wgt = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-brand")) { - char *b = argv[i + 1]; - CHECK_NEXT_ARG - major_brand = GF_4CC(b[0], b[1], b[2], b[3]); - open_edit = GF_TRUE; - if (b[4] == ':') { - if (!strncmp(b+5, "0x", 2)) - sscanf(b+5, "0x%x", &minor_version); - else - minor_version = atoi(b + 5); - } - i++; - } - else if (!stricmp(arg, "-ab")) { - char *b = argv[i + 1]; - CHECK_NEXT_ARG - brand_add = (u32*)gf_realloc(brand_add, sizeof(u32) * (nb_alt_brand_add + 1)); - brand_add[nb_alt_brand_add] = GF_4CC(b[0], b[1], b[2], b[3]); - nb_alt_brand_add++; - open_edit = GF_TRUE; - i++; - } - else if (!stricmp(arg, "-rb")) { - char *b = argv[i + 1]; - CHECK_NEXT_ARG - brand_rem = (u32*)gf_realloc(brand_rem, sizeof(u32) * (nb_alt_brand_rem + 1)); - brand_rem[nb_alt_brand_rem] = GF_4CC(b[0], b[1], b[2], b[3]); - nb_alt_brand_rem++; - open_edit = GF_TRUE; - i++; - } -#endif - else if (!stricmp(arg, "-languages")) { - PrintLanguages(); - return 1; + if (meta->image_props && meta->image_props->src_file) { + gf_isom_delete(meta->image_props->src_file); + meta->image_props->src_file = NULL; + } else if (!self_ref) { + gf_isom_remove_track(file, old_tk_count+1); + if (do_flat) { + M4_LOG(GF_LOG_ERROR, ("Warning: -flat storage cannot be used when using -add-image on external file\n")); + e = GF_NOT_SUPPORTED; + } + } + do_save = GF_TRUE; } - else if (!stricmp(arg, "-h")) { - gf_sys_set_args(argc, (const char**) argv); - - if (i + 1 == (u32)argc) PrintUsage(); - else if (!strcmp(argv[i + 1], "general")) PrintGeneralUsage(); - else if (!strcmp(argv[i + 1], "extract")) PrintExtractUsage(); - else if (!strcmp(argv[i + 1], "dash")) PrintDASHUsage(); - else if (!strcmp(argv[i + 1], "dump")) PrintDumpUsage(); - else if (!strcmp(argv[i + 1], "import")) PrintImportUsage(); - else if (!strcmp(argv[i + 1], "format")) fprintf(stderr, "deprectaed, see [filters documentation](Filters)\n"); - else if (!strcmp(argv[i + 1], "hint")) PrintHintUsage(); - else if (!strcmp(argv[i + 1], "encode")) PrintEncodeUsage(); - else if (!strcmp(argv[i + 1], "crypt")) PrintEncryptUsage(); - else if (!strcmp(argv[i + 1], "meta")) PrintMetaUsage(); - else if (!strcmp(argv[i + 1], "swf")) PrintSWFUsage(); -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - else if (!strcmp(argv[i + 1], "rtp")) fprintf(stderr, "RTP streaming deprecated in MP4Box, use gpac application\n"); - else if (!strcmp(argv[i + 1], "live")) PrintLiveUsage(); -#endif - else if (!strcmp(argv[i + 1], "core")) PrintCoreUsage(); - else if (!strcmp(argv[i + 1], "all")) { - PrintGeneralUsage(); - PrintExtractUsage(); - PrintDASHUsage(); - PrintDumpUsage(); - PrintImportUsage(); - PrintHintUsage(); - PrintEncodeUsage(); - PrintEncryptUsage(); - PrintMetaUsage(); - PrintSWFUsage(); -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - PrintLiveUsage(); -#endif - PrintCoreUsage(); - } else if (!strcmp(argv[i + 1], "opts")) { - PrintHelp("@", GF_FALSE, GF_FALSE); + break; + case META_ACTION_ADD_IMAGE_DERIVED: + { + u32 meta_type = gf_isom_get_meta_type(file, meta->root_meta, tk); + e = GF_OK; + if (!meta_type) { + e = gf_isom_set_meta_type(file, meta->root_meta, tk, GF_META_ITEM_TYPE_PICT); } else { - PrintHelp(argv[i+1], GF_FALSE, GF_FALSE); + if (meta_type != GF_META_ITEM_TYPE_PICT) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Warning: file already has a root 'meta' box of type %s\n", gf_4cc_to_str(meta_type))); + e = GF_BAD_PARAM; + } } - return 1; - } - else if (!stricmp(arg, "-hx")) { - if (i + 1 == (u32)argc) PrintUsage(); - else PrintHelp(argv[i+1], GF_TRUE, GF_FALSE); - return 1; - } - else if (!strcmp(arg, "-genmd")) { - help_flags = GF_PRINTARG_MD | GF_PRINTARG_IS_APP; - helpout = gf_fopen("mp4box-gen-opts.md", "w"); - - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » General"); - fprintf(helpout, "\n"); - fprintf(helpout, "# Syntax\n"); - gf_sys_format_help(helpout, help_flags, "MP4Box [option] input [option] [other_dash_inputs]\n" - " \n" - ); - PrintGeneralUsage(); - PrintEncryptUsage(); - fprintf(helpout, "# Help Options\n"); - while (m4b_usage_args[i].name) { - GF_GPACArg *g_arg = &m4b_usage_args[i]; - i++; - gf_sys_print_arg(helpout, help_flags, g_arg, "mp4box-general"); + if (e) break; + if (!meta->item_id) { + e = gf_isom_meta_get_next_item_id(file, meta->root_meta, tk, &meta->item_id); + } + if (e == GF_OK && meta->item_type) { + if (meta->item_type == GF_4CC('g','r','i','d')) { + e = gf_isom_iff_create_image_grid_item(file, meta->root_meta, tk, + meta->szName && strlen(meta->szName) ? meta->szName : NULL, + meta->item_id, + meta->image_props); + } else if (meta->item_type == GF_4CC('i','o','v','l')) { + e = gf_isom_iff_create_image_overlay_item(file, meta->root_meta, tk, + meta->szName && strlen(meta->szName) ? meta->szName : NULL, + meta->item_id, + meta->image_props); + } else if (meta->item_type == GF_4CC('i','d','e','n')) { + e = gf_isom_iff_create_image_identity_item(file, meta->root_meta, tk, + meta->szName && strlen(meta->szName) ? meta->szName : NULL, + meta->item_id, + meta->image_props); + } else { + e = GF_NOT_SUPPORTED; + } + if (e) break; + if (meta->primary) { + e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); + if (e) break; + } + if (meta->item_refs && gf_list_count(meta->item_refs)) { + u32 ref_i; + for (ref_i = 0; ref_i < gf_list_count(meta->item_refs); ref_i++) { + MetaRef *ref_entry = gf_list_get(meta->item_refs, ref_i); + e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, ref_entry->ref_item_id, ref_entry->ref_type, NULL); + if (e) break; + } + } } - - gf_fclose(helpout); - - helpout = gf_fopen("mp4box-import-opts.md", "w"); - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media Import"); - fprintf(helpout, "\n"); - PrintImportUsage(); - gf_fclose(helpout); - - helpout = gf_fopen("mp4box-dash-opts.md", "w"); - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media DASH"); - fprintf(helpout, "\n"); - PrintDASHUsage(); - gf_fclose(helpout); - - helpout = gf_fopen("mp4box-dump-opts.md", "w"); - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media Dump and Export"); - fprintf(helpout, "\n"); - PrintExtractUsage(); - PrintDumpUsage(); - gf_fclose(helpout); - - helpout = gf_fopen("mp4box-meta-opts.md", "w"); - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Meta and HEIF/IFF"); - fprintf(helpout, "\n"); - PrintMetaUsage(); - gf_fclose(helpout); - - - helpout = gf_fopen("mp4box-scene-opts.md", "w"); - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Scene Description"); - fprintf(helpout, "\n"); - PrintEncodeUsage(); -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - PrintLiveUsage(); -#endif - PrintSWFUsage(); - gf_fclose(helpout); - - helpout = gf_fopen("mp4box-other-opts.md", "w"); - fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Other Features"); - fprintf(helpout, "\n"); - PrintHintUsage(); - gf_fclose(helpout); - - gf_sys_close(); - return 1; - } else if (!strcmp(arg, "-genman")) { - help_flags = GF_PRINTARG_MAN; - helpout = gf_fopen("mp4box.1", "w"); - - - fprintf(helpout, ".TH MP4Box 1 2019 MP4Box GPAC\n"); - fprintf(helpout, ".\n.SH NAME\n.LP\nMP4Box \\- GPAC command-line media packager\n.SH SYNOPSIS\n.LP\n.B MP4Box\n.RI [options] \\ [file] \\ [options]\n.br\n.\n"); - - PrintGeneralUsage(); - PrintExtractUsage(); - PrintDASHUsage(); - PrintDumpUsage(); - PrintImportUsage(); - PrintHintUsage(); - PrintEncodeUsage(); - PrintEncryptUsage(); - PrintMetaUsage(); - PrintSWFUsage(); -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - PrintLiveUsage(); -#endif - - fprintf(helpout, ".SH EXAMPLES\n.TP\nBasic and advanced examples are available at https://wiki.gpac.io/MP4Box-Introduction\n"); - fprintf(helpout, ".SH MORE\n.LP\nAuthors: GPAC developers, see git repo history (-log)\n" - ".br\nFor bug reports, feature requests, more information and source code, visit http://github.com/gpac/gpac\n" - ".br\nbuild: %s\n" - ".br\nCopyright: %s\n.br\n" - ".SH SEE ALSO\n" - ".LP\ngpac(1), MP4Client(1)\n", gf_gpac_version(), gf_gpac_copyright()); - - gf_fclose(helpout); - gf_sys_close(); - return 1; + do_save = GF_TRUE; } + break; + case META_ACTION_REM_ITEM: + e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id, GF_FALSE, NULL); + do_save = GF_TRUE; + break; + case META_ACTION_SET_PRIMARY_ITEM: + e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); + do_save = GF_TRUE; + break; + case META_ACTION_SET_XML: + case META_ACTION_SET_BINARY_XML: + e = gf_isom_set_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL, 0, (meta->act_type==META_ACTION_SET_BINARY_XML) ? 1 : 0); + do_save = GF_TRUE; + break; + case META_ACTION_REM_XML: + if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) { + e = gf_isom_remove_meta_xml(file, meta->root_meta, tk); + do_save = GF_TRUE; + } else { + M4_LOG(GF_LOG_WARNING, ("No meta box in input file\n")); + e = GF_OK; + } + break; + case META_ACTION_DUMP_ITEM: + if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) { + e = gf_isom_extract_meta_item(file, meta->root_meta, tk, meta->item_id, meta->szPath && strlen(meta->szPath) ? meta->szPath : NULL); + } else { + M4_LOG(GF_LOG_WARNING, ("No meta box in input file\n")); + e = GF_OK; + } + break; +#endif // GPAC_DISABLE_ISOM_WRITE - else if (!stricmp(arg, "-v")) verbose++; - else if (!stricmp(arg, "-tag-list")) { - fprintf(stderr, "Supported iTunes tag modifiers:\n"); - for (i = 0; i < nb_itunes_tags; i++) { - fprintf(stderr, "\t%s\t%s\n", itags[i].name, itags[i].comment); + case META_ACTION_DUMP_XML: + if (gf_isom_has_meta_xml(file, meta->root_meta, tk)) { + e = gf_isom_extract_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL); + } else { + M4_LOG(GF_LOG_WARNING, ("No meta box in input file\n")); + e = GF_OK; } - return 1; + break; + default: + break; } - else if (!live_scene) { - u32 res = gf_sys_is_gpac_arg(arg); - if (res==0) { - PrintHelp(arg, GF_FALSE, GF_TRUE); - return 2; - } else if (res==2) { - i++; + if (meta->item_refs) { + while (gf_list_count(meta->item_refs)) { + gf_free(gf_list_pop_back(meta->item_refs)); } + gf_list_del(meta->item_refs); + meta->item_refs = NULL; } + // meta->image_props is freed in mp4box_cleanup + if (e) return e; } - *current_index = i; - return 0; + return GF_OK; } -Bool mp4box_parse_args(int argc, char **argv) +static GF_Err do_tsel_act() { u32 i; - /*parse our args*/ - for (i = 1; i < (u32)argc; i++) { - char *arg = argv[i]; - /*input file(s)*/ - if ((arg[0] != '-') || !stricmp(arg, "--")) { - char *arg_val = arg; - if (!stricmp(arg, "--")) { - CHECK_NEXT_ARG - arg_val = argv[i + 1]; - i++; - } - if (argc < 3) { - fprintf(stderr, "Error - only one input file found as argument, please check usage\n"); - return 2; + GF_Err e; + for (i=0; i0) { + u32 tk, k; + for (k=0; k<(u32) count; k++) { + gf_isom_get_reference(file, j+1, GF_ISOM_REF_CHAP, k+1, &tk); + if (tk==i+1) { + is_chap = 1; + break; + } + } + if (is_chap) break; } - dash_inputs = set_dash_input(dash_inputs, arg_val, &nb_dash_inputs); + if (is_chap) break; } - else { - fprintf(stderr, "Error - 2 input names specified, please check usage\n"); - return 2; - } - } - else { - inName = arg_val; + /*this is a subtitle track*/ + if (!is_chap) + gf_isom_set_media_type(file, i+1, GF_ISOM_MEDIA_SUBT); } + break; } - else if (!stricmp(arg, "-?")) { - PrintUsage(); - return 1; - } - else if (!stricmp(arg, "-version")) { - PrintVersion(); - return 1; - } - else if (!stricmp(arg, "-sdp")) print_sdp = 1; - else if (!strcmp(argv[i], "-mem-track")) continue; - else if (!strcmp(argv[i], "-mem-track-stack")) continue; - else if (!strcmp(argv[i], "-p")) { - i++; - continue; - } - else if (!strncmp(argv[i], "-p=", 3)) continue; - else if (!stricmp(arg, "-logs") || !strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { - i++; - } - else if (!stricmp(arg, "-tracks")) get_nb_tracks = 1; - else if (!stricmp(arg, "-info") || !stricmp(arg, "-infon")) { - print_info = 1; - if ((i + 1<(u32)argc) && (sscanf(argv[i + 1], "%u", &info_track_id) == 1)) { - char szTk[20]; - sprintf(szTk, "%u", info_track_id); - if (!strcmp(szTk, argv[i + 1])) i++; - else info_track_id = 0; + } + gf_isom_set_brand_info(file, ipod_major_brand, 1); + gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_MP42, GF_TRUE); + do_save = GF_TRUE; +} + +static GF_Err do_track_act() +{ + u32 j; + for (j=0; jtrackID ? gf_isom_get_track_by_id(file, tka->trackID) : 0; - if (!stricmp(arg, "-infon")) print_info = 2; + timescale = gf_isom_get_timescale(file); + switch (tka->act_type) { + case TRACK_ACTION_REM_TRACK: + e = gf_isom_remove_track(file, track); + if (e) { + M4_LOG(GF_LOG_ERROR, ("Error Removing track ID %d: %s\n", tka->trackID, gf_error_to_string(e))); + } else { + M4_LOG(GF_LOG_INFO, ("Removing track ID %d\n", tka->trackID)); } - else { - info_track_id = 0; + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_LANGUAGE: + for (i=0; ilang); + if (e) return e; + do_save = GF_TRUE; } - } - else if (!stricmp(arg, "-grab-ts")) { - fprintf(stderr, "Deprecated option - use gpac application\n"); - return mp4box_cleanup(2); - } - else if (!stricmp(arg, "-atsc")) { - fprintf(stderr, "Deprecated option - use gpac application\n"); - return mp4box_cleanup(2); - } -#if !defined(GPAC_DISABLE_CORE_TOOLS) - else if (!stricmp(arg, "-wget")) { - CHECK_NEXT_ARG - do_wget = argv[i + 1]; - i++; - } -#endif - /*******************************************************************************/ - else if (!stricmp(arg, "-dvbhdemux")) { - dvbhdemux = GF_TRUE; - } - /********************************************************************************/ -#ifndef GPAC_DISABLE_MEDIA_EXPORT - else if (!stricmp(arg, "-raw")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NATIVE); - i++; - } - else if (!stricmp(arg, "-raw-layer")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER); - i++; - } - else if (!stricmp(arg, "-qcp")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP); - i++; - } - else if (!stricmp(arg, "-aviraw")) { - CHECK_NEXT_ARG - if (argv[i + 1] && !stricmp(argv[i + 1], "video")) trackID = 1; - else if (argv[i + 1] && !stricmp(argv[i + 1], "audio")) { - if (strlen(argv[i + 1]) == 5) trackID = 2; - else trackID = 1 + atoi(argv[i + 1] + 5); - } else { - fprintf(stderr, "Usage: \"-aviraw video\" or \"-aviraw audio\"\n"); - return 2; + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_KIND: + for (i=0; ikind_scheme, tka->kind_value); + if (e) return e; + do_save = GF_TRUE; } - track_dump_type = GF_EXPORT_AVI_NATIVE; - i++; - } - else if (!stricmp(arg, "-raws")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_RAW_SAMPLES); - i++; - } - else if (!stricmp(arg, "-nhnt")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NHNT); - i++; - } - else if (!stricmp(arg, "-nhml")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NHML); - i++; - } - else if (!stricmp(arg, "-webvtt-raw")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_WEBVTT_META); - i++; - } - else if (!stricmp(arg, "-six")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_SIX); - i++; - } - else if (!stricmp(arg, "-avi")) { - CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_AVI); - if (tracks[nb_track_act-1].trackID) - i++; - } -#endif /*GPAC_DISABLE_MEDIA_EXPORT*/ -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - else if (!stricmp(arg, "-rtp")) { - fprintf(stderr, "Deprecated option - use gpac application\n"); - return mp4box_cleanup(2); - } - else if (!stricmp(arg, "-live")) { - live_scene = GF_TRUE; - } -#endif - else if (!stricmp(arg, "-diod")) { - dump_iod = GF_TRUE; - } -#ifndef GPAC_DISABLE_VRML - else if (!stricmp(arg, "-node")) { - CHECK_NEXT_ARG - PrintNode(argv[i + 1], 0); - return 1; - } - else if (!stricmp(arg, "-xnode")) { - CHECK_NEXT_ARG - PrintNode(argv[i + 1], 1); - return 1; - } - else if (!stricmp(arg, "-nodes") || !stricmp(arg, "-nodex")) { - PrintBuiltInNodes(0, !stricmp(arg, "-nodex") ? GF_TRUE : GF_FALSE); - return 1; - } - else if (!stricmp(arg, "-xnodes") || !stricmp(arg, "-xnodex")) { - PrintBuiltInNodes(1, !stricmp(arg, "-xnodex") ? GF_TRUE : GF_FALSE); - return 1; - } -#endif -#ifndef GPAC_DISABLE_SVG - else if (!stricmp(arg, "-snodes")) { - PrintBuiltInNodes(2, GF_FALSE); - return 1; - } -#endif - else if (!stricmp(arg, "-boxcov")) { - gf_sys_set_args(argc, (const char **) argv); - PrintBuiltInBoxes(GF_TRUE); - return 1; - } else if (!stricmp(arg, "-boxes")) { - PrintBuiltInBoxes(GF_FALSE); - return 1; - } - else if (!stricmp(arg, "-std")) dump_std = 2; - else if (!stricmp(arg, "-stdb")) dump_std = 1; - else if (!stricmp(arg, "-fstat")) fs_dump_flags |= 1; - else if (!stricmp(arg, "-fgraph")) fs_dump_flags |= 1<<1; - -#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_SCENE_DUMP) - else if (!stricmp(arg, "-keep-ods")) no_odf_conf = GF_TRUE; - else if (!stricmp(arg, "-bt")) dump_mode = GF_SM_DUMP_BT; - else if (!stricmp(arg, "-xmt")) dump_mode = GF_SM_DUMP_XMTA; - else if (!stricmp(arg, "-wrl")) dump_mode = GF_SM_DUMP_VRML; - else if (!stricmp(arg, "-x3dv")) dump_mode = GF_SM_DUMP_X3D_VRML; - else if (!stricmp(arg, "-x3d")) dump_mode = GF_SM_DUMP_X3D_XML; - else if (!stricmp(arg, "-lsr")) dump_mode = GF_SM_DUMP_LASER; - else if (!stricmp(arg, "-svg")) dump_mode = GF_SM_DUMP_SVG; -#endif /*defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_SCENE_DUMP)*/ - - else if (!stricmp(arg, "-stat")) stat_level = 1; - else if (!stricmp(arg, "-stats")) stat_level = 2; - else if (!stricmp(arg, "-statx")) stat_level = 3; - else if (!stricmp(arg, "-diso")) dump_isom = 1; - else if (!stricmp(arg, "-dxml")) dump_isom = 2; - else if (!stricmp(arg, "-disox")) dump_isom = 3; - else if (!stricmp(arg, "-mergevtt")) merge_vtt_cues = GF_TRUE; - else if (!stricmp(arg, "-dump-cover")) dump_cart = 1; - else if (!stricmp(arg, "-dump-chap")) dump_chap = 1; - else if (!stricmp(arg, "-dump-chap-ogg")) dump_chap = 2; - else if (!stricmp(arg, "-dump-chap-zoom")) dump_chap = 3; - else if (!stricmp(arg, "-hash")) do_hash = GF_TRUE; - else if (!strnicmp(arg, "-comp", 5)) { - CHECK_NEXT_ARG - - if (strchr(arg, 'x')) comp_top_box_version = 1; - else if (strchr(arg, 'f')) comp_top_box_version = 2; - - if (strchr(arg, 'l')) comp_lzma = GF_TRUE; - - compress_top_boxes = argv[i + 1]; - i++; - } - else if (!strnicmp(arg, "-topsize", 8)) { - CHECK_NEXT_ARG - size_top_box = 1; - compress_top_boxes = argv[i + 1]; - i++; - } - else if (!strnicmp(arg, "-topcount", 8)) { - CHECK_NEXT_ARG - size_top_box = 2; - compress_top_boxes = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-mpd-rip")) do_mpd_rip = GF_TRUE; - else if (!strcmp(arg, "-init-seg")) { - CHECK_NEXT_ARG - use_init_seg = argv[i + 1]; - i += 1; - } + do_save = GF_TRUE; + break; + case TRACK_ACTION_REM_KIND: + for (i=0; ikind_scheme, tka->kind_value); + if (e) return e; + do_save = GF_TRUE; + } + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_DELAY: + if (tka->delay.num && tka->delay.den) { + u64 tk_dur; -#ifndef GPAC_DISABLE_CORE_TOOLS - else if (!stricmp(arg, "-bin")) do_bin_xml = GF_TRUE; -#endif - else if (!stricmp(arg, "-dump-udta")) { - char *sep, *code; - CHECK_NEXT_ARG - sep = strchr(argv[i + 1], ':'); - if (sep) { - sep[0] = 0; - dump_udta_track = atoi(argv[i + 1]); - sep[0] = ':'; - code = &sep[1]; + e = gf_isom_remove_edits(file, track); + if (e) return e; + tk_dur = gf_isom_get_track_duration(file, track); + if (gf_isom_get_edits_count(file, track)) + do_save = GF_TRUE; + if (tka->delay.num>0) { + //cast to u64, delay_ms * timescale can be quite big before / 1000 + e = gf_isom_append_edit(file, track, ((u64) tka->delay.num) * timescale / tka->delay.den, 0, GF_ISOM_EDIT_EMPTY); + if (e) return e; + e = gf_isom_append_edit(file, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); + if (e) return e; + do_save = GF_TRUE; + } else { + //cast to u64, delay_ms * timescale can be quite big before / 1000 + u64 to_skip = ((u64) -tka->delay.num) * timescale / tka->delay.den; + if (to_skipdelay.num) * gf_isom_get_media_timescale(file, track) / tka->delay.den; + e = gf_isom_append_edit(file, track, tk_dur-to_skip, media_time, GF_ISOM_EDIT_NORMAL); + if (e) return e; + do_save = GF_TRUE; + } else { + M4_LOG(GF_LOG_WARNING, ("Warning: request negative delay longer than track duration - ignoring\n")); + } + } + } else if (gf_isom_get_edits_count(file, track)) { + e = gf_isom_remove_edits(file, track); + if (e) return e; + do_save = GF_TRUE; } - else { - code = argv[i + 1]; + break; + case TRACK_ACTION_SET_KMS_URI: + for (i=0; ikms); + if (e) return e; + do_save = GF_TRUE; + } + break; + case TRACK_ACTION_SET_ID: + if (!tka->trackID && (gf_isom_get_track_count(file) == 1)) { + M4_LOG(GF_LOG_WARNING, ("Warning: track id is not specified, but file has only one track - assume that you want to change id for this track\n")); + track = 1; } - if (strlen(code) == 4) { - dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]); - } else if (strlen(code) == 8) { - // hex representation on 8 chars - u32 hex1, hex2, hex3, hex4; - if (sscanf(code, "%02x%02x%02x%02x", &hex1, &hex2, &hex3, &hex4) != 4) { - fprintf(stderr, "udta code is either a 4CC or 8 hex chars for non-printable 4CC\n"); - return mp4box_cleanup(1); + if (track) { + u32 newTrack; + newTrack = gf_isom_get_track_by_id(file, tka->newTrackID); + if (newTrack != 0) { + M4_LOG(GF_LOG_WARNING, ("Cannot set track id with value %d because a track already exists - ignoring", tka->newTrackID)); + } else { + e = gf_isom_set_track_id(file, track, tka->newTrackID); + if (e) return e; + do_save = GF_TRUE; } - dump_udta_type = GF_4CC(hex1, hex2, hex3, hex4); } else { - fprintf(stderr, "udta code is either a 4CC or 8 hex chars for non-printable 4CC\n"); - return mp4box_cleanup(1); + M4_LOG(GF_LOG_WARNING, ("Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID)); } - i++; - } - else if (!stricmp(arg, "-dmp4")) { - dump_isom = 1; - fprintf(stderr, "WARNING: \"-dmp4\" is deprecated - use \"-diso\" option\n"); - } - else if (!stricmp(arg, "-drtp")) dump_rtp = 1; - else if (!stricmp(arg, "-dts")) { - dump_timestamps = 1; - if (((i + 1<(u32)argc) && inName) || (i + 2<(u32)argc)) { - if (isdigit(argv[i + 1][0])) { - program_number = atoi(argv[i + 1]); - i++; + break; + case TRACK_ACTION_SWAP_ID: + if (track) { + u32 tk1, tk2; + tk1 = gf_isom_get_track_by_id(file, tka->trackID); + tk2 = gf_isom_get_track_by_id(file, tka->newTrackID); + if (!tk1 || !tk2) { + M4_LOG(GF_LOG_WARNING, ("Error: Cannot swap track IDs because not existing - ignoring")); + } else { + e = gf_isom_set_track_id(file, tk2, 0); + if (e) return e; + e = gf_isom_set_track_id(file, tk1, tka->newTrackID); + if (e) return e; + e = gf_isom_set_track_id(file, tk2, tka->trackID); + if (e) return e; + do_save = GF_TRUE; } + } else { + M4_LOG(GF_LOG_WARNING, ("Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID)); } - } - else if (!stricmp(arg, "-dtsx")) { - dump_timestamps = 2; - } - else if (!stricmp(arg, "-dtsc")) { - dump_timestamps = 3; - } - else if (!stricmp(arg, "-dtsxc")) { - dump_timestamps = 4; - } - else if (!strnicmp(arg, "-dnal", 5)) { - CHECK_NEXT_ARG - dump_nal = atoi(argv[i + 1]); - if (arg[5] == 'c') dump_nal_type |= 1; - else if (arg[5] == 'd') dump_nal_type |= 2; - else if (arg[5] == 'x') dump_nal_type |= 2|1; - i++; - } - else if (!strnicmp(arg, "-dsap", 5)) { - CHECK_NEXT_ARG - dump_saps = atoi(argv[i + 1]); - if (!stricmp(arg, "-dsaps")) dump_saps_mode = 1; - else if (!stricmp(arg, "-dsapc")) dump_saps_mode = 2; - else if (!stricmp(arg, "-dsapd")) dump_saps_mode = 3; - else if (!stricmp(arg, "-dsapp")) dump_saps_mode = 4; - else dump_saps_mode = 0; - i++; - } - else if (!stricmp(arg, "-dcr")) dump_cr = 1; - else if (!stricmp(arg, "-ttxt") || !stricmp(arg, "-srt")) { - if ((i + 1<(u32)argc) && (sscanf(argv[i + 1], "%u", &trackID) == 1)) { - char szTk[20]; - sprintf(szTk, "%d", trackID); - if (!strcmp(szTk, argv[i + 1])) i++; - else trackID = 0; - } - else if ((i + 1<(u32)argc) && !strcmp(argv[i + 1], "*")) { - trackID = (u32)-1; - i++; + break; + case TRACK_ACTION_SET_PAR: + e = gf_media_change_par(file, track, tka->par_num, tka->par_den, tka->force_par, tka->rewrite_bs); + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_CLAP: + e = gf_isom_set_clean_aperture(file, track, 1, tka->clap_wnum, tka->clap_wden, tka->clap_hnum, tka->clap_hden, tka->clap_honum, tka->clap_hoden, tka->clap_vonum, tka->clap_voden); + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_MX: + e = gf_isom_set_track_matrix(file, track, tka->mx); + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_HANDLER_NAME: + e = gf_isom_set_handler_name(file, track, tka->hdl_name); + do_save = GF_TRUE; + break; + case TRACK_ACTION_ENABLE: + if (!gf_isom_is_track_enabled(file, track)) { + e = gf_isom_set_track_enabled(file, track, GF_TRUE); + do_save = GF_TRUE; } - else { - trackID = 0; + break; + case TRACK_ACTION_DISABLE: + if (gf_isom_is_track_enabled(file, track)) { + e = gf_isom_set_track_enabled(file, track, GF_FALSE); + do_save = GF_TRUE; } -#ifdef GPAC_DISABLE_ISOM_WRITE - if (trackID) { - fprintf(stderr, "Error: Read-Only version - subtitle conversion not available\n"); - return 2; + break; + case TRACK_ACTION_REFERENCE: + e = gf_isom_set_track_reference(file, track, GF_4CC(tka->lang[0], tka->lang[1], tka->lang[2], tka->lang[3]), tka->newTrackID); + do_save = GF_TRUE; + break; + case TRACK_ACTION_REM_NON_RAP: + e = gf_media_remove_non_rap(file, track, GF_FALSE); + do_save = GF_TRUE; + break; + case TRACK_ACTION_REM_NON_REFS: + e = gf_media_remove_non_rap(file, track, GF_TRUE); + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_UDTA: + e = set_file_udta(file, track, tka->udta_type, tka->string ? tka->string : tka->src_name , tka->sample_num ? GF_TRUE : GF_FALSE, tka->string ? GF_TRUE : GF_FALSE); + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_EDITS: + e = apply_edits(file, track, tka->string); + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_TIME: + if (!tka->trackID) { + e = gf_isom_set_creation_time(file, tka->time, tka->time); + if (e) return e; + for (i=0; itime, tka->time); + if (e) return e; + } + } else { + e = gf_isom_set_track_creation_time(file, track, tka->time, tka->time); } -#endif //GPAC_DISABLE_ISOM_WRITE - if (!stricmp(arg, "-ttxt")) dump_ttxt = GF_TRUE; - else dump_srt = GF_TRUE; - import_subtitle = 1; - } - else if (!stricmp(arg, "-dm2ts")) { - dump_m2ts = 1; - if (((i + 1<(u32)argc) && inName) || (i + 2<(u32)argc)) { - if (argv[i + 1][0] != '-') pes_dump = argv[i + 1]; - i++; + do_save = GF_TRUE; + break; + case TRACK_ACTION_SET_MEDIA_TIME: + for (i=0; itime, tka->time); + if (e) return e; } + do_save = GF_TRUE; + break; + default: + break; } + if (e) return e; + } + return GF_OK; +} -#ifndef GPAC_DISABLE_SWF_IMPORT - /*SWF importer options*/ - else if (!stricmp(arg, "-global")) swf_flags |= GF_SM_SWF_STATIC_DICT; - else if (!stricmp(arg, "-no-ctrl")) swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; - else if (!stricmp(arg, "-no-text")) swf_flags |= GF_SM_SWF_NO_TEXT; - else if (!stricmp(arg, "-no-font")) swf_flags |= GF_SM_SWF_NO_FONT; - else if (!stricmp(arg, "-no-line")) swf_flags |= GF_SM_SWF_NO_LINE; - else if (!stricmp(arg, "-no-grad")) swf_flags |= GF_SM_SWF_NO_GRADIENT; - else if (!stricmp(arg, "-quad")) swf_flags |= GF_SM_SWF_QUAD_CURVE; - else if (!stricmp(arg, "-xlp")) swf_flags |= GF_SM_SWF_SCALABLE_LINE; - else if (!stricmp(arg, "-ic2d")) swf_flags |= GF_SM_SWF_USE_IC2D; - else if (!stricmp(arg, "-same-app")) swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; - else if (!stricmp(arg, "-flatten")) { - CHECK_NEXT_ARG - swf_flatten_angle = (Float)atof(argv[i + 1]); - i++; - } -#endif -#ifndef GPAC_DISABLE_ISOM_WRITE - else if (!stricmp(arg, "-isma")) { - conv_type = GF_ISOM_CONV_TYPE_ISMA; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-3gp")) { - conv_type = GF_ISOM_CONV_TYPE_3GPP; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-ipod")) { - conv_type = GF_ISOM_CONV_TYPE_IPOD; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-psp")) { - conv_type = GF_ISOM_CONV_TYPE_PSP; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-ismax")) { - conv_type = GF_ISOM_CONV_TYPE_ISMA_EX; - open_edit = GF_TRUE; - } +static GF_Err do_itunes_tag() +{ + GF_Err e; + char *itunes_data = NULL; + char *tags = itunes_tags; + + if (gf_file_exists(itunes_tags)) { + u32 len; + e = gf_file_load_data(itunes_tags, (u8 **) &itunes_data, &len); + if (e) return e; + tags = itunes_data; + } - else if (!stricmp(arg, "-no-sys") || !stricmp(arg, "-nosys")) { - remove_sys_tracks = 1; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-no-iod")) { - remove_root_od = 1; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-out")) { - CHECK_NEXT_ARG outName = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-tmp")) { - CHECK_NEXT_ARG tmpdir = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-co64")) { - force_co64 = GF_TRUE; - open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-write-buffer")) { - CHECK_NEXT_ARG - fprintf(stderr, "\tWARNING: \"-write-buffer\" deprecated and will soon be removed, use -bs-cache-size=%s\n", argv[i + 1]); - gf_opts_set_key("temp", "bs-cache-size", argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-cprt")) { - CHECK_NEXT_ARG cprt = argv[i + 1]; - i++; - if (!dash_duration) open_edit = GF_TRUE; - } - else if (!stricmp(arg, "-chap") || !stricmp(arg, "-chapqt")) { - CHECK_NEXT_ARG - chap_file = argv[i + 1]; - i++; - open_edit = GF_TRUE; - if (!stricmp(arg, "-chapqt")) chap_qt = GF_TRUE; - } - else if (!stricmp(arg, "-inter") || !stricmp(arg, "-old-inter")) { - CHECK_NEXT_ARG - interleaving_time = atof(argv[i + 1]) / 1000; - if (!interleaving_time) do_flat = 2; - open_edit = GF_TRUE; - needSave = GF_TRUE; - if (!stricmp(arg, "-old-inter")) old_interleave = 1; - i++; - } - else if (!stricmp(arg, "-frag")) { - CHECK_NEXT_ARG - interleaving_time = atof(argv[i + 1]) / 1000; - needSave = GF_TRUE; - i++; - Frag = GF_TRUE; - } - else if (!stricmp(arg, "-dash")) { - CHECK_NEXT_ARG - dash_duration = atof(argv[i + 1]) / 1000; - if (dash_duration == 0.0) { - fprintf(stderr, "\tERROR: \"-dash-dash_duration\": invalid parameter %s\n", argv[i + 1]); - return 2; + while (tags) { + char *val; + Bool clear = GF_FALSE; + Bool is_wma = GF_FALSE; + u32 tlen, tagtype=0, itag = 0; + s32 tag_idx=-1; + char *sep = itunes_data ? strchr(tags, '\n') : gf_url_colon_suffix(tags, '='); + while (sep) { + char *eq = strchr(sep+1, '='); + if (eq) eq[0] = 0; + s32 next_tag_idx = gf_itags_find_by_name(sep+1); + if (next_tag_idx<0) { + //4CC tag + if ( strlen(sep+1)==4) { + next_tag_idx = 0; + } + //3CC tag, changed to @tag + if ( strlen(sep+1)==3) { + next_tag_idx = 0; + } + //unrecognized tag tag + else { + M4_LOG(GF_LOG_WARNING, ("Unrecognize tag \"%s\", assuming part of previous tag\n", sep+1)); + } } - i++; - } - else if (!stricmp(arg, "-dash-strict")) { - CHECK_NEXT_ARG - dash_duration = atof(argv[i + 1]) / 1000; - if (dash_duration == 0.0) { - fprintf(stderr, "\tERROR: \"-dash-dash_duration\": invalid parameter %s\n", argv[i + 1]); - return 2; + + if (eq) eq[0] = '='; + if (next_tag_idx>=0) { + sep[0] = 0; + break; } - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] -dash-strict is deprecated, will behave like -dash\n")); - i++; - } - else if (!stricmp(arg, "-subdur")) { - CHECK_NEXT_ARG - dash_subduration = atof(argv[i + 1]) / 1000; - i++; + sep = itunes_data ? strchr(sep+1, '\n') : gf_url_colon_suffix(sep+1, '='); } - else if (!stricmp(arg, "-dash-scale")) { - CHECK_NEXT_ARG - dash_scale = atoi(argv[i + 1]); - if (!dash_scale) { - fprintf(stderr, "\tERROR: \"-dash-scale\": invalid parameter %s\n", argv[i + 1]); - return 2; + val = strchr(tags, '='); + if (val) val[0] = 0; + if (!strcmp(tags, "clear") || !strcmp(tags, "reset")) { + clear = GF_TRUE; + } else if (!strncmp(tags, "WM/", 3) ) { + is_wma = GF_TRUE; + } else { + tag_idx = gf_itags_find_by_name(tags); + if (tag_idx<0) { + if (strlen(tags)==4) { + itag = GF_4CC(tags[0], tags[1], tags[2], tags[3]); + tagtype = GF_ITAG_STR; + } else if (strlen(tags)==3) { + itag = GF_4CC(0xA9, tags[0], tags[1], tags[2]); + tagtype = GF_ITAG_STR; + } } - i++; - } - else if (!stricmp(arg, "-dash-ts-prog")) { - CHECK_NEXT_ARG - program_number = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-subsegs-per-sidx") || !stricmp(arg, "-frags-per-sidx")) { - CHECK_NEXT_ARG - subsegs_per_sidx = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-segment-name")) { - CHECK_NEXT_ARG - seg_name = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-run-for")) { - CHECK_NEXT_ARG - run_for = atoi(argv[i + 1]); - i++; - } - else if (!stricmp(arg, "-no-cache")) { - no_cache = GF_TRUE; - } - else if (!stricmp(arg, "-no-loop")) { - no_loop = GF_TRUE; - } - else if (!stricmp(arg, "-hlsc")) { - hls_clock = GF_TRUE; - } - else if (!stricmp(arg, "-bound")) { - dash_split_mode = GF_DASH_SPLIT_IN; - } - else if (!stricmp(arg, "-closest")) { - dash_split_mode = GF_DASH_SPLIT_CLOSEST; } - else if (!stricmp(arg, "-segment-ext")) { - CHECK_NEXT_ARG - seg_ext = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-init-segment-ext")) { - CHECK_NEXT_ARG - init_seg_ext = argv[i + 1]; - i++; + if (val) { + val[0] = '='; + val++; } - else if (!stricmp(arg, "-bs-switching")) { - CHECK_NEXT_ARG - if (!stricmp(argv[i + 1], "no") || !stricmp(argv[i + 1], "off")) bitstream_switching_mode = GF_DASH_BSMODE_NONE; - else if (!stricmp(argv[i + 1], "merge")) bitstream_switching_mode = GF_DASH_BSMODE_MERGED; - else if (!stricmp(argv[i + 1], "multi")) bitstream_switching_mode = GF_DASH_BSMODE_MULTIPLE_ENTRIES; - else if (!stricmp(argv[i + 1], "single")) bitstream_switching_mode = GF_DASH_BSMODE_SINGLE; - else if (!stricmp(argv[i + 1], "inband")) bitstream_switching_mode = GF_DASH_BSMODE_INBAND; - else { - fprintf(stderr, "\tWARNING: Unrecognized bitstream switchin mode \"%s\" - please check usage\n", argv[i + 1]); - return 2; + if (!itag && !clear && !is_wma) { + if (tag_idx<0) { + M4_LOG(GF_LOG_WARNING, ("Invalid iTune tag name \"%s\" - ignoring\n", tags)); + break; } - i++; + itag = gf_itags_get_itag(tag_idx); + tagtype = gf_itags_get_type(tag_idx); } - else if (!stricmp(arg, "-dynamic")) { - dash_mode = GF_DASH_DYNAMIC; + if (!val || (val[0]==':') || !val[0] || !stricmp(val, "NULL") ) val = NULL; + + //if val is NULL, use tlen=1 to force removal of tag + tlen = val ? (u32) strlen(val) : 1; + if (clear) { + e = gf_isom_apple_set_tag(file, GF_ISOM_ITUNE_RESET, NULL, 0, 0, 0); } - else if (!stricmp(arg, "-last-dynamic")) { - dash_mode = GF_DASH_DYNAMIC_LAST; + else if (is_wma) { + if (val) val[-1] = 0; + e = gf_isom_wma_set_tag(file, tags, val); + if (val) val[-1] = '='; } - else if (!stricmp(arg, "-frag-rt")) { - frag_real_time = GF_TRUE; + else if (val && (tagtype==GF_ITAG_FILE)) { + u32 flen = (u32) strlen(val); + u8 *d=NULL; + while (flen && val[flen-1]=='\n') flen--; + val[flen] = 0; + e = gf_file_load_data(val, (u8 **) &d, &tlen); + val[flen] = '\n'; + + if (!e) + e = gf_isom_apple_set_tag(file, itag, d, tlen, 0, 0); + + if (d) gf_free(d); + } else { + e = gf_isom_apple_set_tag(file, itag, (u8 *) val, tlen, 0, 0); } - else if (!stricmp(arg, "-start-date")) { - dash_start_date = argv[i+1]; - i++; + if (e) { + M4_LOG(GF_LOG_ERROR, ("Error assigning tag %s: %s\n", tags, gf_error_to_string(e) )); } - else if (!strnicmp(arg, "-cp-location=", 13)) { - if (strcmp(arg+13, "both")) cp_location_mode = GF_DASH_CPMODE_BOTH; - else if (strcmp(arg+13, "as")) cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET; - else if (strcmp(arg+13, "rep")) cp_location_mode = GF_DASH_CPMODE_REPRESENTATION; - else { - fprintf(stderr, "\tWARNING: Unrecognized ContentProtection loction mode \"%s\" - please check usage\n", argv[i + 13]); - return 2; - } + + do_save = GF_TRUE; + + if (sep) { + sep[0] = itunes_data ? '\n' : ':'; + tags = sep+1; + } else { + tags = NULL; } - else if (!strnicmp(arg, "-dash-live", 10) || !strnicmp(arg, "-ddbg-live", 10)) { - dash_mode = !strnicmp(arg, "-ddbg-live", 10) ? GF_DASH_DYNAMIC_DEBUG : GF_DASH_DYNAMIC; - dash_live = 1; - if (arg[10] == '=') { - dash_ctx_file = arg + 11; + } + if (itunes_data) gf_free(itunes_data); + return GF_OK; +} + +#if !defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_SENG) +static void set_sdp_ext() +{ + u32 i, j; + for (i=0; ioverlay_offsets) gf_free(iprops->overlay_offsets); + if (iprops->aux_urn) gf_free((char *) iprops->aux_urn); + if (iprops->aux_data) gf_free((char *) iprops->aux_data); + gf_free(iprops); + } } - else if (!stricmp(arg, "-pssh-moof")) { - pssh_mode = GF_DASH_PSSH_MOOF; - } - else if (!strnicmp(arg, "-pssh=", 6)) { - if (!strcmp(arg+6, "f")) pssh_mode = GF_DASH_PSSH_MOOF; - else if (!strcmp(arg+6, "v")) pssh_mode = GF_DASH_PSSH_MOOV; - else if (!strcmp(arg+6, "m")) pssh_mode = GF_DASH_PSSH_MPD; - else if (!strcmp(arg+6, "mf") || !strcmp(arg+6, "fm")) pssh_mode = GF_DASH_PSSH_MOOF_MPD; - else if (!strcmp(arg+6, "mv") || !strcmp(arg+6, "vm")) pssh_mode = GF_DASH_PSSH_MOOV_MPD; - else pssh_mode = GF_DASH_PSSH_MOOV; - } - else if (!stricmp(arg, "-sample-groups-traf")) { - samplegroups_in_traf = 1; - } - else if (!stricmp(arg, "-mvex-after-traks")) { - mvex_after_traks = GF_TRUE; - } - else if (!stricmp(arg, "-sdtp-traf")) { - CHECK_NEXT_ARG - if (!stricmp(argv[i + 1], "both")) sdtp_in_traf = 2; - else if (!stricmp(argv[i + 1], "sdtp")) sdtp_in_traf = 1; - else sdtp_in_traf = 0; - i++; + gf_free(metas); + metas = NULL; + } + if (tracks) { + u32 i; + for (i = 0; inb_baseURL) { + for (j = 0; jnb_baseURL; j++) { + gf_free(di->baseURL[j]); + } + gf_free(di->baseURL); } - else if (!stricmp(argv[i + 1], "dashavc264:live")) { - dash_profile = GF_DASH_PROFILE_AVC264_LIVE; + if (di->rep_descs) { + for (j = 0; jnb_rep_descs; j++) { + gf_free(di->rep_descs[j]); + } + gf_free(di->rep_descs); } - else if (!stricmp(argv[i + 1], "dashavc264:onDemand")) { - dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND; + if (di->as_descs) { + for (j = 0; jnb_as_descs; j++) { + gf_free(di->as_descs[j]); + } + gf_free(di->as_descs); } - else if (!stricmp(argv[i + 1], "main")) dash_profile = GF_DASH_PROFILE_MAIN; - else if (!stricmp(argv[i + 1], "full")) dash_profile = GF_DASH_PROFILE_FULL; - else { - fprintf(stderr, "\tWARNING: Unrecognized DASH profile \"%s\" - please check usage\n", argv[i + 1]); - return 2; + if (di->as_c_descs) { + for (j = 0; jnb_as_c_descs; j++) { + gf_free(di->as_c_descs[j]); + } + gf_free(di->as_c_descs); } - i++; - } - else if (!stricmp(arg, "-profile-ext")) { - CHECK_NEXT_ARG - dash_profile_extension = argv[i + 1]; - i++; - } - else if (!strnicmp(arg, "-url-template", 13)) { - use_url_template = 1; - if ((arg[13] == '=') && arg[14]) { - if (!strcmp(&arg[14], "simulate")) use_url_template = 2; + if (di->p_descs) { + for (j = 0; jnb_p_descs; j++) { + gf_free(di->p_descs[j]); + } + gf_free(di->p_descs); + } + if (di->representationID) gf_free(di->representationID); + if (di->periodID) gf_free(di->periodID); + if (di->xlink) gf_free(di->xlink); + if (di->seg_template) gf_free(di->seg_template); + if (di->hls_pl) gf_free(di->hls_pl); + if (di->source_opts) gf_free(di->source_opts); + if (di->filter_chain) gf_free(di->filter_chain); + + if (di->roles) { + for (j = 0; jnb_roles; j++) { + gf_free(di->roles[j]); + } + gf_free(di->roles); } } - else if (!stricmp(arg, "-segment-timeline")) { - segment_timeline = 1; - } - else if (!stricmp(arg, "-mem-frags")) { - memory_frags = 1; - } - else if (!stricmp(arg, "-segment-marker")) { - char *m; - CHECK_NEXT_ARG - m = argv[i + 1]; - segment_marker = GF_4CC(m[0], m[1], m[2], m[3]); - i++; - } - else if (!stricmp(arg, "-cues")) { - CHECK_NEXT_ARG - dash_cues = argv[i + 1]; - i++; - } - else if (!stricmp(arg, "-strict-cues")) { - strict_cues = GF_TRUE; - } - else if (!stricmp(arg, "-insert-utc")) { - insert_utc = GF_TRUE; - } -#endif //GPAC_DISABLE_ISOM_WRITE - else if (!stricmp(arg, "-udp-write")) { - udp_dest = argv[i+1]; - i++; - } - else { - u32 ret = mp4box_parse_args_continue(argc, argv, &i); - if (ret) return ret; - } + gf_free(dash_inputs); + dash_inputs = NULL; } - return 0; + if (logfile) gf_fclose(logfile); + gf_sys_close(); + +#ifdef GPAC_MEMORY_TRACKING + if (mem_track && (gf_memory_size() || gf_file_handles_count() )) { + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); + gf_memory_print(); + } +#endif + + return ret_code; } + + int mp4boxMain(int argc, char **argv) { u32 i, j; const char *gpac_profile = "0"; GF_Err e = GF_OK; - nb_tsel_acts = nb_add = nb_cat = nb_track_act = nb_sdp_ex = max_ptime = nb_meta_act = rtp_rate = major_brand = nb_alt_brand_add = nb_alt_brand_rem = car_dur = minor_version = 0; - - split_duration = 0.0; - split_start = -1.0; - interleaving_time = 0; - dash_duration = dash_subduration = 0.0; - import_fps.num = import_fps.den = 0; - import_flags = 0; - split_size = 0; - movie_time = 0; - dump_nal = dump_saps = dump_saps_mode = force_new = 0; - FullInter = HintInter = encode = do_scene_log = old_interleave = do_saf = do_hash = verbose = do_mpd_rip = merge_vtt_cues = get_nb_tracks = GF_FALSE; -#ifndef GPAC_DISABLE_SCENE_DUMP - dump_mode = GF_SM_DUMP_NONE; -#endif - Frag = force_ocr = remove_sys_tracks = agg_samples = remove_hint = keep_sys_tracks = remove_root_od = single_group = clean_groups = compress_moov = GF_FALSE; - conv_type = HintIt = needSave = print_sdp = regular_iod = dump_std = open_edit = dump_rtp = dump_cr = dump_srt = dump_ttxt = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_live = GF_FALSE; - no_fragments_defaults = GF_FALSE; - single_traf_per_moof = hls_clock = GF_FALSE; - tfdt_per_traf = GF_FALSE; - dump_nal_type = 0; - dump_isom = 0; - print_info = 0; - /*align cat is the new default behaviour for -cat*/ - align_cat = GF_TRUE; - subsegs_per_sidx = 0; - track_dump_type = 0; - crypt = 0; - time_shift_depth = 0; - file = NULL; - itunes_tags = pes_dump = NULL; - seg_name = dash_ctx_file = NULL; - compress_top_boxes = NULL; - initial_moof_sn = 0; - initial_tfdt = 0; - -#ifndef GPAC_DISABLE_SCENE_ENCODER - memset(&smenc_opts, 0, sizeof(smenc_opts)); -#endif - - trackID = stat_level = hint_flags = 0; - program_number = 0; - info_track_id = 0; - do_flat = 0; - inName = outName = mediaSource = input_ctx = output_ctx = drm_file = avi2raw = cprt = chap_file = pack_file = raw_cat = high_dynamc_range_filename = use_init_seg = box_patch_filename = NULL; -#ifndef GPAC_DISABLE_SWF_IMPORT - swf_flags = GF_SM_SWF_SPLIT_TIMELINE; +#ifdef TEST_ARGS + i=0; + mp4box_parse_single_arg(argc, argv, "", &i); #endif - swf_flatten_angle = 0.0f; - tmpdir = NULL; for (i = 1; i < (u32) argc ; i++) { if (!strcmp(argv[i], "-mem-track") || !strcmp(argv[i], "-mem-track-stack")) { #ifdef GPAC_MEMORY_TRACKING mem_track = !strcmp(argv[i], "-mem-track-stack") ? GF_MemTrackerBackTrace : GF_MemTrackerSimple; #else - fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"%s\"\n", argv[i]); + M4_LOG(GF_LOG_WARNING, ("WARNING - GPAC not compiled with Memory Tracker - ignoring \"%s\"\n", argv[i])); #endif break; } @@ -4490,7 +5692,7 @@ int mp4boxMain(int argc, char **argv) if (i+1<(u32) argc) gpac_profile = argv[i+1]; else { - fprintf(stderr, "Bad argument for -p, expecting profile name but no more args\n"); + M4_LOG(GF_LOG_ERROR, ("Bad argument for -p, expecting profile name but no more args\n")); return 1; } } @@ -4505,9 +5707,9 @@ int mp4boxMain(int argc, char **argv) /*init libgpac*/ gf_sys_init(mem_track, gpac_profile); if (argc < 2) { - fprintf(stderr, "Not enough arguments - check usage with -h\n" - "MP4Box - GPAC version %s\n" - "%s\n", gf_gpac_version(), gf_gpac_copyright_cite()); + M4_LOG(GF_LOG_ERROR, ("Not enough arguments - check usage with -h\n")); + M4_LOG(GF_LOG_INFO, ("MP4Box - GPAC version %s\n" + "%s\n", gf_gpac_version(), gf_gpac_copyright_cite() )); gf_sys_close(); return 0; } @@ -4518,13 +5720,32 @@ int mp4boxMain(int argc, char **argv) if (i) { return mp4box_cleanup(i - 1); } +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + if (live_scene) { + int ret = live_session(argc, argv); + return mp4box_cleanup(ret); + } +#endif + + if (!dash_duration && interleaving_time && do_frag) + interleaving_time /= 1000; + + if (do_mpd_conv) inName = do_mpd_conv; + +#ifndef GPAC_DISABLE_STREAMING + if (import_flags & GF_IMPORT_FORCE_MPEG4) + hint_flags |= GP_RTP_PCK_FORCE_MPEG4; +#endif if (!inName && dump_std) inName = "std"; + if (!dash_duration && cprt) + open_edit = GF_TRUE; + if (!inName) { if (has_next_arg) { - fprintf(stderr, "Broken argument specifier or file name missing - check usage with -h\n"); + M4_LOG(GF_LOG_ERROR, ("Broken argument specifier or file name missing - check usage with -h\n")); } else { PrintUsage(); } @@ -4540,7 +5761,7 @@ int mp4boxMain(int argc, char **argv) /*by default use single fragment per dash segment*/ if (dash_duration) interleaving_time = dash_duration; - else if (!do_flat) { + else if (!do_flat && !(split_duration || split_size || split_range_str)) { interleaving_time = DEFAULT_INTERLEAVING_IN_SEC; } } @@ -4555,23 +5776,16 @@ int mp4boxMain(int argc, char **argv) if ( freopen(NULL, "wb", stdout) == NULL) #endif { - fprintf(stderr, "Fatal error: cannot reopen stdout in binary mode.\n"); + M4_LOG(GF_LOG_ERROR, ("Fatal error: cannot reopen stdout in binary mode.\n")); return mp4box_cleanup(1); } } -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - if (live_scene) { - int ret = live_session(argc, argv); - return mp4box_cleanup(ret); - } -#endif - GF_LOG_Level level = verbose ? GF_LOG_DEBUG : GF_LOG_INFO; gf_log_set_tool_level(GF_LOG_CONTAINER, level); gf_log_set_tool_level(GF_LOG_SCENE, level); gf_log_set_tool_level(GF_LOG_PARSER, level); - gf_log_set_tool_level(GF_LOG_AUTHOR, level); + gf_log_set_tool_level(GF_LOG_MEDIA, level); gf_log_set_tool_level(GF_LOG_CODING, level); gf_log_set_tool_level(GF_LOG_DASH, level); #ifdef GPAC_MEMORY_TRACKING @@ -4581,44 +5795,20 @@ int mp4boxMain(int argc, char **argv) e = gf_sys_set_args(argc, (const char **) argv); if (e) { - fprintf(stderr, "Error assigning libgpac arguments: %s\n", gf_error_to_string(e) ); + M4_LOG(GF_LOG_ERROR, ("Error assigning libgpac arguments: %s\n", gf_error_to_string(e) )); return mp4box_cleanup(1); } - if (raw_cat) { - char chunk[4096]; - FILE *fin, *fout; - s64 to_copy, done; - fin = gf_fopen(raw_cat, "rb"); - if (!fin) return mp4box_cleanup(1); + if (raw_cat) + return do_raw_cat(); - fout = gf_fopen(inName, "a+b"); - if (!fout) { - gf_fclose(fin); - return mp4box_cleanup(1); - } - gf_fseek(fin, 0, SEEK_END); - to_copy = gf_ftell(fin); - gf_fseek(fin, 0, SEEK_SET); - done = 0; - while (1) { - u32 nb_bytes = (u32) gf_fread(chunk, 4096, fin); - gf_fwrite(chunk, nb_bytes, fout); - done += nb_bytes; - fprintf(stderr, "Appending file %s - %02.2f done\r", raw_cat, 100.0*done/to_copy); - if (done >= to_copy) break; - } - gf_fclose(fin); - gf_fclose(fout); - return mp4box_cleanup(0); - } if (compress_top_boxes) { if (size_top_box) { u64 top_size = do_size_top_boxes(inName, compress_top_boxes, size_top_box); fprintf(stdout, LLU"\n", top_size); return mp4box_cleanup(e ? 1 : 0); } else { - e = do_compress_top_boxes(inName, outName, compress_top_boxes, comp_top_box_version, comp_lzma); + e = do_compress_top_boxes(inName, outName); return mp4box_cleanup(e ? 1 : 0); } } @@ -4632,127 +5822,25 @@ int mp4boxMain(int argc, char **argv) if (do_wget != NULL) { e = gf_dm_wget(do_wget, inName, 0, 0, NULL); if (e != GF_OK) { - fprintf(stderr, "Cannot retrieve %s: %s\n", do_wget, gf_error_to_string(e) ); + M4_LOG(GF_LOG_ERROR, ("Cannot retrieve %s: %s\n", do_wget, gf_error_to_string(e) )); return mp4box_cleanup(1); } return mp4box_cleanup(0); } #endif - if (udp_dest) { - GF_Socket *sock = gf_sk_new(GF_SOCK_TYPE_UDP); - u16 port = 2345; - char *sep = strrchr(udp_dest, ':'); - if (sep) { - sep[0] = 0; - port = atoi(sep+1); - } - e = gf_sk_bind( sock, "127.0.0.1", 0, udp_dest, port, 0); - if (sep) sep[0] = ':'; - if (e) fprintf(stderr, "Failed to bind socket to %s: %s\n", udp_dest, gf_error_to_string(e) ); - else { - e = gf_sk_send(sock, (u8 *) inName, (u32)strlen(inName)); - if (e) fprintf(stderr, "Failed to send datagram: %s\n", gf_error_to_string(e) ); - } - gf_sk_del(sock); - return 0; - } + if (udp_dest) + return do_write_udp(); #ifndef GPAC_DISABLE_MPD - if (do_mpd) { - Bool remote = GF_FALSE; - GF_MPD *mpd; - char *mpd_base_url = NULL; - if (!strnicmp(inName, "http://", 7) || !strnicmp(inName, "https://", 8)) { -#if !defined(GPAC_DISABLE_CORE_TOOLS) - e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0, &mpd_base_url); - if (e != GF_OK) { - fprintf(stderr, "Cannot retrieve M3U8 (%s): %s\n", inName, gf_error_to_string(e)); - if (mpd_base_url) gf_free(mpd_base_url); - return mp4box_cleanup(1); - } - remote = GF_TRUE; -#else - gf_free(mpd_base_url); - fprintf(stderr, "HTTP Downloader disabled in this build\n"); - return mp4box_cleanup(1); + if (do_mpd_conv) + return convert_mpd(); #endif - if (outName) - strcpy(outfile, outName); - else { - const char *sep = gf_file_basename(inName); - char *ext = gf_file_ext_start(sep); - if (ext) ext[0] = 0; - sprintf(outfile, "%s.mpd", sep); - if (ext) ext[0] = '.'; - } - } else { - if (outName) - strcpy(outfile, outName); - else { - char *dst = strdup(inName); - char *ext = strstr(dst, ".m3u8"); - if (ext) ext[0] = 0; - sprintf(outfile, "%s.mpd", dst); - gf_free(dst); - } - } - - mpd = gf_mpd_new(); - if (!mpd) { - e = GF_OUT_OF_MEM; - fprintf(stderr, "[DASH] Error: MPD creation problem %s\n", gf_error_to_string(e)); - mp4box_cleanup(1); - } - FILE *f = gf_fopen(remote ? "tmp_main.m3u8" : inName, "r"); - u32 manif_type = 0; - if (f) { - char szDATA[1000]; - s32 read; - szDATA[999]=0; - read = (s32) gf_fread(szDATA, 999, f); - if (read<0) read = 0; - szDATA[read]=0; - gf_fclose(f); - if (strstr(szDATA, "SmoothStreamingMedia")) - manif_type = 2; - else if (strstr(szDATA, "#EXTM3U")) - manif_type = 1; - } - - if (manif_type==1) { - e = gf_m3u8_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd_base_url ? mpd_base_url : inName, outfile, 0, "video/mp2t", GF_TRUE, use_url_template, segment_timeline, NULL, mpd, GF_TRUE, GF_TRUE); - } else if (manif_type==2) { - e = gf_mpd_smooth_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd, mpd_base_url ? mpd_base_url : inName); - } else { - e = GF_NOT_SUPPORTED; - } - if (!e) - gf_mpd_write_file(mpd, outfile); - - if (mpd) - gf_mpd_del(mpd); - if (mpd_base_url) - gf_free(mpd_base_url); - - if (remote) { - gf_file_delete("tmp_main.m3u8"); - } - if (e != GF_OK) { - fprintf(stderr, "Error converting %s (%s) to MPD (%s): %s\n", (manif_type==1) ? "HLS" : "Smooth", inName, outfile, gf_error_to_string(e)); - return mp4box_cleanup(1); - } else { - fprintf(stderr, "Done converting %s (%s) to MPD (%s)\n", (manif_type==1) ? "HLS" : "Smooth", inName, outfile); - return mp4box_cleanup(0); - } - } -#endif if (dash_duration && !nb_dash_inputs) { dash_inputs = set_dash_input(dash_inputs, inName, &nb_dash_inputs); } - if (do_saf && !encode) { switch (get_file_type_by_ext(inName)) { case GF_FILE_TYPE_BT_WRL_X3DV: @@ -4774,533 +5862,78 @@ int mp4boxMain(int argc, char **argv) } #endif + if (import_subtitle && !trackID) + return do_import_sub(); - if (import_subtitle && !trackID) { - /* We import the subtitle file, - i.e. we parse it and store the content as samples of a 3GPP Timed Text track in an ISO file, - possibly for later export (e.g. when converting SRT to TTXT, ...) */ -#ifndef GPAC_DISABLE_MEDIA_IMPORT - GF_MediaImporter import; - /* Prepare the importer */ - file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL); - if (timescale && file) gf_isom_set_timescale(file, timescale); - - memset(&import, 0, sizeof(GF_MediaImporter)); - import.dest = file; - import.in_name = inName; - /* Start the import */ - e = gf_media_import(&import); - if (e) { - fprintf(stderr, "Error importing %s: %s\n", inName, gf_error_to_string(e)); - gf_isom_delete(file); - gf_file_delete("ttxt_convert"); - return mp4box_cleanup(1); - } - /* Prepare the export */ - strcpy(outfile, inName); - if (strchr(outfile, '.')) { - while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; - outfile[strlen(outfile)-1] = 0; - } -#ifndef GPAC_DISABLE_ISOM_DUMP - /* Start the export of the track #1, in the appropriate dump type, indicating it's a conversion */ - dump_isom_timed_text(file, gf_isom_get_track_id(file, 1), - dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, - GF_TRUE, - (import_subtitle==2) ? GF_TEXTDUMPTYPE_SVG : (dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT)); -#endif - /* Clean the importer */ - gf_isom_delete(file); - gf_file_delete("ttxt_convert"); - if (e) { - fprintf(stderr, "Error converting %s: %s\n", inName, gf_error_to_string(e)); - return mp4box_cleanup(1); - } - return mp4box_cleanup(0); -#else - fprintf(stderr, "Feature not supported\n"); - return mp4box_cleanup(1); -#endif - } #if !defined(GPAC_DISABLE_MEDIA_IMPORT) && !defined(GPAC_DISABLE_ISOM_WRITE) if (nb_add || nb_cat) { - u32 ipass, nb_pass = 1; - char *mux_args=NULL; - GF_FilterSession *fs = NULL; - if (nb_add) { - - GF_ISOOpenMode open_mode = GF_ISOM_OPEN_EDIT; - if (force_new) { - open_mode = (do_flat || (force_new==2)) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; - } else { - FILE *test = gf_fopen(inName, "rb"); - if (!test) { - open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; - if (!outName) outName = inName; - } else { - gf_fclose(test); - if (! gf_isom_probe_file(inName) ) { - open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; - if (!outName) outName = inName; - } - } - } - open_edit = do_flat ? GF_FALSE : GF_TRUE; - file = gf_isom_open(inName, open_mode, tmpdir); - if (!file) { - fprintf(stderr, "Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) ); - return mp4box_cleanup(1); - } - - if (freeze_box_order) - gf_isom_freeze_order(file); - } - - if (do_flat && interleaving_time) { - char szSubArg[100]; - gf_isom_set_storage_mode(file, GF_ISOM_STORE_FASTSTART); - do_flat = 2; - nb_pass = 2; - fs = gf_fs_new_defaults(0); - if (!fs) { - fprintf(stderr, "Error creating filter session\n"); - gf_isom_delete(file); - return mp4box_cleanup(1); - } - - //mux args - gf_dynstrcat(&mux_args, "mp4mx:importer:store=fstart", ":"); - - sprintf(szSubArg, "file=%p", file); - gf_dynstrcat(&mux_args, szSubArg, ":"); - sprintf(szSubArg, "cdur=%g", interleaving_time); - gf_dynstrcat(&mux_args, szSubArg, ":"); - } - - for (ipass=0; ipass0) && (dash_duration > dash_subduration)) { - fprintf(stderr, "Warning: -subdur parameter (%g s) should be greater than segment duration (%g s), using segment duration instead\n", dash_subduration, dash_duration); - dash_subduration = dash_duration; - } - - if (dash_mode && dash_live) - fprintf(stderr, "Live DASH-ing - press 'q' to quit, 's' to save context and quit\n"); - - if (!dash_ctx_file && dash_live) { - u32 r1; - u64 add = (u64) (intptr_t) &dasher; - add ^= gf_net_get_utc(); - r1 = (u32) add ^ (u32) (add/0xFFFFFFFF); - r1 ^= gf_rand(); - sprintf(szStateFile, "%s/dasher_%X.xml", gf_get_default_cache_directory(), r1 ); - dash_ctx_file = szStateFile; - dyn_state_file = GF_TRUE; - } else if (dash_ctx_file) { - if (force_new) - gf_file_delete(dash_ctx_file); - } - - if (dash_profile==GF_DASH_PROFILE_AUTO) - dash_profile = dash_mode ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_FULL; - - if (!dash_mode) { - time_shift_depth = 0; - mpd_update_time = 0; - } else if ((dash_profile>=GF_DASH_PROFILE_MAIN) && !use_url_template && !mpd_update_time) { - /*use a default MPD update of dash_duration sec*/ - mpd_update_time = (Double) (dash_subduration ? dash_subduration : dash_duration); - fprintf(stderr, "Using default MPD refresh of %g seconds\n", mpd_update_time); - } - - if (file && needSave) { - gf_isom_close(file); - file = NULL; - del_file = GF_TRUE; - } - - /*setup dash*/ - dasher = gf_dasher_new(szMPD, dash_profile, tmpdir, dash_scale, dash_ctx_file); - if (!dasher) { - return mp4box_cleanup(1); - } - e = gf_dasher_set_info(dasher, dash_title, cprt, dash_more_info, dash_source, NULL); - if (e) { - fprintf(stderr, "DASH Error: %s\n", gf_error_to_string(e)); - gf_dasher_del(dasher); - return mp4box_cleanup(1); - } - - gf_dasher_set_start_date(dasher, dash_start_date); - gf_dasher_set_location(dasher, dash_source); - for (i=0; i < nb_mpd_base_urls; i++) { - e = gf_dasher_add_base_url(dasher, mpd_base_urls[i]); - if (e) { - fprintf(stderr, "DASH Error: %s\n", gf_error_to_string(e)); - gf_dasher_del(dasher); - return mp4box_cleanup(1); - } - } - - if (segment_timeline && !use_url_template) { - fprintf(stderr, "DASH Warning: using -segment-timeline with no -url-template. Forcing URL template.\n"); - use_url_template = GF_TRUE; - } - - e = gf_dasher_enable_url_template(dasher, (Bool) use_url_template, seg_name, seg_ext, init_seg_ext); - if (!e) e = gf_dasher_enable_segment_timeline(dasher, segment_timeline); - if (!e) e = gf_dasher_enable_single_segment(dasher, single_segment); - if (!e) e = gf_dasher_enable_single_file(dasher, single_file); - if (!e) e = gf_dasher_set_switch_mode(dasher, bitstream_switching_mode); - if (!e) e = gf_dasher_set_durations(dasher, dash_duration, interleaving_time, dash_subduration); - if (!e) e = gf_dasher_enable_rap_splitting(dasher, seg_at_rap, frag_at_rap); - if (!e) e = gf_dasher_set_segment_marker(dasher, segment_marker); - if (!e) e = gf_dasher_enable_sidx(dasher, (subsegs_per_sidx>=0) ? 1 : 0, (u32) subsegs_per_sidx, daisy_chain_sidx, use_ssix); - if (!e) e = gf_dasher_set_dynamic_mode(dasher, dash_mode, mpd_update_time, time_shift_depth, mpd_live_duration); - if (!e) e = gf_dasher_set_min_buffer(dasher, min_buffer); - if (!e) e = gf_dasher_set_ast_offset(dasher, ast_offset_ms); - if (!e) e = gf_dasher_enable_memory_fragmenting(dasher, memory_frags); - if (!e) e = gf_dasher_set_initial_isobmf(dasher, initial_moof_sn, initial_tfdt); - if (!e) e = gf_dasher_configure_isobmf_default(dasher, no_fragments_defaults, pssh_mode, samplegroups_in_traf, single_traf_per_moof, tfdt_per_traf, mvex_after_traks, sdtp_in_traf); - if (!e) e = gf_dasher_enable_utc_ref(dasher, insert_utc); - if (!e) e = gf_dasher_enable_real_time(dasher, frag_real_time); - if (!e) e = gf_dasher_set_content_protection_location_mode(dasher, cp_location_mode); - if (!e) e = gf_dasher_set_profile_extension(dasher, dash_profile_extension); - if (!e) e = gf_dasher_enable_cached_inputs(dasher, no_cache); - if (!e) e = gf_dasher_enable_loop_inputs(dasher, ! no_loop); - if (!e) e = gf_dasher_set_split_mode(dasher, dash_split_mode); - if (!e) e = gf_dasher_set_hls_clock(dasher, hls_clock); - if (!e && dash_cues) e = gf_dasher_set_cues(dasher, dash_cues, strict_cues); - if (!e && fs_dump_flags) e = gf_dasher_print_session_info(dasher, fs_dump_flags); - - for (i=0; i < nb_dash_inputs; i++) { - if (!e) e = gf_dasher_add_input(dasher, &dash_inputs[i]); - } - if (e) { - fprintf(stderr, "DASH Setup Error: %s\n", gf_error_to_string(e)); - gf_dasher_del(dasher); - return mp4box_cleanup(1); - } - - dash_cumulated_time=0; - - while (1) { - if (run_for && (dash_cumulated_time >= run_for)) { - fprintf(stderr, "Done running, computing static MPD\n"); - do_abort = 3; - } - - dash_prev_time=gf_sys_clock(); - if (do_abort>=2) { - e = gf_dasher_set_dynamic_mode(dasher, GF_DASH_DYNAMIC_LAST, 0, time_shift_depth, mpd_live_duration); - } - - if (!e) e = gf_dasher_process(dasher); - if (!dash_live && (e==GF_EOS) ) { - fprintf(stderr, "Nothing to dash, too early ...\n"); - e = GF_OK; - } - - if (do_abort) - break; - - //this happens when reading file while writing them (local playback of the live session ...) - if (dash_live && (e==GF_IO_ERR) ) { - fprintf(stderr, "Error dashing file (%s) but continuing ...\n", gf_error_to_string(e) ); - e = GF_OK; - } - - if (e) break; - - if (dash_live) { - u64 ms_in_session=0; - u32 slept = gf_sys_clock(); - u32 sleep_for = gf_dasher_next_update_time(dasher, &ms_in_session); - fprintf(stderr, "Next generation scheduled in %u ms (DASH time "LLU" ms)\r", sleep_for, ms_in_session); - if (run_for && (ms_in_session>=run_for)) { - dash_cumulated_time = 1+run_for; - continue; - } - - while (1) { - if (gf_prompt_has_input()) { - char c = (char) gf_prompt_get_char(); - if (c=='X') { - do_abort = 1; - break; - } - if (c=='q') { - do_abort = 2; - break; - } - if (c=='s') { - do_abort = 3; - break; - } - } - - if (dash_mode == GF_DASH_DYNAMIC_DEBUG) { - break; - } - if (!sleep_for) break; - - gf_sleep(sleep_for/10); - sleep_for = gf_dasher_next_update_time(dasher, NULL); - if (sleep_for<=1) { - dash_now_time=gf_sys_clock(); - dash_cumulated_time+=(dash_now_time-dash_prev_time); - fprintf(stderr, "Slept for %d ms before generation, dash cumulated time %d\n", dash_now_time - slept, dash_cumulated_time); - break; - } - } - } else { - break; - } - } - - gf_dasher_del(dasher); - - if (!run_for && dash_ctx_file && (do_abort==3) && (dyn_state_file) && !gf_sys_is_test_mode() ) { - char szName[1024]; - fprintf(stderr, "Enter file name to save dash context:\n"); - if (scanf("%1023s", szName) == 1) { - gf_file_move(dash_ctx_file, szName); - } - } - if (e) fprintf(stderr, "Error DASHing file: %s\n", gf_error_to_string(e)); - if (file) gf_isom_delete(file); - if (del_file) - gf_file_delete(inName); - + e = do_dash(); if (e) return mp4box_cleanup(1); goto exit; } - else if (!file && !do_hash -#ifndef GPAC_DISABLE_MEDIA_EXPORT - && !(track_dump_type & GF_EXPORT_AVI_NATIVE) -#endif - ) { + if (split_duration || split_size || split_range_str) { + if (force_new==2) { + do_flat = 3; + force_new = 0; + } + } else { + if (do_flat) + open_edit = GF_TRUE; + } + + //need to open input + if (!file && !do_hash) { FILE *st = gf_fopen(inName, "rb"); Bool file_exists = 0; GF_ISOOpenMode omode; @@ -5316,36 +5949,39 @@ int mp4boxMain(int argc, char **argv) //keep fragment signaling in moov omode = GF_ISOM_OPEN_READ; if (use_init_seg) - file = gf_isom_open(use_init_seg, GF_ISOM_OPEN_READ, tmpdir); + file = gf_isom_open(use_init_seg, GF_ISOM_OPEN_READ, NULL); } if (!crypt && use_init_seg) { - file = gf_isom_open(use_init_seg, GF_ISOM_OPEN_READ_DUMP, tmpdir); + file = gf_isom_open(use_init_seg, GF_ISOM_OPEN_READ_DUMP, NULL); if (file) { e = gf_isom_open_segment(file, inName, 0, 0, 0); - if (e) { - fprintf(stderr, "Error opening segment %s: %s\n", inName, gf_error_to_string(e) ); + if (e==GF_ISOM_INCOMPLETE_FILE) { + M4_LOG(GF_LOG_WARNING, ("Segment %s: %s\n", inName, gf_error_to_string(e) )); + } else if (e) { + M4_LOG(GF_LOG_ERROR, ("Error opening segment %s: %s\n", inName, gf_error_to_string(e) )); gf_isom_delete(file); file = NULL; } } } if (!file) - file = gf_isom_open(inName, omode, tmpdir); + file = gf_isom_open(inName, omode, NULL); if (!file && (gf_isom_last_error(NULL) == GF_ISOM_INCOMPLETE_FILE) && !open_edit) { u64 missing_bytes; - e = gf_isom_open_progressive(inName, 0, 0, GF_FALSE, &file, &missing_bytes); - fprintf(stderr, "Truncated file - missing "LLD" bytes\n", missing_bytes); + gf_isom_open_progressive(inName, 0, 0, GF_FALSE, &file, &missing_bytes); + if (missing_bytes) + M4_LOG(GF_LOG_ERROR, ("Truncated file - missing "LLD" bytes\n", missing_bytes)); } if (!file) { if (open_edit && nb_meta_act) { - file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, tmpdir); + file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, NULL); if (!outName && file) outName = inName; } if (!file) { - fprintf(stderr, "Error opening file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL))); + M4_LOG(GF_LOG_ERROR, ("Error opening file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)))); return mp4box_cleanup(1); } } @@ -5389,7 +6025,7 @@ int mp4boxMain(int argc, char **argv) import.flags = GF_IMPORT_MPE_DEMUX; e = gf_media_import(&import); if (e) { - fprintf(stderr, "Error importing %s: %s\n", inName, gf_error_to_string(e)); + M4_LOG(GF_LOG_ERROR, ("Error importing %s: %s\n", inName, gf_error_to_string(e))); gf_isom_delete(file); gf_file_delete("ttxt_convert"); return mp4box_cleanup(1); @@ -5399,11 +6035,11 @@ int mp4boxMain(int argc, char **argv) if (dump_m2ts) { #ifndef GPAC_DISABLE_MPEG2TS - dump_mpeg2_ts(inName, pes_dump, program_number); + dump_mpeg2_ts(inName, outName, program_number); #endif } else if (dump_timestamps) { #ifndef GPAC_DISABLE_MPEG2TS - dump_mpeg2_ts(inName, pes_dump, program_number); + dump_mpeg2_ts(inName, outName, program_number); #endif #ifndef GPAC_DISABLE_CORE_TOOLS } else if (do_bin_xml) { @@ -5416,108 +6052,77 @@ int mp4boxMain(int argc, char **argv) convert_file_info(inName, info_track_id); #endif } else { - fprintf(stderr, "Input %s is not an MP4 file, operation not allowed\n", inName); - return mp4box_cleanup(1); + if (mux_name) { + e = do_remux_file(); + if (e) goto err_exit; + if (file) gf_isom_delete(file); + goto exit; + } else { + M4_LOG(GF_LOG_ERROR, ("Input %s is not an MP4 file, operation not allowed\n", inName)); + return mp4box_cleanup(1); + } } goto exit; } #endif /*GPAC_DISABLE_ISOM_WRITE*/ else if (open_edit) { - file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, tmpdir); + file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, NULL); if (!outName && file) outName = inName; } else if (!file_exists) { - fprintf(stderr, "Error creating file %s: %s\n", inName, gf_error_to_string(GF_URL_ERROR)); + M4_LOG(GF_LOG_ERROR, ("Error %s file %s: %s\n", force_new ? "creating" : "opening", inName, gf_error_to_string(GF_URL_ERROR))); return mp4box_cleanup(1); } else { - fprintf(stderr, "Cannot open %s - extension not supported\n", inName); + M4_LOG(GF_LOG_ERROR, ("Cannot open %s - extension not supported\n", inName)); return mp4box_cleanup(1); } } } if (high_dynamc_range_filename) { - e = parse_high_dynamc_range_xml_desc(file, high_dynamc_range_filename); + e = parse_high_dynamc_range_xml_desc(file, 0, high_dynamc_range_filename); if (e) goto err_exit; } - if (file && keep_utc && open_edit) { + if (file && keep_utc) { gf_isom_keep_utc_times(file, 1); } - strcpy(outfile, outName ? outName : inName); - { - - char *szExt = gf_file_ext_start(outfile); + if ( gf_strlcpy(outfile, outName ? outName : inName, sizeof(outfile)) >= sizeof(outfile) ) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Filename too long (limit is %d)\n", GF_MAX_PATH)); + return mp4box_cleanup(1); + } - if (szExt) - { - /*turn on 3GP saving*/ - if (!stricmp(szExt, ".3gp") || !stricmp(szExt, ".3gpp") || !stricmp(szExt, ".3g2")) - conv_type = GF_ISOM_CONV_TYPE_3GPP; - else if (!stricmp(szExt, ".m4a") || !stricmp(szExt, ".m4v")) - conv_type = GF_ISOM_CONV_TYPE_IPOD; - else if (!stricmp(szExt, ".psp")) - conv_type = GF_ISOM_CONV_TYPE_PSP; - else if (!stricmp(szExt, ".mov") || !stricmp(szExt, ".qt")) - conv_type = GF_ISOM_CONV_TYPE_MOV; + char *szExt = gf_file_ext_start(outfile); + if (szExt) { + /*turn on 3GP saving*/ + if (!stricmp(szExt, ".3gp") || !stricmp(szExt, ".3gpp") || !stricmp(szExt, ".3g2")) + conv_type = GF_ISOM_CONV_TYPE_3GPP; + else if (!stricmp(szExt, ".m4a") || !stricmp(szExt, ".m4v")) + conv_type = GF_ISOM_CONV_TYPE_IPOD; + else if (!stricmp(szExt, ".psp")) + conv_type = GF_ISOM_CONV_TYPE_PSP; + else if (!stricmp(szExt, ".mov") || !stricmp(szExt, ".qt")) + conv_type = GF_ISOM_CONV_TYPE_MOV; - //remove extension from outfile - *szExt = 0; - } + //remove extension from outfile + *szExt = 0; } #ifndef GPAC_DISABLE_MEDIA_EXPORT - if (track_dump_type & GF_EXPORT_AVI_NATIVE) { - char szFile[GF_MAX_PATH+24]; - GF_MediaExporter mdump; - memset(&mdump, 0, sizeof(mdump)); - mdump.in_name = inName; - mdump.flags = GF_EXPORT_AVI_NATIVE; - mdump.trackID = trackID; - if (dump_std) { - mdump.out_name = "std"; - } else if (outName) { - mdump.out_name = outName; - } else if (trackID>2) { - sprintf(szFile, "%s_audio%d", outfile, trackID-1); - mdump.out_name = szFile; - } else { - sprintf(szFile, "%s_%s", outfile, (trackID==1) ? "video" : "audio"); - mdump.out_name = szFile; - } - - mdump.print_stats_graph = fs_dump_flags; - e = gf_media_export(&mdump); + if (!open_edit && track_dump_type && !gf_isom_probe_file(inName)) { + e = do_export_tracks_non_isobmf(); if (e) goto err_exit; goto exit; } - if (!open_edit && track_dump_type && !gf_isom_probe_file(inName)) { - GF_MediaExporter mdump; - char szFile[GF_MAX_PATH+24]; - for (i=0; iact_type != TRAC_ACTION_RAW_EXTRACT) continue; - memset(&mdump, 0, sizeof(mdump)); - mdump.in_name = inName; - mdump.flags = tka->dump_type; - mdump.trackID = tka->trackID; - mdump.sample_num = tka->sample_num; - if (outName) { - mdump.out_name = outName; - mdump.flags |= GF_EXPORT_MERGE; - } else if (nb_track_act>1) { - sprintf(szFile, "%s_track%d", outfile, mdump.trackID); - mdump.out_name = szFile; - } else { - mdump.out_name = outfile; - } - mdump.print_stats_graph = fs_dump_flags; - e = gf_media_export(&mdump); - if (e) goto err_exit; - } + if (mux_name) { + e = do_remux_file(); + if (e) goto err_exit; + if (file) gf_isom_delete(file); goto exit; } + + #endif /*GPAC_DISABLE_MEDIA_EXPORT*/ #ifndef GPAC_DISABLE_SCENE_DUMP @@ -5532,17 +6137,17 @@ int mp4boxMain(int argc, char **argv) #endif #ifndef GPAC_DISABLE_ISOM_HINTING - if (!HintIt && print_sdp) dump_isom_sdp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); + if (!do_hint && print_sdp) dump_isom_sdp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); #endif if (get_nb_tracks) { fprintf(stdout, "%d\n", gf_isom_get_track_count(file)); } if (print_info) { if (!file) { - fprintf(stderr, "Cannot print info on a non ISOM file (%s)\n", inName); + M4_LOG(GF_LOG_ERROR, ("Cannot print info on a non ISOM file (%s)\n", inName)); } else { - if (info_track_id) DumpTrackInfo(file, info_track_id, 1, (print_info==2) ? GF_TRUE : GF_FALSE); - else DumpMovieInfo(file); + if (info_track_id) DumpTrackInfo(file, info_track_id, 1, (print_info==2) ? GF_TRUE : GF_FALSE, GF_FALSE); + else DumpMovieInfo(file, (print_info==2) ? GF_TRUE : GF_FALSE); } } #ifndef GPAC_DISABLE_ISOM_DUMP @@ -5574,7 +6179,10 @@ int mp4boxMain(int argc, char **argv) #endif if (dump_timestamps) dump_isom_timestamps(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_timestamps); - if (dump_nal) dump_isom_nal(file, dump_nal, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_nal_type); + if (dump_nal) { + e = dump_isom_nal(file, dump_nal, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_nal_type); + if (e) goto err_exit; + } if (dump_saps) dump_isom_saps(file, dump_saps, dump_saps_mode, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); if (do_hash) { @@ -5588,216 +6196,46 @@ int mp4boxMain(int argc, char **argv) } #endif + if (dump_chunk) dump_isom_chunks(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); if (dump_cart) dump_isom_cover_art(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); if (dump_chap) dump_isom_chapters(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_chap); if (dump_udta_type) dump_isom_udta(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_udta_type, dump_udta_track); if (dump_iod) { - GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)gf_isom_get_root_od(file); - if (!iod) { - fprintf(stderr, "File %s has no IOD\n", inName); - } else { - char szName[GF_MAX_PATH+10]; - FILE *iodf; - sprintf(szName, "%s.iod", outfile); - iodf = gf_fopen(szName, "wb"); - if (!iodf) { - fprintf(stderr, "Cannot open destination %s\n", szName); - } else { - u8 *desc; - u32 size; - GF_BitStream *bs = gf_bs_from_file(iodf, GF_BITSTREAM_WRITE); - if (gf_odf_desc_write((GF_Descriptor *)iod, &desc, &size)==GF_OK) { - gf_fwrite(desc, size, iodf); - gf_free(desc); - } else { - fprintf(stderr, "Error writing IOD %s\n", szName); - } - gf_fclose(iodf); - gf_bs_del(bs); - } - gf_odf_desc_del((GF_Descriptor*)iod); - } + e = do_dump_iod(); + if (e) goto err_exit; } #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) if (split_duration || split_size || split_range_str) { - split_isomedia_file(file, split_duration, split_size, inName, interleaving_time, split_start, adjust_split_end, outName, tmpdir, seg_at_rap, split_range_str); + split_isomedia_file(file, split_duration, split_size, inName, interleaving_time, split_start, adjust_split_end, outName, seg_at_rap, split_range_str, fs_dump_flags); + /*never save file when splitting is desired*/ open_edit = GF_FALSE; - needSave = GF_FALSE; + do_save = GF_FALSE; } #endif // !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) #ifndef GPAC_DISABLE_MEDIA_EXPORT - if (track_dump_type) { - char szFile[GF_MAX_PATH+24]; - GF_MediaExporter mdump; - for (i=0; iact_type != TRAC_ACTION_RAW_EXTRACT) continue; - memset(&mdump, 0, sizeof(mdump)); - mdump.file = file; - mdump.flags = tka->dump_type; - mdump.trackID = tka->trackID; - mdump.sample_num = tka->sample_num; - if (tka->out_name) { - mdump.out_name = tka->out_name; - } else if (outName) { - mdump.out_name = outName; - mdump.flags |= GF_EXPORT_MERGE; - /*don't infer extension on user-given filename*/ - mdump.flags |= GF_EXPORT_NO_FILE_EXT; - } else if (mdump.trackID) { - sprintf(szFile, "%s_track%d", outfile, mdump.trackID); - mdump.out_name = szFile; - } else { - sprintf(szFile, "%s_export", outfile); - mdump.out_name = szFile; - } - if (tka->trackID==(u32) -1) { - for (j=0; jtrackID) tk = gf_isom_get_track_by_id(file, meta->trackID); - - switch (meta->act_type) { -#ifndef GPAC_DISABLE_ISOM_WRITE - case META_ACTION_SET_TYPE: - /*note: we don't handle file brand modification, this is an author stuff and cannot be guessed from meta type*/ - e = gf_isom_set_meta_type(file, meta->root_meta, tk, meta->meta_4cc); - gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO2, GF_TRUE); - needSave = GF_TRUE; - break; - case META_ACTION_ADD_ITEM: - self_ref = !stricmp(meta->szPath, "NULL") || !stricmp(meta->szPath, "this") || !stricmp(meta->szPath, "self"); - e = gf_isom_add_meta_item(file, meta->root_meta, tk, self_ref, self_ref ? NULL : meta->szPath, - meta->szName, - meta->item_id, - meta->item_type, - meta->mime_type, - meta->enc_type, - meta->use_dref ? meta->szPath : NULL, NULL, - meta->image_props); - if (meta->ref_type) { - e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, meta->ref_item_id, meta->ref_type, NULL); - } - needSave = GF_TRUE; - break; - case META_ACTION_ADD_IMAGE_ITEM: - { - u32 old_tk_count = gf_isom_get_track_count(file); - GF_Fraction _frac = {0,0}; - e = import_file(file, meta->szPath, 0, _frac, 0, NULL, NULL, 0); - if (e == GF_OK) { - u32 meta_type = gf_isom_get_meta_type(file, meta->root_meta, tk); - if (!meta_type) { - e = gf_isom_set_meta_type(file, meta->root_meta, tk, GF_META_ITEM_TYPE_PICT); - } else { - if (meta_type != GF_META_ITEM_TYPE_PICT) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Warning: file already has a root 'meta' box of type %s\n", gf_4cc_to_str(meta_type))); - e = GF_BAD_PARAM; - } - } - if (e == GF_OK) { - if (!meta->item_id) { - e = gf_isom_meta_get_next_item_id(file, meta->root_meta, tk, &meta->item_id); - } - if (e == GF_OK) { - e = gf_isom_iff_create_image_item_from_track(file, meta->root_meta, tk, 1, - meta->szName, - meta->item_id, - meta->image_props, NULL); - if (e == GF_OK && meta->primary) { - e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); - } - if (e == GF_OK && meta->ref_type) { - e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, meta->ref_item_id, meta->ref_type, NULL); - } - } - } - } - gf_isom_remove_track(file, old_tk_count+1); - needSave = GF_TRUE; - } - break; - case META_ACTION_REM_ITEM: - e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id); - needSave = GF_TRUE; - break; - case META_ACTION_SET_PRIMARY_ITEM: - e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); - needSave = GF_TRUE; - break; - case META_ACTION_SET_XML: - case META_ACTION_SET_BINARY_XML: - e = gf_isom_set_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL, 0, (meta->act_type==META_ACTION_SET_BINARY_XML) ? 1 : 0); - needSave = GF_TRUE; - break; - case META_ACTION_REM_XML: - if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) { - e = gf_isom_remove_meta_xml(file, meta->root_meta, tk); - needSave = GF_TRUE; - } else { - fprintf(stderr, "No meta box in input file\n"); - } - break; - case META_ACTION_DUMP_ITEM: - if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) { - e = gf_isom_extract_meta_item(file, meta->root_meta, tk, meta->item_id, strlen(meta->szPath) ? meta->szPath : NULL); - } else { - fprintf(stderr, "No meta box in input file\n"); - } - break; -#endif // GPAC_DISABLE_ISOM_WRITE - - case META_ACTION_DUMP_XML: - if (gf_isom_has_meta_xml(file, meta->root_meta, tk)) { - e = gf_isom_extract_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL); - } else { - fprintf(stderr, "No meta box in input file\n"); - } - break; - default: - break; - } - if (meta->image_props) { - gf_free(meta->image_props); - meta->image_props = NULL; - } + if (track_dump_type) { + e = do_export_tracks(); + if (e) goto err_exit; + } else if (do_saf) { + GF_MediaExporter mdump; + memset(&mdump, 0, sizeof(mdump)); + mdump.file = file; + mdump.flags = GF_EXPORT_SAF; + mdump.out_name = outfile; + mdump.print_stats_graph = fs_dump_flags; + e = gf_media_export(&mdump); if (e) goto err_exit; } - if (!open_edit && !needSave) { +#endif + + e = do_meta_act(); + if (e) goto err_exit; + + if (!open_edit && !do_save) { if (file) gf_isom_delete(file); goto exit; } @@ -5807,89 +6245,59 @@ int mp4boxMain(int argc, char **argv) if (clean_groups) { e = gf_isom_reset_switch_parameters(file); if (e) goto err_exit; - needSave = GF_TRUE; + do_save = GF_TRUE; } - for (i=0; i0) { - u32 tk, k; - for (k=0; k<(u32) count; k++) { - gf_isom_get_reference(file, j+1, GF_ISOM_REF_CHAP, k+1, &tk); - if (tk==i+1) { - is_chap = 1; - break; - } - } - if (is_chap) break; - } - if (is_chap) break; - } - /*this is a subtitle track*/ - if (!is_chap) - gf_isom_set_media_type(file, i+1, GF_ISOM_MEDIA_SUBT); - } - break; - } - } - gf_isom_set_brand_info(file, ipod_major_brand, 1); - gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_MP42, GF_TRUE); - needSave = GF_TRUE; + do_ipod_conv(); } } else if (outName) { strcpy(outfile, outName); } - for (j=0; jtrackID ? gf_isom_get_track_by_id(file, tka->trackID) : 0; - - timescale = gf_isom_get_timescale(file); - switch (tka->act_type) { - case TRAC_ACTION_REM_TRACK: - e = gf_isom_remove_track(file, track); - if (e) { - fprintf(stderr, "Error Removing track ID %d: %s\n", tka->trackID, gf_error_to_string(e)); - } else { - fprintf(stderr, "Removing track ID %d\n", tka->trackID); - } - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_LANGUAGE: - for (i=0; ilang); - if (e) goto err_exit; - needSave = GF_TRUE; - } - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_KIND: - for (i=0; ikind_scheme, tka->kind_value); - if (e) goto err_exit; - needSave = GF_TRUE; - } - needSave = GF_TRUE; - break; - case TRAC_ACTION_REM_KIND: - for (i=0; ikind_scheme, tka->kind_value); - if (e) goto err_exit; - needSave = GF_TRUE; - } - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_DELAY: - if (tka->delay_ms) { - u64 tk_dur; - - gf_isom_remove_edits(file, track); - tk_dur = gf_isom_get_track_duration(file, track); - if (gf_isom_get_edits_count(file, track)) - needSave = GF_TRUE; - if (tka->delay_ms>0) { - gf_isom_append_edit(file, track, (timescale*tka->delay_ms)/1000, 0, GF_ISOM_EDIT_EMPTY); - gf_isom_append_edit(file, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); - needSave = GF_TRUE; - } else { - u64 to_skip = (timescale*(-tka->delay_ms))/1000; - if (to_skipdelay_ms)*gf_isom_get_media_timescale(file, track) / 1000; - gf_isom_append_edit(file, track, tk_dur-to_skip, media_time, GF_ISOM_EDIT_NORMAL); - needSave = GF_TRUE; - } else { - fprintf(stderr, "Warning: request negative delay longer than track duration - ignoring\n"); - } - } - } else if (gf_isom_get_edits_count(file, track)) { - gf_isom_remove_edits(file, track); - needSave = GF_TRUE; - } - break; - case TRAC_ACTION_SET_KMS_URI: - for (i=0; ikms); - if (e) goto err_exit; - needSave = GF_TRUE; - } - break; - case TRAC_ACTION_SET_ID: - if (!tka->trackID && (gf_isom_get_track_count(file) == 1)) { - fprintf(stderr, "Warning: track id is not specified, but file has only one track - assume that you want to change id for this track\n"); - track = 1; - } - if (track) { - u32 newTrack; - newTrack = gf_isom_get_track_by_id(file, tka->newTrackID); - if (newTrack != 0) { - fprintf(stderr, "Error: Cannot set track id with value %d because a track already exists - ignoring", tka->newTrackID); - } else { - e = gf_isom_set_track_id(file, track, tka->newTrackID); - needSave = GF_TRUE; - } - } else { - fprintf(stderr, "Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID); - } - break; - case TRAC_ACTION_SWAP_ID: - if (track) { - u32 tk1, tk2; - tk1 = gf_isom_get_track_by_id(file, tka->trackID); - tk2 = gf_isom_get_track_by_id(file, tka->newTrackID); - if (!tk1 || !tk2) { - fprintf(stderr, "Error: Cannot swap track IDs because not existing - ignoring"); - } else { - e = gf_isom_set_track_id(file, tk2, 0); - if (!e) e = gf_isom_set_track_id(file, tk1, tka->newTrackID); - if (!e) e = gf_isom_set_track_id(file, tk2, tka->trackID); - needSave = GF_TRUE; - } - } else { - fprintf(stderr, "Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID); - } - break; - case TRAC_ACTION_SET_PAR: - e = gf_media_change_par(file, track, tka->par_num, tka->par_den, tka->force_par, tka->rewrite_bs); - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_CLAP: - e = gf_isom_set_clean_aperture(file, track, 1, tka->clap_wnum, tka->clap_wden, tka->clap_hnum, tka->clap_hden, tka->clap_honum, tka->clap_hoden, tka->clap_vonum, tka->clap_voden); - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_MX: - e = gf_isom_set_track_matrix(file, track, tka->mx); - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_HANDLER_NAME: - e = gf_isom_set_handler_name(file, track, tka->hdl_name); - needSave = GF_TRUE; - break; - case TRAC_ACTION_ENABLE: - if (!gf_isom_is_track_enabled(file, track)) { - e = gf_isom_set_track_enabled(file, track, GF_TRUE); - needSave = GF_TRUE; - } - break; - case TRAC_ACTION_DISABLE: - if (gf_isom_is_track_enabled(file, track)) { - e = gf_isom_set_track_enabled(file, track, GF_FALSE); - needSave = GF_TRUE; - } - break; - case TRAC_ACTION_REFERENCE: - e = gf_isom_set_track_reference(file, track, GF_4CC(tka->lang[0], tka->lang[1], tka->lang[2], tka->lang[3]), (u32) tka->delay_ms); - needSave = GF_TRUE; - break; - case TRAC_ACTION_REM_NON_RAP: - fprintf(stderr, "Removing non-rap samples from track %d\n", tka->trackID); - e = gf_media_remove_non_rap(file, track, GF_FALSE); - needSave = GF_TRUE; - break; - case TRAC_ACTION_REM_NON_REFS: - fprintf(stderr, "Removing non-reference samples from track %d\n", tka->trackID); - e = gf_media_remove_non_rap(file, track, GF_TRUE); - needSave = GF_TRUE; - break; - case TRAC_ACTION_SET_UDTA: - fprintf(stderr, "Assigning udta box\n"); - e = set_file_udta(file, track, tka->udta_type, tka->src_name, tka->sample_num ? GF_TRUE : GF_FALSE); - if (e) goto err_exit; - needSave = GF_TRUE; - break; - default: - break; - } - if (e) goto err_exit; - } + e = do_track_act(); + if (e) goto err_exit; if (itunes_tags) { - char *tags = itunes_tags; - - while (tags) { - char *val; - char *sep = gf_url_colon_suffix(tags); - u32 tlen, itag = 0; - if (sep) { - while (sep) { - for (itag=0; itag> 8; - _t[5] = t; - _t[4] = t >> 8; - } - else if (sscanf(val, "%u", &n) == 1) { - _t[3] = n; - _t[2] = n >> 8; - } - else tlen = 0; - } - if (!val || tlen) gf_isom_apple_set_tag(file, itag, val ? (u8 *)_t : NULL, tlen); - } - break; - case GF_ISOM_ITUNE_GAPLESS: - case GF_ISOM_ITUNE_COMPILATION: - { - u8 _t[1]; - if (val && !stricmp(val, "yes")) _t[0] = 1; - else _t[0] = 0; - gf_isom_apple_set_tag(file, itag, _t, 1); - } - break; - default: - gf_isom_apple_set_tag(file, itag, (u8 *)val, tlen); - break; - } - needSave = GF_TRUE; - - if (sep) { - sep[0] = ':'; - tags = sep+1; - } else { - tags = NULL; - } - } - } - - if (movie_time) { - gf_isom_set_creation_time(file, movie_time); - for (i=0; i #endif +#ifndef GPAC_DISABLE_LOG +#define M4_LOG(_a, _b) GF_LOG(_a, GF_LOG_APP, _b) +#else +void mp4box_log(const char *fmt, ...); + +#define M4_LOG(_a, _b) mp4box_log _b +#endif + typedef enum { GF_FILE_TYPE_NOT_SUPPORTED = 0, @@ -53,26 +61,30 @@ typedef enum { void convert_file_info(char *inName, GF_ISOTrackID trackID); #endif -GF_Err parse_high_dynamc_range_xml_desc(GF_ISOFile* movie, char* file_name); +Bool mp4box_check_isom_fileopt(char *opt); + +GF_Err parse_high_dynamc_range_xml_desc(GF_ISOFile* movie, u32 track, char* file_name); #ifndef GPAC_DISABLE_ISOM_WRITE #ifndef GPAC_DISABLE_MEDIA_IMPORT -GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, GF_FilterSession *fsess, char **mux_args_if_first_pass, u32 tk_idx); +GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, GF_FilterSession *fsess, char **mux_args_if_first_pass, char **mux_sid_if_first_pass, u32 tk_idx); #else GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, GF_FilterSession *fsess, Bool second_pass) { return GF_NOT_SUPPORTED; } #endif -GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, char *inName, Double interleaving_time, Double chunk_start, Bool adjust_split_end, char *outName, const char *tmpdir, Bool force_rap_split, const char *split_range_str); -GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command, Bool is_pl); +GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u64 split_size_kb, char *inName, Double interleaving_time, Double chunk_start, u32 adjust_split_end, char *outName, Bool force_rap_split, const char *split_range_str, u32 fs_dump_flags); +GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, Bool force_cat, Bool align_timelines, Bool allow_add_in_command, Bool is_pl); + +GF_Err apply_edits(GF_ISOFile *dest, u32 track, char *edits); #if !defined(GPAC_DISABLE_SCENE_ENCODER) GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *logs); -GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext, const char *tmpdir); +GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext); #endif -GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool make_wgt); +GF_ISOFile *package_file(char *file_name, char *fcc, Bool make_wgt); #endif @@ -80,7 +92,7 @@ GF_Err dump_isom_cover_art(GF_ISOFile *file, char *inName, Bool is_final_name); GF_Err dump_isom_chapters(GF_ISOFile *file, char *inName, Bool is_final_name, Bool dump_ogg); GF_Err dump_isom_udta(GF_ISOFile *file, char *inName, Bool is_final_name, u32 dump_udta_type, u32 dump_udta_track); -GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array); +GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array, Bool is_string); u32 id3_get_genre_tag(const char *name); /*in filedump.c*/ @@ -91,9 +103,9 @@ GF_Err dump_isom_scene(char *file, char *inName, Bool is_final_name, GF_SceneDum #ifndef GPAC_DISABLE_SCENE_STATS void dump_isom_scene_stats(char *file, char *inName, Bool is_final_name, u32 stat_level); #endif -void PrintNode(const char *name, u32 graph_type); -void PrintBuiltInNodes(u32 graph_type, Bool dump_all); -void PrintBuiltInBoxes(Bool do_cov); +u32 PrintNode(const char *name, u32 graph_type); +u32 PrintBuiltInNodes(char *arg_val, u32 dump_type); +u32 PrintBuiltInBoxes(char *arg_val, u32 do_cov); #ifndef GPAC_DISABLE_ISOM_DUMP GF_Err dump_isom_xml(GF_ISOFile *file, char *inName, Bool is_final_name, Bool do_track_dump, Bool merge_vtt_cues, Bool skip_init, Bool skip_samples); @@ -108,18 +120,20 @@ void dump_isom_sdp(GF_ISOFile *file, char *inName, Bool is_final_name); #endif void dump_isom_timestamps(GF_ISOFile *file, char *inName, Bool is_final_name, Bool skip_offset); -void dump_isom_nal(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, Bool is_final_name, u32 dump_flags); +GF_Err dump_isom_nal(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, Bool is_final_name, u32 dump_flags); void dump_isom_saps(GF_ISOFile *file, GF_ISOTrackID trackID, u32 dump_saps_mode, char *inName, Bool is_final_name); +void dump_isom_chunks(GF_ISOFile *file, char *inName, Bool is_final_name); + #ifndef GPAC_DISABLE_ISOM_DUMP void dump_isom_ismacryp(GF_ISOFile *file, char *inName, Bool is_final_name); void dump_isom_timed_text(GF_ISOFile *file, GF_ISOTrackID trackID, char *inName, Bool is_final_name, Bool is_convert, GF_TextDumpType dump_type); #endif /*GPAC_DISABLE_ISOM_DUMP*/ -void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool is_track_num); -void DumpMovieInfo(GF_ISOFile *file); -void PrintLanguages(); +void DumpTrackInfo(GF_ISOFile *file, GF_ISOTrackID trackID, Bool full_dump, Bool is_track_num, Bool dump_m4sys); +void DumpMovieInfo(GF_ISOFile *file, Bool full_dump); +u32 PrintLanguages(char *argv, u32 opt); #ifndef GPAC_DISABLE_MPEG2TS void dump_mpeg2_ts(char *mpeg2ts_file, char *pes_out_name, Bool prog_num); @@ -139,7 +153,40 @@ u32 grab_live_m2ts(const char *grab_m2ts, const char *outName); GF_Err rip_mpd(const char *mpd, const char *dst_file); -GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); +GF_Err cat_playlist(GF_ISOFile *dest, char *playlistName, u32 import_flags, GF_Fraction force_fps, u32 frames_per_sample, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); + + +u32 parse_track_dump(char *arg, u32 dump_type); +u32 parse_track_action(char *arg, u32 act_type); +u32 parse_sdp_ext(char *arg_val, u32 param); +u32 parse_help(char *arg_val, u32 opt); +u32 parse_gendoc(char *name, u32 opt); +u32 parse_comp_box(char *arg_val, u32 opt); +u32 parse_dnal(char *arg_val, u32 opt); +u32 parse_dsap(char *arg_val, u32 opt); +u32 parse_bs_switch(char *arg_val, u32 opt); +u32 parse_cp_loc(char *arg_val, u32 opt); +u32 parse_pssh(char *arg_val, u32 opt); +u32 parse_sdtp(char *arg_val, u32 opt); +u32 parse_dash_profile(char *arg_val, u32 opt); +u32 parse_rap_ref(char *arg_val, u32 opt); +u32 parse_store_mode(char *arg_val, u32 opt); +u32 parse_base_url(char *arg_val, u32 opt); +u32 parse_multi_rtp(char *arg_val, u32 opt); +u32 parse_senc_param(char *arg_val, u32 opt); +u32 parse_cryp(char *arg_val, u32 opt); +u32 parse_fps(char *arg_val, u32 opt); +u32 parse_split(char *arg_val, u32 opt); +u32 parse_brand(char *b, u32 opt); +u32 parse_mpegu(char *arg_val, u32 opt); +u32 parse_file_info(char *arg_val, u32 opt); +u32 parse_boxpatch(char *arg_val, u32 opt); +u32 parse_aviraw(char *arg_val, u32 opt); +u32 parse_dump_udta(char *code, u32 opt); +u32 parse_dump_ts(char *arg_val, u32 opt); +u32 parse_ttxt(char *arg_val, u32 opt); +u32 parse_dashlive(char *arg, char *arg_val, u32 opt); +u32 parse_compress(char *arg_val, u32 opt); #endif // _MP4BOX_H diff --git a/applications/mp4box/wrapper.c b/applications/mp4box/wrapper.c deleted file mode 100644 index 74e84e6..0000000 --- a/applications/mp4box/wrapper.c +++ /dev/null @@ -1,102 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "stdlib.h" -#include "stdio.h" -#include "string.h" - - -#define jniTAG "WRAPPER_JNI" - -#define jniLOGV(X) __android_log_print(ANDROID_LOG_VERBOSE, jniTAG, X) -#define jniLOGI(X) __android_log_print(ANDROID_LOG_INFO, jniTAG, X) -#define jniLOGE(X) __android_log_print(ANDROID_LOG_ERROR, jniTAG, X) - -/*#define CAST_HANDLE(wr) jclass c = env->GetObjectClass(obj);\ - if (!c) return;\ - jfieldID fid = env->GetFieldID(c, "handle", "J");\ - if (!fid){\ - __android_log_print(ANDROID_LOG_ERROR, jniTAG, "No Field ID, ERROR");\ - return;\ - }\ - jlong h = env->GetLongField(obj, fid); - //CNativeWrapper* wr = (CNativeWrapper*) h;*/ - -char ** ConvertCommandLine( const char* sCommand, int* iNbArg ); - -JNIEXPORT void JNICALL Java_com_enst_mp4box_mp4terminal_run(JNIEnv * env, jobject obj, jstring sCommand) -{ - //CAST_HANDLE(wr); - jniLOGV("mp4terminal::start"); - /*if (!wr) - { - jniLOGV("mp4terminal::end : aborted"); - return; - }*/ - jboolean isCopy; - const char * sOriginalCommand = (*env)->GetStringUTFChars(env, sCommand, &isCopy); - - jniLOGV("mp4terminal::command get back ok"); - jniLOGV(sOriginalCommand); - - int i = 0; - char** sConvertedCommandLine; - sConvertedCommandLine = ConvertCommandLine( sOriginalCommand, &i ); - - jniLOGV("Convert command line done"); - FILE* ferr = freopen( "/mnt/sdcard/stderrout.txt", "w", stderr ); - - FILE* fout = freopen( "/mnt/sdcard/stdout.txt", "w", stdout ); - - mp4boxMain(i, sConvertedCommandLine); - - (*env)->ReleaseStringUTFChars(env, sCommand, sOriginalCommand); - jniLOGV("mp4terminal::end"); - gf_fclose(ferr); - gf_fclose(fout); -} - -char ** ConvertCommandLine( const char* sCommand, int* iNbArg ) -{ - int iLength = strlen( sCommand ); - int iArgNumber = 1; - int i = 0; - char** pReturn; - int iPreviousPos = 0; - int k = 1;//begin at character position 1 as the 0 position will be held by the process name , i.e. mp4box - int l = 0; - - for ( i = 0; i < iLength ; i++ ) - { - if( sCommand[i] == ' ' ) - { - iArgNumber++; - } - } - iArgNumber++;; // last argument will not be detected as it is not followed by a space character - pReturn = (char**)malloc(sizeof(char*)*iArgNumber); - pReturn[0] = (char*)malloc(sizeof( char) * ( 7 )); - strcpy( pReturn[0], "MP4Box" );//just a place holder , will never be read. - pReturn[0][6] = '\0'; - - for ( l = 0; l <= iLength ; l++ ) - { - if( sCommand[l] == ' ' || l == ( iLength ) ) - { - pReturn[k] = (char*)malloc(sizeof( char) * ( l - iPreviousPos + 1)); - strncpy( pReturn[k], sCommand + iPreviousPos, l - iPreviousPos ); - pReturn[k][l-iPreviousPos] = '\0'; - iPreviousPos = l + 1; - k++; - } - } - *iNbArg = iArgNumber; - return pReturn; -} -#ifdef __cplusplus -} -#endif - diff --git a/applications/mp4client/Makefile b/applications/mp4client/Makefile index caea206..f39c315 100644 --- a/applications/mp4client/Makefile +++ b/applications/mp4client/Makefile @@ -58,6 +58,10 @@ endif SRCS := $(OBJS:.o=.c) +ifeq ($(CONFIG_WIN32),yes) +OBJS+=$(SRC_PATH)/manifest.o +endif + all: $(PROG) MP4Client$(EXE): $(OBJS) diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c index 4a1b1d2..d270560 100644 --- a/applications/mp4client/main.c +++ b/applications/mp4client/main.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2005-2020 + * Copyright (c) Telecom ParisTech 2005-2022 * All rights reserved * * This file is part of GPAC / command-line client @@ -286,6 +286,9 @@ void PrintUsage(Bool show_all) "# General\n" "The player accepts any URL supported by GPAC.\n" "Specific URLs shortcuts are available, see [GPAC Compositor (gpac -h compositor)](compositor)\n" + "\n" + "Warning: MP4Client is being deprecated, use `gpac -play URL`, `gpac -gui URL` or `gpac -mp4c URL`.\n" + "\n" "Version: %s\n" "%s\n" "For more info on GPAC configuration, use `gpac ` [-h](GPAC) `bin` \n \n" @@ -1250,7 +1253,7 @@ int mp4client_main(int argc, char **argv) fprintf(helpout, ".SH EXAMPLES\n.TP\nBasic and advanced examples are available at https://wiki.gpac.io/mp4client\n"); fprintf(helpout, ".SH MORE\n.LP\nAuthors: GPAC developers, see git repo history (-log)\n" - ".br\nFor bug reports, feature requests, more information and source code, visit http://github.com/gpac/gpac\n" + ".br\nFor bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac\n" ".br\nbuild: %s\n" ".br\nCopyright: %s\n.br\n" ".SH SEE ALSO\n" @@ -1391,7 +1394,7 @@ int mp4client_main(int argc, char **argv) TCHAR buffer[1024]; DWORD res = GetCurrentDirectory(1024, buffer); buffer[res] = 0; - opt = gf_opts_get_key("core", "mod-dirs"); + opt = gf_opts_get_key("core", "module-dir"); if (strstr(opt, buffer)) { gui_mode=1; } else { @@ -1494,26 +1497,12 @@ int mp4client_main(int argc, char **argv) strcpy(the_url, url_arg); } ext = strrchr(the_url, '.'); - if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) { + //only local playlist - maybe we could remove and control through flist ? + if (ext && !strncmp("http", the_url, 4) && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) { e = GF_OK; fprintf(stderr, "Opening Playlist %s\n", the_url); strcpy(pl_path, the_url); - /*this is not clean, we need to have a plugin handle playlist for ourselves*/ - if (!strncmp("http:", the_url, 5)) { -#ifdef FILTER_FIXME - GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e); - if (sess) { - e = gf_dm_sess_process(sess); - if (!e) { - strncpy(the_url, gf_dm_sess_get_cache_name(sess), sizeof(the_url) - 1); - the_url[sizeof(the_url) - 1] = 0; - } - gf_dm_sess_del(sess); - } -#endif - } - playlist = e ? NULL : gf_fopen(the_url, "rt"); readonly_playlist = 1; if (playlist) { @@ -2610,7 +2599,7 @@ static void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number, const char *szURL) fprintf(stderr, "\tBitrate over last second: %d kbps\n\tMax bitrate over one second: %d kbps\n\tAverage Decoding Time %.2f us %d max)\n\tTotal decoded frames %d\n", (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time, odi.nb_dec_frames); } - if (odi.protection) fprintf(stderr, "Encrypted Media%s\n", (odi.protection==2) ? " NOT UNLOCKED" : ""); + if (odi.protection) fprintf(stderr, "Encrypted Media scheme %s\n", gf_4cc_to_str(odi.protection) ); fprintf(stderr, "\nStream ID %d - %s - Clock ID %d\n", odi.pid_id, gf_stream_type_name(odi.od_type), odi.ocr_id); // if (esd->dependsOnESID) fprintf(stderr, "\tDepends on Stream ID %d for decoding\n", esd->dependsOnESID); diff --git a/applications/mp4client/mp4client.rc b/applications/mp4client/mp4client.rc index d902032..8c7fa31 100644 --- a/applications/mp4client/mp4client.rc +++ b/applications/mp4client/mp4client.rc @@ -7,7 +7,7 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include "windows.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -34,7 +34,7 @@ END 2 TEXTINCLUDE BEGIN - "#include ""afxres.h""\r\n" + "#include ""windows.h""\r\n" "\0" END diff --git a/configure b/configure index de8ea99..25d67dc 100755 --- a/configure +++ b/configure @@ -1,8 +1,8 @@ #!/bin/sh # # GPAC configure script -# (c) 2003-2018 Telecom ParisTech -# Authors: Jean Le Feuvre, Romain Bouqueau +# (c) 2003-2022 Telecom ParisTech +# Authors: Jean Le Feuvre, Romain Bouqueau, Aurelien David # #set -v @@ -78,6 +78,7 @@ has_xvid="no" has_mad="no" has_faad="no" has_ffmpeg="no" +ffmpeg_vvc="no" has_amr_nb_fixed="no" has_amr_nb="no" has_amr_wb="no" @@ -111,8 +112,9 @@ has_joystick="no" has_hid="no" has_sock_un="no" has_lzma="no" +has_nghttp2="no" enable_joystick="no" -static_mp4box="no" +static_bin="no" disable_core_tools="no" disable_3d="no" disable_svg="no" @@ -161,18 +163,20 @@ disable_vobsub="no" disable_ttxt="no" disable_ttml="no" disable_hevc="no" -disable_atsc="no" +disable_route="no" disable_crypto="no" +disable_log="no" +disable_nvdec="no" enable_qjs="yes" +enable_qjs_libc="yes" enable_depth_compositor="no" -enable_renoir="no" enable_sanitizer="no" -has_avcap="no" -avcap_cflags="" -avcap_ldflags="-lavcap" has_opensvc="no" has_openhevc="no" has_vtb="no" +has_strlcpy="no" +disable_codecs="no" +enable_qjs_stack_check="no" win32="no" mingw32="no" @@ -197,6 +201,7 @@ OSS_LDFLAGS="" INSTFLAGS="" is_64="no" ffmpeg_extra_ldflags="" +has_st_nsec="no" logs="config.log" echo "Logs for GPAC configure $GPAC_CONFIGURATION" > $logs @@ -239,10 +244,10 @@ GPAC configuration options: --enable-pic enable Position Independant Code for shared objects --strip enable strip --std-allocator uses standard lib memory allocator - --static-modules includes static modules in libgpac whenever possible --enable-mem-track enable tracking of all memory allocated by gpac - --enable-sanitizer enable adress sanitizer + --enable-sanitizer enable address sanitizer --enable-afl enable instrumentation for American Fuzzy Lop + --enable-afl-clang enable instrumentation for American Fuzzy Lop using afl-clang(++) --disable-opt disable GCC optimizations --disable-ipv6 disable IPV6 support --disable-platinum disable Platinum UPnP support @@ -263,9 +268,13 @@ GPAC configuration options: --enable-amr-nb enable AMR NB library --enable-amr-wb enable AMR WB library --enable-amr enable both AMR NB and WB libraries - --enable-static-bin link statically against libgpac - --static-mp4box configure for static linking of MP4Box only. + --static-modules use static modules in libgpac rather than dynamic library modules + --static-build link statically against libgpac but still allow dependencies to shared libraries (enable --static-modules) + --enable-static-bin old name for --static-build, deprecated + --static-bin enable static linking of MP4Box and gpac only (enable --static-build), disable MP4Client and all libraries not linkable statically. + --static-mp4box old name for --static-bin, deprecated --enable-depth enables depth handling in the compositor + --enable-qjs-stack enables stack depth checking in QuickJS (WILL CRASH in multithreaded modes) Configuration options for libgpac - all options can be enabled with --enable-optname --disable-all disables all features in libgpac @@ -312,8 +321,10 @@ Configuration options for libgpac - all options can be enabled with --enable-opt --disable-player disable player (terminal and compositor) --disable-scenegraph disable scenegraph, scene parsers and player (terminal and compositor) --disable-hevc disable HEVC support - --disable-atsc disable ATSC3 support + --disable-route disable ROUTE (ATSC3) support --disable-crypto disable crypto support + --disable-nvdec disable NVDec support + --disable-codecs disable all media decoders and encoders Extra libraries configuration. You can turn a library off or force using the local version in gpac/extra_lib/ --use-ft=OPT force FreeType OPT=[no,local] @@ -335,6 +346,8 @@ EOF exit 1 fi +use_static="no" + for opt do case "$opt" in --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` @@ -375,8 +388,16 @@ for opt do ;; --enable-afl) cc_orig="afl-gcc"; cxx_orig="afl-g++" ;; + --enable-afl-clang) cc_orig="afl-clang"; cxx_orig="afl-clang++" + ;; --verbose) verbose="yes"; ;; + --static-bin) use_static="yes" + ;; + --static-mp4box) use_static="yes" + ;; + --enable-sanitizer) enable_sanitizer="yes" + ;; esac done @@ -457,9 +478,23 @@ cxx="${cross_prefix}${cxx}" ar="${cross_prefix}${ar}" ranlib="${cross_prefix}${ranlib}" strip="${cross_prefix}${strip}" -pkg_config="${pkg_config}" windres="${cross_prefix}${windres}" +if test "$enable_sanitizer" = "yes" ; then +if test "$use_static" = "yes" ; then +echo "Cannot use static bin with sanitizer, disabling static bin" +use_static="no" +fi +fi + +if test "$use_static" = "yes" ; then +pkg_config="${pkg_config} --static" +if test "$darwin" != "yes" ; then + LDFLAGS="-static $LDFLAGS" +fi +else +pkg_config="${pkg_config}" +fi #check pkg_config if test "$cross_prefix" = "" ; then @@ -601,7 +636,7 @@ EOF CFLAGS="$CFLAGS -I/mingw32/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" LDFLAGS="$LDFLAGS -L/mingw32/lib" else - extralibs="$extralibs -lws2_32 -lwinmm -limagehlp" + extralibs="$extralibs -lws2_32 -lwinmm -limagehlp -ldbghelp" CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" fi LDFLAGS="$LDFLAGS" @@ -777,6 +812,17 @@ fi +#check st_mtim.tv_nsec +cat > $TMPC << EOF +#include +int main( void ) { struct stat st; st.st_mtim.tv_nsec = 0; return 0; } +EOF + +if docc ; then + has_st_nsec="yes" +fi + + #look for platinum support cat > $TMPCXX << EOF #include @@ -786,39 +832,6 @@ if docxx -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer has_platinum="yes" fi -#look for avcap support -avcap_cflags="" -avcap_ldflags="-lavcap" - -cat > $TMPC << EOF -#include -using namespace avcap; -int main( void ) { - const DeviceCollector::DeviceList& dl = DEVICE_COLLECTOR::instance().getDeviceList(); - DeviceDescriptor* dd = 0; - for (DeviceCollector::DeviceList::const_iterator i = dl.begin(); i != dl.end(); i++) { - dd = *i; - std::cout << dd->getName().c_str() << "\n"; - } - return 0; -} -EOF -if docxx -o $TMPO $TMPC $LDFLAGS $avcap_cflags $avcap_ldflags ; then - has_avcap="yes" -else - if test "$darwin" = "yes" ; then - avcap_cflags="-I$local_inc -I$local_inc/avcap/osx" - avcap_ldflags="${wl}-flat_namespace -lavcap -lpthread -framework QuickTime -framework QuartzCore" - else - avcap_cflags="-I$local_inc -I$local_inc/avcap/linux" - avcap_ldflags="-lavcap -lpthread" - fi - if docxx -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags ; then - has_avcap="yes" - avcap_ldflags="-L$local_lib $avcap_ldflags" - fi -fi - #look for opensvc support @@ -904,7 +917,7 @@ fi if test "$has_ft" = "no" ; then ft_cflags="-I$local_inc/freetype" ft_lflags="-L$local_lib -lfreetype" - if docc $ft_cflags $ft_lflags ; then + if docc $ft_cflags $ft_lflags $LDFLAGS ; then has_ft="local" fi fi @@ -1010,7 +1023,7 @@ fi if test "$has_jpeg" = "no" ; then jpeg_cflags="-I$local_inc/jpeg" jpeg_lflags="-L$local_lib -ljpeg" - if docc $jpeg_cflags $jpeg_lflags ; then + if docc $jpeg_cflags $jpeg_lflags $LDFLAGS ; then has_jpeg="local" fi fi @@ -1054,7 +1067,7 @@ if test "$cross_prefix" = "" ; then fi if test "$has_openjpeg" = "no" ; then - if docc -I$local_inc/openjpeg -L$local_lib -lopenjpeg ; then + if docc -I$local_inc/openjpeg -L$local_lib -lopenjpeg $LDFLAGS ; then has_openjpeg="local" openjpeg_ldflags="-lopenjpeg" fi @@ -1086,7 +1099,7 @@ if test "$cross_prefix" = "" ; then fi fi if test "$has_png" = "no" ; then - if docc -I$local_inc/png -L$local_lib -lpng ; then + if docc -I$local_inc/png -L$local_lib -lpng $LDFLAGS ; then has_png="local" fi fi @@ -1112,13 +1125,12 @@ if test "$cross_prefix" = "" ; then fi fi if test "$has_mad" = "no" ; then - if docc -I$local_inc -L$local_lib -lmad ; then + if docc -I$local_inc -L$local_lib -lmad $LDFLAGS ; then has_mad="local" fi fi - #look for A52DEC support cat > $TMPC << EOF #include @@ -1142,13 +1154,12 @@ if test "$cross_prefix" = "" ; then fi fi if test "$has_a52" = "no" ; then - if docc -I$local_inc -L$local_lib -la52 ; then + if docc -I$local_inc -L$local_lib -la52 $LDFLAGS ; then has_a52="local" fi fi - #look for XVID support cat > $TMPC << EOF #include @@ -1170,13 +1181,12 @@ if test "$cross_prefix" = "" ; then fi fi if test "$has_xvid" = "no" ; then - if docc -I$local_inc -L$local_lib -lxvidcore -lpthread ; then + if docc -I$local_inc -L$local_lib -lxvidcore -lpthread $LDFLAGS ; then has_xvid="local" fi fi - #look for FAAD support cat > $TMPC << EOF #include @@ -1196,13 +1206,12 @@ if test "$cross_prefix" = "" ; then fi fi if test "$has_faad" = "no" ; then - if docc -I$local_inc -L$local_lib -lfaad -lm ; then + if docc -I$local_inc -L$local_lib -lfaad -lm $LDFLAGS ; then has_faad="local" fi fi - #look for FFMPEG support ffmpeg_cflags="" @@ -1274,7 +1283,7 @@ if test "$cross_prefix" = "" ; then fi fi if test "$has_ffmpeg" = "no" ; then - if docc -I$local_inc -L$local_lib $ffmpeg_lflags ; then + if docc -I$local_inc -L$local_lib $ffmpeg_lflags $LDFLAGS ; then has_ffmpeg="local" ffmpeg_cflags="-I$local_inc" ffmpeg_lflags="-L$local_lib $ffmpeg_lflags" @@ -1347,6 +1356,19 @@ else fi +#detect vvc support in ffmpegf +cat > $TMPC << EOF +#include +int main(void) { + AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_VVC); + return 0; +} +EOF + +if docc $ffmpeg_cflags $ffmpeg_lflags ; then + ffmpeg_vvc="yes" +fi + #look for FREENECT support freenect_flags="" freenect_ld="-lfreenect" @@ -1460,6 +1482,7 @@ EOF if docc $LDFLAGS $vtb_ldflags ; then has_vtb="yes" fi + fi @@ -1665,12 +1688,65 @@ EOF if docc $CFLAGS_DIR -llzma $LDFLAGS ; then has_lzma="yes" - GPAC_SH_FLAGS="$GPAC_SH_FLAGS -llzma" - if test "$win32" = "yes"; then - extralibs="$extralibs -llzma" +fi + +#look for strlcpy support +cat > $TMPC << EOF +#include +int main( void ) { + char dest[1]; + strlcpy(dest, "1", 1); + return 0; +} +EOF + +if docc $LDFLAGS ; then + has_strlcpy="yes" +fi + + +#look for nghttp2 support + +if test "$cross_prefix" = "" -a "$pkg_config" != "no"; then + if $pkg_config --exists libnghttp2 ; then + has_nghttp2="system" + nghttp2_cflags=`$pkg_config --cflags libnghttp2` + nghttp2_ldflags=`$pkg_config --libs libnghttp2` fi fi +if test "$has_nghttp2" = "no" ; then +cat > $TMPC << EOF +#include +#include +int main( void ) { return 0; } +EOF + +if docc $LDFLAGS -lnghttp2 ; then + has_nghttp2="system" + nghttp2_ldflags="-lnghttp2" +fi +if test "$cross_prefix" = "" ; then + if test "$has_nghttp2" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lnghttp2 2>>$logs ; then + has_nghttp2="system" + nghttp2_ldflags="-lnghttp2" + fi + fi + fi +fi + +if test "$has_nghttp2" = "no" ; then + if docc -I$local_inc -L$local_lib -lnghttp2 $LDFLAGS ; then + has_nghttp2="local" + nghttp2_ldflags="-lnghttp2" + fi +fi + +fi + + #overwrite detection with manual settings for opt do case "$opt" in @@ -1708,7 +1784,11 @@ for opt do ;; --enable-gprof) gprof_build="yes"; ;; - --enable-static-bin) static_build="yes"; + --static-build) static_build="yes"; + ;; + --enable-static-bin) + echo "$opt deprecated, use --static-build instead" + static_build="yes"; ;; --disable-ipv6) has_ipv6="no" ;; @@ -1728,8 +1808,6 @@ for opt do ;; --enable-mem-track) use_memory_tracking="yes" ;; - --enable-sanitizer) enable_sanitizer="yes" - ;; --enable-tinygl) enable_tinygl="yes" ;; --disable-ssl) has_ssl="no" @@ -1738,7 +1816,13 @@ for opt do ;; --enable-depth) enable_depth_compositor="yes" ;; - --static-mp4box) static_mp4box="yes" + --enable-qjs-stack) enable_qjs_stack_check="yes" + ;; + --static-bin) static_bin="yes" + ;; + --static-mp4box) + echo "$opt deprecated, use --static-bin instead" + static_bin="yes" ;; --use-faad=*) has_faad=${opt#--use-faad=} ;; @@ -1812,9 +1896,9 @@ for opt do ;; --enable-pulseaudio) has_pulseaudio="yes" ;; - --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_crypto="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_vtt="yes"; disable_ttml="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds="yes"; disable_hevc="yes" ; disable_atsc="yes" ; enable_qjs="no" + --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_log="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_crypto="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_vtt="yes"; disable_ttml="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds="yes"; disable_hevc="yes" ; disable_nvdec="yes" ; disable_route="yes" ; enable_qjs="no" ;; - --isomedia-only) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_crypto="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_hevc="no"; disable_isoff="no"; disable_isoff_hds="no"; disable_isoff_write="no"; disable_isoff_hint="no"; disable_isoff_frag="no" ; disable_atsc="yes" ; enable_qjs="no" + --isomedia-only) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_crypto="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_hevc="no"; disable_isoff="no"; disable_isoff_hds="no"; disable_isoff_write="no"; disable_isoff_hint="no"; disable_isoff_frag="no" ; disable_route="yes" ; disable_nvdec="yes" ; enable_qjs="no" ;; --disable-3d) disable_3d="yes" ;; @@ -2010,14 +2094,26 @@ for opt do ;; --enable-hevc) disable_hevc="no" ;; - --disable-atsc) disable_atsc="yes" + --disable-route) disable_route="yes" ;; - --enable-atsc) disable_atsc="no" + --enable-route) disable_route="no" ;; --disable-qjs) enable_qjs="no" ;; --enable-qjs) enable_qjs="yes" ;; + --disable-qjs-libc) enable_qjs_libc="no" + ;; + --enable-qjs-libc) enable_qjs_libc="yes" + ;; + --disable-log) disable_log="yes" + ;; + --enable-log) disable_log="no" + ;; + --disable-nvdec) disable_nvdec="yes" + ;; + --disable-codecs) disable_codecs="yes" + ;; esac done @@ -2032,6 +2128,12 @@ if test "$disable_core_tools" = "no"; then echo "error: zlib not found on system or in local libs" exit 1 fi + if test "$has_zlib" = "force-no" ; then + # can't have libpng without zlib + has_png="no" + # can't have freetype without libpng + has_ft="no" + fi if test "$dlopen" = "no"; then if test "$win32" = "no"; then echo "error: dlopen not found on system" @@ -2248,38 +2350,91 @@ if test x"$mandir" = x""; then mandir="share/man" fi -if test "$static_mp4box" = "yes"; then - has_opengl="no" - has_ssl="no" - has_js="no" + +if test "$disable_codecs" = "yes"; then has_jpeg="no" has_png="no" has_mad="no" - has_ft="no" - has_openjpeg="no" + has_a52="no" has_mad="no" has_faad="no" has_xvid="no" + has_opensvc="no" + has_openjpeg="no" has_ffmpeg="no" has_ogg="no" has_theora="no" has_vorbis="no" - has_a52="no" - has_opensvc="no" + has_openhevc="no" +fi + +if test "$static_bin" = "yes"; then + static_modules="yes" + static_build="yes" + #we cannot use openssl vanilla since it is usually built with DSO and requires dlopen + has_ssl="no" + #we cannot use ipv6 due to getaddrinfo not being present + has_ipv6="no" + +# has_js="no" +# has_ft="no" +# has_jpeg="no" +# has_png="no" +# has_mad="no" +# has_a52="no" +# has_mad="no" +# has_faad="no" +# has_xvid="no" +# has_opensvc="no" + + #we cannot use openjpeg to produce a static bin, no static lib on most distributions + has_openjpeg="no" + + #we cannot use FFMPEG to produce a static bin, no static lib on most distributions. This could be done by building a local statoc only ffmpeg +if test "$has_ffmpeg" = "system" ; then + has_ffmpeg="no" +fi + + #we cannot use ogg/theora/vorbis to produce a static bin, no static lib on most distributions, issues with lm acosf_finite, log_finite, ... + has_ogg="no" + has_theora="no" + has_vorbis="no" + #we cannot use openhevc to produce a static bin, dependencies to avcodec/avformat. We need a static ffmpeg build with openhevc support has_openhevc="no" has_freenect="no" has_platinum="no" - static_build="yes" + has_lzma="no" + has_vtb="no" + +#we cannot use openGL nor audio/video output to produce a static bin + has_opengl="no" + has_sdl="no" + has_oss_audio="no" + has_alsa="no" + has_jack="no" + has_pulseaudio="no" + has_directfb="no" + has_x11="no" + has_dvb4linux="no" + has_mingw_directx="no" + fi if test "$cpu" = "sh4"; then viren_dir="`ls \"$source_path/modules\" | grep viren_out`" if test "$viren_dir" = "viren_out"; then enable_depth_compositor="yes" - enable_renoir="yes" fi fi +if test "$has_lzma" = "yes"; then + GPAC_SH_FLAGS="$GPAC_SH_FLAGS -llzma" + if test "$win32" = "yes"; then + extralibs="$extralibs -llzma" + fi +fi + + if test "$disable_player" = "yes" ; then disable_scenegraph="yes" fi @@ -2304,6 +2459,7 @@ if test "$disable_scenegraph" = "yes" ; then disable_streaming="yes" disable_player="yes" disable_smgr="yes" + disable_nvdec="yes" has_js="no" fi @@ -2337,7 +2493,7 @@ soname_version="${version_major}.${version_minor}.${version_micro}" #check revision.h cd $source_path -./check_revision.sh +. ./check_revision.sh cd $build_path echo "" @@ -2354,21 +2510,34 @@ if test $cpu = "mips"; then fi echo "" echo "** GPAC $version rev$revision Core Configuration **" +if test "$static_bin" = "yes" ; then + echo "Static binaries enabled" + echo "#define GPAC_STATIC_BUILD" >> $TMPH +elif test "$static_build" = "yes" ; then + echo "Static build enabled" + echo "#define GPAC_STATIC_BUILD" >> $TMPH +else + echo "Static Modules: $static_modules" +fi echo "debug version: $debuginfo" echo "GProf enabled: $gprof_build" -echo "Static build enabled: $static_build" echo "Memory tracking enabled: $use_memory_tracking" echo "Sanitizer enabled: $enable_sanitizer" echo "Fixed-Point Version: $use_fixed_point" echo "IPV6 Support: $has_ipv6" -echo "Static Modules: $static_modules" -echo "QuickJS Support: $enable_qjs" +echo "QuickJS Support: $enable_qjs (qjslibc $enable_qjs_libc)" if test "$disable_player" = "yes" ; then echo "Player disabled" echo "#define GPAC_DISABLE_PLAYER" >> $TMPH disable_laser="yes" fi + +if test "$has_st_nsec" = "yes" ; then + echo "#define GPAC_HAS_MTIM_NSEC" >> $TMPH +fi + + if test "$disable_smgr" = "yes" ; then disable_seng="yes" disable_qtvr="yes" @@ -2562,6 +2731,10 @@ if test "$enable_depth_compositor" = "yes" ; then echo "#define GF_SR_USE_DEPTH" >> $TMPH fi +if test "$enable_qjs_stack_check" = "yes" ; then + echo "#define GPAC_QJS_STACK_CHECK" >> $TMPH +fi + if test "$disable_mpd" = "yes" ; then echo "HLS and DASH Manifest Disabled" echo "#define GPAC_DISABLE_MPD" >> $TMPH @@ -2577,9 +2750,9 @@ if test "$disable_hevc" = "yes" ; then echo "#define GPAC_DISABLE_HEVC" >> $TMPH fi -if test "$disable_atsc" = "yes" ; then - echo "ATSC3 Support disabled" - echo "#define GPAC_DISABLE_ATSC" >> $TMPH +if test "$disable_route" = "yes" ; then + echo "ROUTE Support disabled" + echo "#define GPAC_DISABLE_ROUTE" >> $TMPH fi if test "$disable_crypto" = "yes" ; then @@ -2587,40 +2760,43 @@ if test "$disable_crypto" = "yes" ; then echo "#define GPAC_DISABLE_CRYPTO" >> $TMPH fi +if test "$disable_log" = "yes" ; then + echo "Logging disabled" + echo "#define GPAC_DISABLE_LOG" >> $TMPH +fi + echo "" echo "** Detected libraries **" echo "zlib: $has_zlib" +echo "OpenGL support: $has_opengl" +echo "TinyGL support: $has_tinygl" +echo "OpenSSL support: $has_ssl" if test "$win32" != "yes" ; then echo "OSS Audio: $has_oss_audio" echo "ALSA Audio: $has_alsa" echo "Jack Audio: $has_jack" - echo "PulseAudio Audio: $has_pulseaudio" - echo "DirectFB support: $has_directfb" + echo "Pulse Audio: $has_pulseaudio" + echo "DirectFB: $has_directfb" if test "$has_x11" != "no" ; then echo "X11 Shared Memory support: $has_x11_shm (path: $X11_PATH)" echo "X11 XVideo support: $has_x11_xv" fi fi -echo "SDL Support: $has_sdl" +echo "SDL: $has_sdl" if test "$sdl_too_old" = "yes" ; then echo "SDL Version too old - please upgrade for SDL support" fi -echo "OpenGL support: $has_opengl" -echo "TinyGL support: $has_tinygl" -echo "OpenSSL support: $has_ssl" if test "$win32" = "yes" ; then - echo "DirectX Support: $has_mingw_directx" + echo "DirectX: $has_mingw_directx" fi if test "$linux" = "yes" ; then - echo "DVB Support: $has_dvb4linux" + echo "DVB for Linux: $has_dvb4linux" fi -echo "" -echo "** Extra Libraries used **" echo "FreeType: $has_ft" echo "JPEG: $has_jpeg" echo "OpenJPEG: $has_openjpeg" @@ -2629,10 +2805,15 @@ echo "MAD: $has_mad" echo "FAAD: $has_faad" echo "XVID: $has_xvid" echo "FFMPEG: $has_ffmpeg" +if test "$has_ffmpeg" != "no" ; then +if test "$ffmpeg_vvc" = "yes" ; then +echo "FFMPG VVC Support: $ffmpeg_vvc" +fi +fi echo "LZMA: $has_lzma" echo "Xiph OGG: $has_ogg" echo "Platinum UPnP: $has_platinum" -echo "AVCap: $has_avcap" + if test "$has_ogg" = "no"; then has_ogg="no" else @@ -2643,10 +2824,8 @@ echo "A52 (AC3): $has_a52" echo "OpenSVCDecoder: $has_opensvc" echo "OpenHEVCDecoder: $has_openhevc" echo "Freenect: $has_freenect" +echo "nghttp2: $has_nghttp2" -if test "$enable_renoir" = "yes" ; then - echo "Renoir enabled - make sure the driver libraries are present in modules/viren_out directory" -fi if test "$has_amr_nb_fixed" = "yes" ; then echo "" @@ -2697,7 +2876,7 @@ fi if test "$enable_sanitizer" = "yes" ; then - CFLAGS="$CFLAGS -fsanitize=address,undefined -fno-sanitize-recover -g" + CFLAGS="$CFLAGS -fsanitize=address,undefined -fno-sanitize-recover -g -fno-omit-frame-pointer -DASAN_ENABLED" LDFLAGS="$LDFLAGS -fsanitize=address,undefined -ldl" fi @@ -2735,7 +2914,7 @@ echo "STRIP=@$strip" >> config.mak echo "WINDRES=$windres" >> config.mak fi echo "INSTALL=$install" >> config.mak -echo "LIBTOOL=libtool" >> config.mak +echo "LIBTOOL=@libtool" >> config.mak echo "INSTFLAGS=$instflags" >> config.mak echo "OPTFLAGS=$CFLAGS" >> config.mak @@ -2865,6 +3044,10 @@ echo "INSTFLAGS=$INSTFLAGS" >> config.mak echo "CONFIG_JS=$enable_qjs" >> config.mak if test "$enable_qjs" = "yes" ; then echo "#define GPAC_HAS_QJS" >> $TMPH +if test "$enable_qjs_libc" = "no" ; then +echo "#define GPAC_DISABLE_QJS_LIBC" >> $TMPH +fi + fi if test "$has_zlib" = "no" -o "$has_zlib" = "force-no" ; then @@ -2893,6 +3076,11 @@ if test "$has_vtb" != "no" ; then echo "vtb_ldflags=$vtb_ldflags" >> config.mak fi +echo "CONFIG_STRLCPY=$has_strlcpy" >> config.mak +if test "$has_strlcpy" != "no" ; then + echo "#define GPAC_HAS_STRLCPY" >> $TMPH +fi + if test "$has_sock_un" != "no" ; then echo "#define GPAC_HAS_SOCK_UN" >> $TMPH fi @@ -2938,6 +3126,9 @@ else echo "CONFIG_LIBAV=$is_libav" >> config.mak echo "CONFIG_LIBSWRESAMPLE=$has_libswresample" >> config.mak echo "#define GPAC_HAS_FFMPEG" >> $TMPH + if test "$ffmpeg_vvc" = "yes"; then + echo "#define FFMPEG_ENABLE_VVC" >> $TMPH + fi fi echo "CONFIG_FFMPEG_OLD=$old_ffmpeg_inc" >> config.mak @@ -2960,6 +3151,14 @@ if test "$want_gcov" = "yes" ; then echo "#define GPAC_ENABLE_COVERAGE" >> $TMPH fi +echo "CONFIG_NGHTTP2=$has_nghttp2" >> config.mak +if test "$has_nghttp2" != "no" ; then + echo "NGHTTP2_CFLAGS=$nghttp2_cflags" >> config.mak + echo "NGHTTP2_LDFLAGS=$nghttp2_ldflags" >> config.mak + echo "#define GPAC_HAS_HTTP2" >> $TMPH +fi + + echo "DISABLE_PLAYER=$disable_player" >> config.mak echo "DISABLE_STREAMING=$disable_streaming" >> config.mak echo "DISABLE_SVG=$disable_svg" >> config.mak @@ -2998,7 +3197,7 @@ echo "DISABLE_OD_PARSE=$disable_od_parse" >> config.mak echo "MINIMAL_OD=$disable_od" >> config.mak echo "DISABLE_ISOM_ADOBE=$disable_isoff_hds" >> config.mak echo "DISABLE_VRML=$disable_vrml" >> config.mak -echo "DISABLE_ATSC=$disable_atsc" >> config.mak +echo "DISABLE_ROUTE=$disable_route" >> config.mak echo "DISABLE_CRYPTO=$disable_crypto" >> config.mak if test "$disable_parsers" = "yes" ; then @@ -3023,6 +3222,10 @@ if test "$has_tinygl" = "yes" ; then echo "#define GPAC_USE_TINYGL" >> $TMPH fi +if test "$disable_nvdec" = "yes" ; then + echo "#define GPAC_DISABLE_NVDEC" >> $TMPH +fi + echo "ENABLE_JOYSTICK=$has_joystick" >> config.mak echo "HAS_OPENSSL=$has_ssl" >> config.mak @@ -3047,7 +3250,7 @@ echo "CONFIG_AMR_NB_FT=$has_amr_nb" >> config.mak echo "CONFIG_AMR_WB_FT=$has_amr_wb" >> config.mak echo "DEBUGBUILD=$debuginfo" >> config.mak echo "GPROFBUILD=$gprof_build" >> config.mak -echo "MP4BOX_STATIC=$static_mp4box" >> config.mak +echo "STATIC_BINARY=$static_bin" >> config.mak echo "STATICBUILD=$static_build" >> config.mak echo "CONFIG_IPV6=$has_ipv6" >> config.mak @@ -3068,12 +3271,6 @@ fi echo "CONFIG_PLATINUM=$has_platinum" >> config.mak -echo "CONFIG_AVCAP=$has_avcap" >> config.mak -if test "$has_avcap" = "yes" ; then - echo "AVCAP_CFLAGS=$avcap_cflags" >> config.mak - echo "AVCAP_LDFLAGS=$avcap_ldflags" >> config.mak -fi - echo "CONFIG_OPENSVC=$has_opensvc" >> config.mak if test "$has_opensvc" = "yes" ; then echo "OSVC_CFLAGS=$osvc_cflags" >> config.mak @@ -3086,6 +3283,12 @@ if test "$has_openhevc" = "yes" ; then echo "OHEVC_CFLAGS=$ohevc_cflags" >> config.mak echo "OHEVC_LDFLAGS=$ohevc_ldflags" >> config.mak echo "#define GPAC_HAS_OPENHEVC" >> $TMPH + + +if test "$static_modules" = "yes" ; then + echo "#define GPAC_OPENHEVC_STATIC" >> $TMPH +fi + fi echo "MOZILLA_DIR=$moz_path" >> config.mak @@ -3131,8 +3334,6 @@ else fi echo "X11_INC_PATH=$X11_PATH/include" >> config.mak -echo "RENOIR_ENABLE=$enable_renoir" >> config.mak - GPAC_ENST_INC=no GPAC_ENST=no enst_dir="`ls \"$source_path/src/\" | grep enst`" @@ -3261,6 +3462,13 @@ echo ' @echo " CC $<"' >> config.mak fi echo ' $(CXX) $(CFLAGS) -c -o $@ $<' >> config.mak +echo '%.o: %.rc' >> config.mak +if test "$verbose" = "no" ; then +echo ' @echo " RC $<"' >> config.mak +fi +echo ' $(WINDRES) $< -o $@ ' >> config.mak + + #pkg-config generate_pkgconfig () { echo "prefix=$prefix" @@ -3279,29 +3487,14 @@ generate_pkgconfig () { generate_pkgconfig > gpac.pc -generate_gpacdesktop () { - echo "[Desktop Entry]" - echo "Version=1.0" - echo "Name=MP4Client" - echo "Comment=GPAC Media Player" - echo "GenericName=Media Player" - echo "Keywords=Media Player" - echo "Exec=MP4Client -gui %u" - echo "Terminal=false" - echo "X-MultipleArgs=false" - echo "Type=Application" - echo "Icon=$prefix/share/pixmaps/gpac.png" - echo "Categories=AudioVideo" - echo "MimeType=text/text;text/xml;application/xhtml+xml;application/xml;image/jpeg;image/png;video/webm;video/mp4;video/mpeg;audio/mp4;audio/mpeg;x-scheme-handler/rtsp;x-scheme-handler/rtp;x-scheme-handler/atsc" - echo "StartupNotify=true" - echo "Actions=new-window" - echo "" - echo "[Desktop Action new-window]" - echo "Name=Open a New Window" - echo "Exec=MP4Client" - echo "" -} +if test "$static_bin" = "yes"; then + if test "$darwin" = "yes" ; then + echo "\nWarning: static binaries on OSX cannot remove all dependendencies to system libraries\n" + elif test "$win32" = "yes" ; then + echo "\nWarning: static binaries on Win32 cannot remove all dependendencies to system libraries\n" + fi +fi + -generate_gpacdesktop > "$source_path/share/gpac.desktop" echo "Done - type 'make help' for make info, 'make' to build" diff --git a/gpac.spec b/gpac.spec index a560e13..d3e1091 100644 --- a/gpac.spec +++ b/gpac.spec @@ -1,11 +1,11 @@ # $Id: gpac.spec,v 1.5 2008-12-02 18:04:42 jeanlf Exp $ Summary: Framework for production, encoding, delivery and interactive playback of multimedia content Name: gpac -Version: 1.0.1 -Release: 1.0.1 +Version: 2.0 +Release: 2.0 License: LGPL Group: Applications/Multimedia -Source0: gpac-1.0.1.tar.gz%{?_with_amr:Source1:http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-700.zip} +Source0: gpac-2.0.tar.gz URL: http://gpac.io/ BuildRoot: %{_tmppath}/%{name}-root Requires: SDL @@ -31,12 +31,13 @@ BuildRequires: SDL-devel %description -GPAC is a framework for production, encoding, delivery and interactive playback of multimedia content +GPAC is a framework for production, encoding, delivery and interactive playback of multimedia content. GPAC supports many AV codecs, multimedia containers (MP4,fMP4, TS, avi, mov, mpg, mkv ...), complex presentation formats (MPEG-4 Systems, SVG Tiny 1.2, VRML/X3D) and subtitles (SRT, WebVTT, TTXT/TX3G, TTML). -Supported inputs and outputs are pipes, UDP/TCP/UN sockets, local files, HTTP, RTP/RTSP, TS demuxing (from file, IP or DVB4Linux), ATSC 3.0 ROUTE sessions, desktop grabbing, camera/microphone inputs and any input format supported by FFmpeg. -GPAC features a highly configurable media processing pipeline, and can further be extended using JavaScript. +Supported inputs and outputs are pipes, UDP/TCP/UN sockets, local files, HTTP, DASH/HLS, RTP/RTSP, MPEG-2 TS, ATSC 3.0 ROUTE sessions, desktop grabbing, camera/microphone inputs and any input format supported by FFmpeg. + +GPAC features a highly configurable media processing pipeline extensible through JavaScript, and can be embedded in Python or NodeJS applications. GPAC is licensed under the GNU Lesser General Public License. diff --git a/include/gpac/00_doxy.h b/include/gpac/00_doxy.h index 00f6aa6..db10567 100644 --- a/include/gpac/00_doxy.h +++ b/include/gpac/00_doxy.h @@ -80,7 +80,7 @@ \defgroup jsapi_grp JavaScript APIs \brief JavaScript API available in GPAC -Parts of the GPAC code can be scriptable using JavaScript. This part of the documentation describes the various APIs used in GPAC. +Parts of the GPAC code can be modified at run-time using JavaScript. This part of the documentation describes the various APIs used in GPAC. For SVG and DOM scenegraph API, see https://www.w3.org/TR/SVGTiny12/svgudom.html. @@ -102,6 +102,10 @@ This means that JS C modules as defined in QuickJS could also be used (https://b There is currently no support for non-local modules (http, https ...). +The default GPAC compilation includes the following modules from QuickJS: +- 'std': documentation https://bellard.org/quickjs/quickjs.html#std-module +- 'os': documentation https://bellard.org/quickjs/quickjs.html#os-module (see below) + GPAC constants used in the API (error code, property types, specific flags for functions) are exported: - using the same name as native code, e.g. GF_STATS_LOCAL, GF_FILTER_SAP_1, etc... - in the global object of the javascript context @@ -112,5 +116,18 @@ Unless indicated otherwise, all errors are handled through exceptions. An except Types and interfaces are described using WebIDL, see https://heycam.github.io/webidl/, with some slight modifications. \warning These IDL files are only intended to document the APIs, and are likely useless for other purposes. + +Notes on QuickJS 'os' module support: +- Workers are supported on OSX, Windows, iOS and Linux; final dereference of the worker object will end the worker thread. +- On Windows, the `exec` function retuns an array rather than an int when run in asynchronous mode. The `waitpid` function will return an array where the first item is this pid object when the process is over, to keep the same behavious as under non Windows systems. +- On Windows, the `exec` function ignores `uid`, `gid` and user-specified stdin/stderr/stdout. + + +\defgroup pyapi_grp Python APIs +\brief Python API for using libgpac + +\defgroup nodejs_grp NodeJS APIs +\brief API for using libgpac in NodeJS + */ diff --git a/include/gpac/Remotery.h b/include/gpac/Remotery.h index e62dd18..67a4f2a 100644 --- a/include/gpac/Remotery.h +++ b/include/gpac/Remotery.h @@ -286,7 +286,7 @@ typedef enum rmtError typedef enum rmtSampleFlags { - // Default behaviour + // Default behavior RMTSF_None = 0, // Search parent for same-named samples and merge timing instead of adding a new sample diff --git a/include/gpac/atsc.h b/include/gpac/atsc.h deleted file mode 100644 index 3663d4a..0000000 --- a/include/gpac/atsc.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * GPAC - Multimedia Framework C SDK - * - * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2017-2019 - * All rights reserved - * - * This file is part of GPAC / ATSC demuxer - * - * GPAC is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GPAC is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _GF_ATSC_H_ -#define _GF_ATSC_H_ - -#include - -#ifndef GPAC_DISABLE_ATSC - -#ifdef __cplusplus -extern "C" { -#endif - -/*! -\file -\brief Specific extensions for ATSC ROUTE demux -*/ - -/*! -\addtogroup atsc_grp ATSC3 -\ingroup media_grp -\brief ATSC 3.0 reciever - -The ATSC 3.0 receiver implements part of the ATSC 3.0 specification, mostly low-level signaling and ROUTE reception. -It can write received files to disk, or send them back to the user for cache population - -@{ -*/ - -/*!The GF_ATSCDmx object.*/ -typedef struct __gf_atscdmx GF_ATSCDmx; - -/*!The types of events used to communicate withe the demuxer user.*/ -typedef enum -{ - /*! A new service detected, service ID is in evt_param*/ - GF_ATSC_EVT_SERVICE_FOUND = 0, - /*! Service scan completed, no evt_param*/ - GF_ATSC_EVT_SERVICE_SCAN, - /*! New MPD available for service, service ID is in evt_param*/ - GF_ATSC_EVT_MPD, - /*! Init segment update, service ID is in evt_param, file info is in finfo*/ - GF_ATSC_EVT_INIT_SEG, - /*! Segment reception, service ID is in evt_param, file info is in finfo*/ - GF_ATSC_EVT_SEG, -} GF_ATSCEventType; - -/*! Structure used to communicate file objects properties to the user*/ -typedef struct -{ - /*! original file name*/ - const char *filename; - /*! data pointer*/ - u8 *data; - /*! data size*/ - u32 size; - /*! object TSI*/ - u32 tsi; - /*! object TOI*/ - u32 toi; - /*! download time in ms*/ - u32 download_ms; - /*! flag set if file is corrupted*/ - Bool corrupted; -} GF_ATSCEventFileInfo; - -/*! Creates a new ATSC demultiplexer -\param ifce network interface to monitor, NULL for INADDR_ANY -\param dir output directory for files. If NULL, files are not written to disk and user callback will be called if set -\param sock_buffer_size default buffer size for the udp sockets. If 0, uses 0x2000 -\return the ATSC demultiplexer created -*/ -GF_ATSCDmx *gf_atsc3_dmx_new(const char *ifce, const char *dir, u32 sock_buffer_size); -/*! Deletes an ATSC demultiplexer -\param atscd the ATSC demultiplexer to delete -*/ -void gf_atsc3_dmx_del(GF_ATSCDmx *atscd); - -/*! Processes demultiplexing, returns when nothing to read -\param atscd the ATSC demultiplexer -\return error code if any, GF_IP_NETWORK_EMPTY if nothing was read - */ -GF_Err gf_atsc3_dmx_process(GF_ATSCDmx *atscd); - -/*! Sets user callback for disk-less operations -\param atscd the ATSC demultiplexer -\param on_event the user callback function -\param udta the user data passed back by the callback -\return error code if any - */ -GF_Err gf_atsc3_set_callback(GF_ATSCDmx *atscd, void (*on_event)(void *udta, GF_ATSCEventType evt, u32 evt_param, GF_ATSCEventFileInfo *finfo), void *udta); - -/*! Sets the maximum number of objects to store on disk per TSI -\param atscd the ATSC demultiplexer -\param max_segs max number of objects (segments) to store. If 0, all objects are kept -\return error code if any - */ -GF_Err gf_atsc3_set_max_objects_store(GF_ATSCDmx *atscd, u32 max_segs); - -/*! Sets reordering on. -\param atscd the ATSC demultiplexer -\param force_reorder if TRUE, the order flag in ROUTE/LCT is ignored and objects are gathered for the given time. Otherwise, if order flag is set in ROUTE/LCT, an object is considered done as soon as a new object starts -\param timeout_ms maximum delay to wait before considering the object is done when ROUTE/LCT order is not used. A value of 0 implies waiting forever (default value is 5s). -\return error code if any - */ -GF_Err gf_atsc3_set_reorder(GF_ATSCDmx *atscd, Bool force_reorder, u32 timeout_ms); - -/*! Sets the maximum number of objects to store on disk per TSI -\param atscd the ATSC demultiplexer -\param service_id ID of the service to tune in. 0 means no service, 0xFFFFFFFF means all services and 0xFFFFFFFE means first service found -\param tune_others if set, will tune all non-selected services to get the MPD, but won't receive any media data -\return error code if any - */ -GF_Err gf_atsc3_tune_in(GF_ATSCDmx *atscd, u32 service_id, Bool tune_others); - - -/*! Gets the number of objects currently loaded in the service -\param atscd the ATSC demultiplexer -\param service_id ID of the service to query -\return number of objects in service - */ -u32 gf_atsc3_dmx_get_object_count(GF_ATSCDmx *atscd, u32 service_id); - -/*! Removes an object with a given filename -\param atscd the ATSC demultiplexer -\param service_id ID of the service to query -\param fileName name of the file associated with the object -\param purge_previous if set, indicates that all objects with the same TSI and a TOI less than TOI of the deleted object will be removed - */ -void gf_atsc3_dmx_remove_object_by_name(GF_ATSCDmx *atscd, u32 service_id, char *fileName, Bool purge_previous); - -/*! Removes the first object loaded in the service -\param atscd the ATSC demultiplexer -\param service_id ID of the service to query -\return GF_TRUE if success, GF_FALSE if no object could be removed (the object is in download) - */ -Bool gf_atsc3_dmx_remove_first_object(GF_ATSCDmx *atscd, u32 service_id); - -/*! Checks existence of a service -\param atscd the ATSC demultiplexer -\param service_id ID of the service to query -\return true if service is found, false otherwise - */ -Bool gf_atsc3_dmx_find_service(GF_ATSCDmx *atscd, u32 service_id); - -/*! Removes all non-signaling objects (ie TSI!=0), keeping only init segments and currently/last downloaded objects -\note this is mostly useful in case of looping session, or at MPD switch boundaries -\param atscd the ATSC demultiplexer -\param service_id ID of the service to cleanup - */ -void gf_atsc3_dmx_purge_objects(GF_ATSCDmx *atscd, u32 service_id); - - -/*! Gets high resolution system time clock of the first packet received -\param atscd the ATSC demultiplexer -\return system clock in microseconds of first packet received - */ -u64 gf_atsc3_dmx_get_first_packet_time(GF_ATSCDmx *atscd); - -/*! Gets high resolution system time clock of the last packet received -\param atscd the ATSC demultiplexer -\return system clock in microseconds of last packet received - */ -u64 gf_atsc3_dmx_get_last_packet_time(GF_ATSCDmx *atscd); - -/*! Gets the number of packets received since start of the session, for all active services -\param atscd the ATSC demultiplexer -\return number of packets received - */ -u64 gf_atsc3_dmx_get_nb_packets(GF_ATSCDmx *atscd); - -/*! Gets the number of bytes received since start of the session, for all active services -\param atscd the ATSC demultiplexer -\return number of bytes received - */ -u64 gf_atsc3_dmx_get_recv_bytes(GF_ATSCDmx *atscd); - -/*! Gather only objects with given TSI (for debug purposes) -\param atscd the ATSC demultiplexer -\param tsi the target TSI, 0 for no filtering - */ -void gf_atsc3_dmx_debug_tsi(GF_ATSCDmx *atscd, u32 tsi); - -/*! Sets udta for given service id -\param atscd the ATSC demultiplexer -\param service_id the target service -\param udta the target user data - */ -void gf_atsc3_dmx_set_service_udta(GF_ATSCDmx *atscd, u32 service_id, void *udta); - -/*! Gets udta for given service id -\param atscd the ATSC demultiplexer -\param service_id the target service -\return the user data associated with the service - */ -void *gf_atsc3_dmx_get_service_udta(GF_ATSCDmx *atscd, u32 service_id); - -/*! @} */ -#ifdef __cplusplus -} -#endif - -#endif /* GPAC_DISABLE_ATSC */ - -#endif //_GF_ATSC_H_ - diff --git a/include/gpac/avparse.h b/include/gpac/avparse.h index 2a26db3..d44866a 100644 --- a/include/gpac/avparse.h +++ b/include/gpac/avparse.h @@ -54,6 +54,7 @@ This section documents the audio and video parsing functions of the GPAC framewo #include +#include @@ -118,6 +119,11 @@ typedef struct Double fps; /*! position of next object in the bitstream*/ u32 next_object_start; + + /*! progressive video sequence */ + Bool progresive; + /*! chroma format */ + u8 chroma_fmt; } GF_M4VDecSpecInfo; @@ -166,7 +172,7 @@ thus you can seek the bitstream to copy the payload without re-seeking it \param time_inc set to the time increment since last frame \param size set to the size of the compressed frame \param start set to the position of the first byte in the buffer/bitstream -\param is_coded set to 1 if frame is coded, 0 if skip frame +\param is_coded set to 1 if frame is coded, 0 if skip frame, untouched if no frame found \return error if any */ GF_Err gf_m4v_parse_frame(GF_M4VParser *m4v, GF_M4VDecSpecInfo *dsi, u8 *frame_type, u32 *time_inc, u64 *size, u64 *start, Bool *is_coded); @@ -395,9 +401,10 @@ u64 gf_mpegh_escaped_value(GF_BitStream *bs, u32 nBits1, u32 nBits2, u32 nBits3) /*! parse profile and level from a MHAS payload \param ptr the MHAS payhload \param size size of the MHAS payhload +\param chan_layout set to the channel layout if found, 0 otherwise - optional, may be NULL \return the MHAS profile found, or -1 of not found */ -s32 gf_mpegh_get_mhas_pl(u8 *ptr, u32 size); +s32 gf_mpegh_get_mhas_pl(u8 *ptr, u32 size, u64 *chan_layout); /*! reads a 32 bit sync safe integer of id3v2 from a bitstream object \param bs the bitstream object to use - has to be positioned on the start if an id3v2 size field @@ -469,7 +476,9 @@ enum /*! DST*/ GF_M4A_DST = 35, /*! ALS*/ - GF_M4A_ALS = 36 + GF_M4A_ALS = 36, + /*! USAC*/ + GF_M4A_USAC = 42, }; /*! AAC sample rates*/ @@ -482,7 +491,7 @@ static const u32 GF_M4ASampleRates[] = /*! AAC channel configurations*/ static const u32 GF_M4ANumChannels[] = { - 1, 2, 3, 4, 5, 6, 8, 2, 3, 4, 7, 8, 24, 8, 12, 10, 12, 14 + 1, 2, 3, 4, 5, 6, 8, 0, 0, 0, 7, 8, 0, 8, 0 }; #ifndef GPAC_DISABLE_AV_PARSERS @@ -496,7 +505,7 @@ u32 gf_m4a_get_channel_cfg(u32 nb_chan); /*! MPEG-4 Audio decoder specific info*/ typedef struct { - /*Number of channels*/ + /*Number of channels (NOT AAC channel confgiuration), 0 if unknown in which case program_config_element must be set*/ u32 nb_chan; /*base audio object type*/ u32 base_object_type; @@ -516,6 +525,8 @@ typedef struct Bool has_ps; /*audio Profile level indication*/ u8 audioPL; + /*channel configuration, only set when parsing (when writing, recomputed from nb_chan)*/ + u32 chan_cfg; /*set if program config element is present - members until end of struct are ignored/invalid if this is not set*/ Bool program_config_element_present; @@ -575,6 +586,8 @@ typedef struct u8 comment_field_bytes; /*comment field*/ u8 comments[255]; + //set after parsing program_config_element + u32 cpe_channels; } GF_M4ADecSpecInfo; /*! parses MPEG-4 audio dsi @@ -590,27 +603,42 @@ GF_Err gf_m4a_get_config(u8 *dsi, u32 dsi_size, GF_M4ADecSpecInfo *cfg); */ u32 gf_m4a_get_profile(GF_M4ADecSpecInfo *cfg); -/*! writes MPEG-4 audio dsi in a byte buffer +/*! writes MPEG-4 audio dsi in a byte buffer - backward-compatible signaling extensions are not written \param cfg the configuration to write \param dsi set to the encoded buffer (to be freed by caller) \param dsi_size set to the size of the encoded buffer \return error code if any */ GF_Err gf_m4a_write_config(GF_M4ADecSpecInfo *cfg, u8 **dsi, u32 *dsi_size); -/*! writes MPEG-4 audio dsi in a bitstream object +/*! writes MPEG-4 audio dsi in a bitstream object - backward-compatible signaling extensions are not written \param bs the bitstream object to write to \param cfg the configuration to write \return error code if any */ GF_Err gf_m4a_write_config_bs(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg); /*! parses MPEG-4 audio dsi from bitstream -\param bs the bitstream object to use (shall start in the begining of the dsi) +\param bs the bitstream object to use (shall start in the beginning of the dsi) \param cfg will be filled with the parsed value -\param size_known set to GF_TRUE if the bitstream contains the complete DSI (and only it) +\param size_known set to GF_TRUE if the bitstream contains the complete DSI (and only it), to parse backward-compatible extensions \return error code if any */ GF_Err gf_m4a_parse_config(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg, Bool size_known); + +/*! reads program config element of MPEG-4 audio dsi +\param bs the bitstream object to use (shall start in the beginning of the dsi) +\param cfg the config to fill +\return error code if any +*/ +GF_Err gf_m4a_parse_program_config_element(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg); + +/*! writes program config element of MPEG-4 audio dsi +\param bs the bitstream object to use (shall start in the beginning of the dsi) +\param cfg the config to write +\return error code if any +*/ +GF_Err gf_m4a_write_program_config_element_bs(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg); + #endif /*GPAC_DISABLE_AV_PARSERS*/ /*! gets the name of a given MPEG-4 audio object type @@ -626,28 +654,9 @@ const char *gf_m4a_get_profile_name(u8 audio_pl); #ifndef GPAC_DISABLE_AV_PARSERS -/*! AC-3 header*/ -typedef struct -{ - u8 fscod, bsid, bsmod, acmod, lfon, brcode; - u8 asvc, num_dep_sub; - u16 chan_loc; -} GF_AC3StreamInfo; - -/*! AC-3 header*/ -typedef struct -{ - u32 bitrate; - u32 sample_rate; - u32 framesize; - u32 channels; - u16 substreams; //bit-mask, used for channel map > 5.1 - /*only set if full parse*/ - GF_AC3StreamInfo streams[8]; //0->7 sibstream ids - u8 nb_streams; //main and substream, only independent ones - //data rate in kbps - u32 data_rate; -} GF_AC3Header; +//! \cond old name +typedef struct __ac3_config GF_AC3Header; +//! \endcond /*! parses an AC-3 header from a buffer \param buffer buffer to parse @@ -657,21 +666,21 @@ typedef struct \param full_parse if GF_TRUE, complete parsing of the header will be done \return GF_TRUE if success */ -Bool gf_ac3_parser(u8 *buffer, u32 buffer_size, u32 *pos, GF_AC3Header *out_hdr, Bool full_parse); +Bool gf_ac3_parser(u8 *buffer, u32 buffer_size, u32 *pos, GF_AC3Config *out_hdr, Bool full_parse); /*! parses an AC-3 header from a bitstream \param bs bitstream to parse \param hdr will be filled by parser \param full_parse if GF_TRUE, complete parsing of the header will be done \return GF_TRUE if success */ -Bool gf_ac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse); +Bool gf_ac3_parser_bs(GF_BitStream *bs, GF_AC3Config *hdr, Bool full_parse); /*! parses an EAC-3 header from a bitstream \param bs bitstream to parse \param hdr will be filled by parser \param full_parse if GF_TRUE, complete parsing of the header will be done \return GF_TRUE if success */ -Bool gf_eac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse); +Bool gf_eac3_parser_bs(GF_BitStream *bs, GF_AC3Config *hdr, Bool full_parse); /*! gets the number of channels in an AC3 frame \param acmod acmod of the associated frame header \return number of channels @@ -715,8 +724,22 @@ GF_Err gf_avc_get_pps_info(u8 *pps, u32 pps_size, u32 *pps_id, u32 *sps_id); */ GF_Err gf_hevc_get_sps_info(u8 *sps_data, u32 sps_size, u32 *sps_id, u32 *width, u32 *height, s32 *par_n, s32 *par_d); +/*! gets basic information from a VVC Sequence Parameter Set +\param sps_data SPS NAL buffer +\param sps_size size of buffer +\param sps_id set to the ID +\param width set to the width +\param height set to the height +\param par_n set to the pixel aspect ratio numerator +\param par_d set to the pixel aspect ratio denominator +\return error code if any +*/ +GF_Err gf_vvc_get_sps_info(u8 *sps_data, u32 sps_size, u32 *sps_id, u32 *width, u32 *height, s32 *par_n, s32 *par_d); + #endif /*GPAC_DISABLE_AV_PARSERS*/ +const char *gf_vvc_get_profile_name(u8 video_prof); + /*! gets chroma format name from MPEG chroma format \param chroma_format the chroma format to query (1: 420, 2: 422, 3: 444) \return the name of the format @@ -727,11 +750,12 @@ const char * gf_avc_hevc_get_chroma_format_name(u8 chroma_format); \return the name of the profile */ const char *gf_avc_get_profile_name(u8 profile_idc); -/*! checks if an AVC profile is a range extension profile -\param profile_idc the PL indication -\return GF_TRUE if given profile is in range extensions + +/*! checks if avcc extensions are used for this profile + param profile_idc the PL indication +\return GF_TRUE if extensions must be written in avcc for the given profile */ -Bool gf_avc_is_rext_profile(u8 profile_idc); +Bool gf_avcc_use_extensions(u8 profile_idc); /*! gets HEVC profile name from profile indication \param profile_idc the PL indication diff --git a/include/gpac/bitstream.h b/include/gpac/bitstream.h index cafbe22..ee7436b 100644 --- a/include/gpac/bitstream.h +++ b/include/gpac/bitstream.h @@ -104,6 +104,7 @@ GF_BitStream *gf_bs_from_file(FILE *f, u32 mode); \brief bitstream destructor from file handle Deletes the bitstream object. If the buffer was created by the bitstream, it is deleted if still present. +\warning If the bitstream was constructed from a FILE object in write mode, the FILE object MUST be closed after destructing the bitstream \param bs the target bitstream */ void gf_bs_del(GF_BitStream *bs); @@ -178,7 +179,7 @@ Double gf_bs_read_double(GF_BitStream *bs); /*! \brief data reading -Reads a data buffer. Emultation prevention byte removal is not applied here ! +Reads a data buffer. Emultation prevention byte removal is NOT applied here \param bs the target bitstream \param data the data buffer to be filled \param nbBytes the amount of bytes to read @@ -486,7 +487,7 @@ void gf_bs_get_content_no_truncate(GF_BitStream *bs, u8 **output, u32 *outSize, \brief byte skipping Skips bytes in the bitstream. In Write mode, this will write the 0 integer value for memory-based bitstreams or seek the stream - for file-based bitstream. In read mode, emultation prevention byte removal is not applied ! + for file-based bitstream. In read mode, emultation prevention byte is applied if enabled \param bs the target bitstream \param nbBytes the number of bytes to skip */ @@ -623,6 +624,26 @@ Gets the current cookie on the bitstream */ u64 gf_bs_get_cookie(GF_BitStream *bs); + +/*! +\brief Marks overflow access + +Marks the bitstream as overflown (reading outside of buffer range). Marking is done automatically when reading but can be forced using this function. + +\param bs the target bitstream +\param reset if GF_TRUE, reset overflown state, otherwise mark as overflown + */ +void gf_bs_mark_overflow(GF_BitStream *bs, Bool reset); + +/*! +\brief Gets overflow state + +Gets overflow state of the bitstream +\param bs the target bitstream +\return 2 if an overflow was marked by user using \ref gf_bs_mark_overflow, 1 if an overflow occured, 0 otherwise + */ +u32 gf_bs_is_overflow(GF_BitStream *bs); + /*! @} */ #ifdef __cplusplus diff --git a/include/gpac/cache.h b/include/gpac/cache.h index 767280b..5041657 100644 --- a/include/gpac/cache.h +++ b/include/gpac/cache.h @@ -192,12 +192,13 @@ Get content length of resource u32 gf_cache_get_content_length( const DownloadedCacheEntry entry); /** -Append cache directives to an HTTP GET request +Get directives headers associated with the cache \param entry The entry of cache to use -\param httpRequest The HTTP GET request to populate. The request must have been allocated enough to handle the cache arguments +\param etag set to etag value or NULL if no cache +\param last_modif set to last modif value or NULL if no cache \return GF_OK if everything went fine, GF_BAD_PARAM if parameters are wrong */ -GF_Err gf_cache_append_http_headers(const DownloadedCacheEntry entry, char * httpRequest); +GF_Err gf_cache_get_http_headers(const DownloadedCacheEntry entry, const char **etag, const char **last_modif); /* * Cache Management functions diff --git a/include/gpac/color.h b/include/gpac/color.h index 13e4c70..5f72d34 100644 --- a/include/gpac/color.h +++ b/include/gpac/color.h @@ -121,10 +121,10 @@ typedef struct The color type used in the GPAC framework represents colors in the form 0xAARRGGBB, with each component ranging from 0 to 255 */ typedef u32 GF_Color; -/*!\hideinitializer color formating macro from alpha, red, green and blue components expressed as integers ranging from 0 to 255*/ +/*!\hideinitializer color formatting macro from alpha, red, green and blue components expressed as integers ranging from 0 to 255*/ #define GF_COL_ARGB(a, r, g, b) (((u32) a)<<24 | ((u32) r)<<16 | ((u32) g)<<8 | ((u32) b)) -/*!\hideinitializer color formating macro from alpha, red, green and blue components expressed as fixed numbers ranging from 0 to \ref FIX_ONE*/ +/*!\hideinitializer color formatting macro from alpha, red, green and blue components expressed as fixed numbers ranging from 0 to \ref FIX_ONE*/ #define GF_COL_ARGB_FIXED(_a, _r, _g, _b) GF_COL_ARGB(FIX2INT(255*(_a)), FIX2INT(255*(_r)), FIX2INT(255*(_g)), FIX2INT(255*(_b))) /*!\hideinitializer gets alpha component of a color*/ #define GF_COL_A(c) (u8) ((c)>>24) @@ -134,9 +134,9 @@ typedef u32 GF_Color; #define GF_COL_G(c) (u8) ( ((c)>>8) & 0xFF) /*!\hideinitializer gets blue component of a color*/ #define GF_COL_B(c) (u8) ( (c) & 0xFF) -/*!\hideinitializer 16-bits color formating macro from red, green and blue components*/ +/*!\hideinitializer 16-bits color formatting macro from red, green and blue components*/ #define GF_COL_565(r, g, b) (u16) (((r & 248)<<8) + ((g & 252)<<3) + (b>>3)) -/*!\hideinitializer 15-bits color formating macro from red, green and blue components*/ +/*!\hideinitializer 15-bits color formatting macro from red, green and blue components*/ #define GF_COL_555(r, g, b) (u16) (((r & 248)<<7) + ((g & 248)<<2) + (b>>3)) /*!\hideinitializer gets alpha component of a wide color*/ diff --git a/include/gpac/configuration.h b/include/gpac/configuration.h index 181e751..40fc2c6 100644 --- a/include/gpac/configuration.h +++ b/include/gpac/configuration.h @@ -51,7 +51,7 @@ This section documents the base data types of GPAC. #define GPAC_HAS_SSL #define GPAC_HAS_QJS -//codecs +//codecs #define GPAC_HAS_JPEG #define GPAC_HAS_PNG #define GPAC_HAS_LIBA52 @@ -65,6 +65,7 @@ This section documents the base data types of GPAC. #define GPAC_HAS_XVID #define GPAC_HAS_FFMPEG #define GPAC_HAS_DTAPI +#define GPAC_HAS_HTTP2 /*IPv6 enabled - for win32, this is evaluated at compile time, !! do not uncomment !!*/ @@ -122,6 +123,7 @@ This section documents the base data types of GPAC. #define GPAC_HAS_QJS #define GPAC_HAS_JPEG #define GPAC_HAS_PNG +#define GPAC_HAS_HTTP2 /*Configuration for XCode OSX (not iOS) */ #elif defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_CONFIG_IOS) @@ -137,9 +139,12 @@ This section documents the base data types of GPAC. #endif #define GPAC_HAS_QJS +//#define GPAC_DISABLE_QJS_LIBC #define GPAC_HAS_JPEG #define GPAC_HAS_PNG #define GPAC_HAS_GLU +#define GPAC_HAS_VTB +#define GPAC_HAS_HTTP2 #define GPAC_MEMORY_TRACKING @@ -176,6 +181,9 @@ This section documents the base data types of GPAC. #define GPAC_HAS_IPV6 #define GPAC_HAS_SSL #define GPAC_DISABLE_OGG +#define GPAC_HAS_STRLCPY +#define GPAC_HAS_VTB +#define GPAC_HAS_HTTP2 /*Configuration for Symbian*/ #elif defined(__SYMBIAN32__) @@ -335,4 +343,3 @@ this macro is currently defined in setup.h */ /*! @} */ #endif /*_GF_CONFIG_H_*/ - diff --git a/include/gpac/constants.h b/include/gpac/constants.h index bc0522e..48cb1e5 100644 --- a/include/gpac/constants.h +++ b/include/gpac/constants.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / exported constants @@ -112,6 +112,11 @@ enum */ const char *gf_stream_type_name(u32 streamType); +/*! Gets the stream type short name based on stream type (usually the lower case value of the stream name) +\param streamType stream type GF_STREAM_XXX as defined in constants.h +\return NULL if unknown, otherwise value + */ +const char *gf_stream_type_short_name(u32 streamType); /*! Gets the stream type by name \param name name of the stream type to query @@ -119,11 +124,6 @@ const char *gf_stream_type_name(u32 streamType); */ u32 gf_stream_type_by_name(const char *name); -/*! Gets the list of names of all stream types defined -\return names of all stream types defined - */ -const char *gf_stream_type_all_names(); - /*! Enumerates defined stream types \param idx index of the stream type, 0-based \param name name of the stream type (used when parsing stream type from textual definition) @@ -171,7 +171,7 @@ typedef enum /*!32 bit ARGB. Component ordering in bytes is A-R-G-B.*/ GF_PIXEL_ARGB = GF_4CC('A','R','G','B'), - /*!32 bit RGBA (openGL like). Component ordering in bytes is R-G-B-A.*/ + /*!32 bit RGBA (OpenGL like). Component ordering in bytes is R-G-B-A.*/ GF_PIXEL_RGBA = GF_4CC('R','G','B', 'A'), /*!32 bit BGRA. Component ordering in bytes is B-G-R-A.*/ GF_PIXEL_BGRA = GF_4CC('B','G','R','A'), @@ -191,7 +191,7 @@ typedef enum GF_PIXEL_RGB_DEPTH = GF_4CC('R', 'G', 'B', 'd'), /*!YUV packed 422 format*/ - GF_PIXEL_YUYV = GF_4CC('Y','U','Y','2'), + GF_PIXEL_YUYV = GF_4CC('Y','U','Y','V'), /*!YUV packed 422 format*/ GF_PIXEL_YVYU = GF_4CC('Y','V','Y','U'), /*!YUV packed 422 format*/ @@ -199,8 +199,19 @@ typedef enum /*!YUV packed 422 format*/ GF_PIXEL_VYUY = GF_4CC('V','Y','U','Y'), + /*!YUV packed 422 format 10 bits, little endian*/ + GF_PIXEL_YUYV_10 = GF_4CC('Y','U','Y','L'), + /*!YUV packed 422 format 10 bits, little endian*/ + GF_PIXEL_YVYU_10 = GF_4CC('Y','V','Y','L'), + /*!YUV packed 422 format 10 bits, little endian*/ + GF_PIXEL_UYVY_10 = GF_4CC('U','Y','V','L'), + /*!YUV packed 422 format 10 bits, little endian*/ + GF_PIXEL_VYUY_10 = GF_4CC('V','Y','U','L'), + /*!YUV planar format*/ - GF_PIXEL_YUV = GF_4CC('Y','V','1','2'), + GF_PIXEL_YUV = GF_4CC('Y','U','1','2'), + /*!YVU planar format*/ + GF_PIXEL_YVU = GF_4CC('Y','V','1','2'), /*!YUV420p in 10 bits mode, little endian*/ GF_PIXEL_YUV_10 = GF_4CC('Y','0','1','0'), /*!YUV420p + Alpha plane*/ @@ -225,8 +236,14 @@ typedef enum GF_PIXEL_YUV444 = GF_4CC('Y','4','4','4'), /*!444 YUV, 10 bits, little endian*/ GF_PIXEL_YUV444_10 = GF_4CC('Y','4','1','0'), - - /*!Unknown format exposed a single openGL texture to be consumed using samplerExternalOES*/ + /*!444 YUV packed*/ + GF_PIXEL_YUV444_PACK = GF_4CC('Y','4','4','p'), + /*!444 YUV+Alpha packed*/ + GF_PIXEL_YUVA444_PACK = GF_4CC('Y','A','4','p'), + /*!444 YUV 10 bit packed*/ + GF_PIXEL_YUV444_10_PACK = GF_4CC('Y','4','1','p'), + + /*!Unknown format exposed a single OpenGL texture to be consumed using samplerExternalOES*/ GF_PIXEL_GL_EXTERNAL = GF_4CC('E','X','G','L') } GF_PixelFormat; @@ -243,9 +260,16 @@ GF_PixelFormat gf_pixel_fmt_parse(const char *pf_name); */ const char *gf_pixel_fmt_name(GF_PixelFormat pfmt); +/*! checks if pixel format is known, does not throw error message +\param pf_4cc pixel format code or 0 +\param pf_name pixel format name or short name or NULL +\return GF_TRUE is format is known, GF_FALSE otherwise +*/ +Bool gf_pixel_fmt_probe(GF_PixelFormat pf_4cc, const char *pf_name); + /*! gets short name of pixel formats, as used for file extensions \param pfmt pixel format code -\return pixel format short name +\return pixel format short name, "unknown" if not found */ const char *gf_pixel_fmt_sname(GF_PixelFormat pfmt); @@ -254,9 +278,9 @@ const char *gf_pixel_fmt_sname(GF_PixelFormat pfmt); \param name name of the pixel format \param fileext file extension of the pixel format \param description description of the pixel format -\return pixel format code, 0 if no more pixel formats are availble +\return pixel format code, 0 if no more pixel formats are available */ -Bool gf_pixel_fmt_enum(u32 *idx, const char **name, const char **fileext, const char **description); +GF_PixelFormat gf_pixel_fmt_enum(u32 *idx, const char **name, const char **fileext, const char **description); /*! gets the list of all supported pixel format names \return list of supported pixel format names @@ -287,16 +311,45 @@ Bool gf_pixel_get_size_info(GF_PixelFormat pixfmt, u32 width, u32 height, u32 *o */ u32 gf_pixel_get_bytes_per_pixel(GF_PixelFormat pixfmt); +/*! Gets the number of bits per component +\param pixfmt pixel format code +\return number of bits per component +*/ +u32 gf_pixel_is_wide_depth(GF_PixelFormat pixfmt); + /*! Gets the number of component per pixel \param pixfmt pixel format code \return number of bytes per pixel */ u32 gf_pixel_get_nb_comp(GF_PixelFormat pixfmt); +/*! Checks if pixel format is transparent +\param pixfmt pixel format code +\return GF_TRUE if alpha channel is present, GF_FALSE otherwise +*/ +Bool gf_pixel_fmt_is_transparent(GF_PixelFormat pixfmt); + +/*! Checks if format is YUV +\param pixfmt pixel format code +\return GF_TRUE is YUV format, GF_FALSE otherwise (greyscale or RGB) +*/ +Bool gf_pixel_fmt_is_yuv(GF_PixelFormat pixfmt); + +/*! gets pixel format associated with a given uncompressed video QT code +\param qt_code the desired QT/ISOBMFF uncompressed video code +\return the corresponding pixel format, or 0 if unknown code +*/ +GF_PixelFormat gf_pixel_fmt_from_qt_type(u32 qt_code); +/*! gets QY code associated with a given pixel format +\param pixfmt the desired pixel format +\return the corresponding QT code, or 0 if no asociation +*/ +u32 gf_pixel_fmt_to_qt_type(GF_PixelFormat pixfmt); + /*! \brief Codec IDs -Codec ID identifies the stream coding type. The enum is devided into values less than 255, which are equivalent to MPEG-4 systems ObjectTypeIndication. Other values are 4CCs, usually matching ISOMEDIA sample entry types*/ +Codec ID identifies the stream coding type. The enum is divided into values less than 255, which are equivalent to MPEG-4 systems ObjectTypeIndication. Other values are 4CCs, usually matching ISOMEDIA sample entry types*/ typedef enum { /*!Never used by PID declarations, but used by filters caps*/ @@ -364,7 +417,7 @@ typedef enum GF_CODECID_MPEG2_PART3 = 0x69, /*! codecid for MPEG-1 Video streams*/ GF_CODECID_MPEG1 = 0x6A, - /*! codecid for MPEG-1 Audio streams*/ + /*! codecid for MPEG-1 Audio streams, layer 3*/ GF_CODECID_MPEG_AUDIO = 0x6B, /*! codecid for JPEG streams*/ GF_CODECID_JPEG = 0x6C, @@ -404,6 +457,8 @@ typedef enum GF_CODECID_AC3 = GF_4CC('a','c','-','3'), /*! codecid for enhanced AC-3 audio streams*/ GF_CODECID_EAC3 = GF_4CC('e','c','-','3'), + /*! codecid for Dolby TrueHS audio streams*/ + GF_CODECID_TRUEHD = GF_4CC('m','l','p','a'), /*! codecid for DRA audio streams*/ GF_CODECID_DRA = GF_4CC('d','r','a','1'), /*! codecid for ITU G719 audio streams*/ @@ -448,7 +503,7 @@ typedef enum \brief OGG DecoderConfig The DecoderConfig for theora, vorbis, flac and opus contains all intitialization ogg packets for the codec - and is formated as follows:\n + and is formatted as follows:\n \code while (dsi_size) { bit(16) packet_size; @@ -521,9 +576,24 @@ typedef enum GF_CODECID_TMCD = GF_4CC('t','m','c','d'), + /*! codecid for FFV1*/ + GF_CODECID_FFV1 = GF_4CC('f','f','v','1'), GF_CODECID_FFMPEG = GF_4CC('F','F','I','D'), + /*! codecid for VVC video */ + GF_CODECID_VVC = GF_4CC('v','v','c',' '), + GF_CODECID_VVC_SUBPIC = GF_4CC('v','v','c','s'), + + /*! codecid for USAC / xHE-AACv2 audio */ + GF_CODECID_USAC = GF_4CC('u','s','a','c'), + + GF_CODECID_V210 = GF_4CC('v','2','1','0'), + + + /*! codecid for MPEG-1 Audio streams, layer 1*/ + GF_CODECID_MPEG_AUDIO_L1 = GF_4CC('m','p','a','1'), + //fake codec IDs for RTP GF_CODECID_FAKE_MP2T = GF_4CC('M','P','2','T') } GF_CodecID; @@ -577,7 +647,7 @@ u32 gf_codecid_4cc_type(GF_CodecID codecid); \param cname target codec short name \return codecid codec ID */ -GF_CodecID gf_codec_parse(const char *cname); +GF_CodecID gf_codecid_parse(const char *cname); /*! Gets the raw file ext (one or more, | separated) for the given codecid \param codecid codec ID @@ -733,12 +803,18 @@ typedef enum GF_AUDIO_FMT_U8 = 1, /*! sample = signed short Little Endian, interleaved channels*/ GF_AUDIO_FMT_S16, + /*! sample = signed short Big Endian, interleaved channels*/ + GF_AUDIO_FMT_S16_BE, /*! sample = signed integer, interleaved channels*/ GF_AUDIO_FMT_S32, /*! sample = 1 float, interleaved channels*/ GF_AUDIO_FMT_FLT, /*! sample = 1 double, interleaved channels*/ GF_AUDIO_FMT_DBL, + /*! sample = signed integer, interleaved channels*/ + GF_AUDIO_FMT_S24, + /*! not a format, indicates the value of last packed format*/ + GF_AUDIO_FMT_LAST_PACKED, /*! sample = unsigned byte, planar channels*/ GF_AUDIO_FMT_U8P, /*! sample = signed short, planar channels*/ @@ -749,8 +825,6 @@ typedef enum GF_AUDIO_FMT_FLTP, /*! sample = 1 double, planar channels*/ GF_AUDIO_FMT_DBLP, - /*! sample = signed integer, interleaved channels*/ - GF_AUDIO_FMT_S24, /*! sample = signed integer, planar channels*/ GF_AUDIO_FMT_S24P, } GF_AudioFormat; @@ -799,16 +873,22 @@ Bool gf_audio_fmt_is_planar(GF_AudioFormat afmt); /*! Returns audio format for raw audio ISOBMFF sample description type \param msubtype ISOBMFF sample description type -\return the associated audio format of 0 if not known +\return the associated audio format or 0 if not known */ GF_AudioFormat gf_audio_fmt_from_isobmf(u32 msubtype); +/*! Returns QTFF/ISOBMFF sample description 4CC of an audio format +\param afmt audio format to query +\return the associated 4CC or 0 if not known + */ +u32 gf_audio_fmt_to_isobmf(GF_AudioFormat afmt); + /*! enumerates audio formats \param idx index of the audio format, 0-based \param name name of the audio format \param fileext file extension of the pixel format \param desc audio format description -\return audio format or 0 if no more audio formats are availble +\return audio format or 0 if no more audio formats are available */ GF_AudioFormat gf_audio_fmt_enum(u32 *idx, const char **name, const char **fileext, const char **desc); @@ -832,12 +912,44 @@ u64 gf_audio_fmt_get_layout_from_cicp(u32 cicp_layout); */ const char *gf_audio_fmt_get_layout_name_from_cicp(u32 cicp_layout); +/*! get channel layout name +\param chan_layout channel layout mask +\return name of layout of "unknown" if unknown +*/ +const char *gf_audio_fmt_get_layout_name(u64 chan_layout); + + +/*! get channel layout from name +\param name channel layout name +\return channel layout mask +*/ +u64 gf_audio_fmt_get_layout_from_name(const char *name); + /*! get CICP layout value from channel layout mask \param chan_layout channel layout mask \return CICP code point or 255 if unknown */ u32 gf_audio_fmt_get_cicp_from_layout(u64 chan_layout); +/*! get channel count from channel layout +\param chan_layout channel layout mask +\return number of channels in this layout +*/ +u32 gf_audio_fmt_get_num_channels_from_layout(u64 chan_layout); + +/*! get dloby chanmap value from cicp layout +\param cicp_layout channel CICP layout +\return dolby chanmap +*/ +u16 gf_audio_fmt_get_dolby_chanmap(u32 cicp_layout); + +/*! enumerates CICP channel layout +\param idx index of cicp layout value to query +\param short_name set t o CICP name as used in GPAC - may be NULL +\param ch_mask set t o audio channel mask, as used in GPAC - may be NULL +\return CICP code point, or 0 if no more to enumerate*/ +u32 gf_audio_fmt_cicp_enum(u32 idx, const char **short_name, u64 *ch_mask); + /*! Color primaries as defined by ISO/IEC 23001-8 / 23091-2 */ typedef enum @@ -988,6 +1100,11 @@ enum GF_AVC_NALU_DV_RPU = 28, /*! Dolby Vision EL */ GF_AVC_NALU_DV_EL = 30, + + /*! NALU-FF extractor */ + GF_AVC_NALU_FF_AGGREGATOR=30, + /*! NALU-FF aggregator */ + GF_AVC_NALU_FF_EXTRACTOR=31, }; @@ -1016,6 +1133,10 @@ enum GF_AVC_TYPE2_SI = 9 }; +/*! Scheme Type only used internally to signal HLS sample AES in TS */ +#define GF_HLS_SAMPLE_AES_SCHEME GF_4CC('s','a','e','s') + + /*! HEVC NAL unit types */ enum { @@ -1077,6 +1198,12 @@ enum GF_HEVC_NALU_SEI_PREFIX = 39, /*! suffix SEI message*/ GF_HEVC_NALU_SEI_SUFFIX = 40, + + /*! NALU-FF aggregator */ + GF_HEVC_NALU_FF_AGGREGATOR=48, + /*! NALU-FF extractor */ + GF_HEVC_NALU_FF_EXTRACTOR=49, + /*! Dolby Vision RPU */ GF_HEVC_NALU_DV_RPU = 62, /*! Dolby Vision EL */ @@ -1085,6 +1212,55 @@ enum +/*! VVC NAL unit types - vtm10) */ +enum +{ + /*! Trail N VVC slice*/ + GF_VVC_NALU_SLICE_TRAIL = 0, + /*! STSA N VVC slice*/ + GF_VVC_NALU_SLICE_STSA = 1, + /*! STSA N VVC slice*/ + GF_VVC_NALU_SLICE_RADL = 2, + /*! STSA N VVC slice*/ + GF_VVC_NALU_SLICE_RASL = 3, + /*! IDR with RADL VVC slice*/ + GF_VVC_NALU_SLICE_IDR_W_RADL = 7, + /*! IDR DLP VVC slice*/ + GF_VVC_NALU_SLICE_IDR_N_LP = 8, + /*! CRA VVC slice*/ + GF_VVC_NALU_SLICE_CRA = 9, + /*! CRA VVC slice*/ + GF_VVC_NALU_SLICE_GDR = 10, + + /*! Operation Point Info */ + GF_VVC_NALU_OPI = 12, + /*! Decode Parameter Set*/ + GF_VVC_NALU_DEC_PARAM = 13, + /*! Video Parameter Set*/ + GF_VVC_NALU_VID_PARAM = 14, + /*! Sequence Parameter Set*/ + GF_VVC_NALU_SEQ_PARAM = 15, + /*! Picture Parameter Set*/ + GF_VVC_NALU_PIC_PARAM = 16, + /*! APS prefix */ + GF_VVC_NALU_APS_PREFIX = 17, + /*! APS suffix */ + GF_VVC_NALU_APS_SUFFIX = 18, + /*! Picture Header*/ + GF_VVC_NALU_PIC_HEADER = 19, + /*! AU delimiter*/ + GF_VVC_NALU_ACCESS_UNIT = 20, + /*! End of sequence*/ + GF_VVC_NALU_END_OF_SEQ = 21, + /*! End of stream*/ + GF_VVC_NALU_END_OF_STREAM = 22, + /*! prefix SEI message*/ + GF_VVC_NALU_SEI_PREFIX = 23, + /*! suffix SEI message*/ + GF_VVC_NALU_SEI_SUFFIX = 24, + /*! Filler Data*/ + GF_VVC_NALU_FILLER_DATA = 25, +}; /*! Number of defined QCELP rate sizes*/ static const unsigned int GF_QCELP_RATE_TO_SIZE_NB = 7; /*! QCELP rate sizes - note that these sizes INCLUDE the rate_type header byte*/ @@ -1136,11 +1312,13 @@ typedef enum { GF_ID3V2_FRAME_SYTC = GF_4CC('S','Y','T','C'), GF_ID3V2_FRAME_TALB = GF_4CC('T','A','L','B'), GF_ID3V2_FRAME_TBPM = GF_4CC('T','B','P','M'), + GF_ID3V2_FRAME_TCAT = GF_4CC('T','C','A','T'), GF_ID3V2_FRAME_TCMP = GF_4CC('T','C','M','P'), GF_ID3V2_FRAME_TCOM = GF_4CC('T','C','O','M'), GF_ID3V2_FRAME_TCON = GF_4CC('T','C','O','N'), GF_ID3V2_FRAME_TCOP = GF_4CC('T','C','O','P'), GF_ID3V2_FRAME_TDAT = GF_4CC('T','D','A','T'), + GF_ID3V2_FRAME_TDES = GF_4CC('T','D','E','S'), GF_ID3V2_FRAME_TDLY = GF_4CC('T','D','L','Y'), GF_ID3V2_FRAME_TDRC = GF_4CC('T','D','R','C'), GF_ID3V2_FRAME_TENC = GF_4CC('T','E','N','C'), @@ -1151,6 +1329,7 @@ typedef enum { GF_ID3V2_FRAME_TIT2 = GF_4CC('T','I','T','2'), GF_ID3V2_FRAME_TIT3 = GF_4CC('T','I','T','3'), GF_ID3V2_FRAME_TKEY = GF_4CC('T','K','E','Y'), + GF_ID3V2_FRAME_TKWD = GF_4CC('T','K','W','D'), GF_ID3V2_FRAME_TLAN = GF_4CC('T','L','A','N'), GF_ID3V2_FRAME_TLEN = GF_4CC('T','L','E','N'), GF_ID3V2_FRAME_TMED = GF_4CC('T','M','E','D'), @@ -1171,6 +1350,11 @@ typedef enum { GF_ID3V2_FRAME_TRSN = GF_4CC('T','R','S','N'), GF_ID3V2_FRAME_TRSO = GF_4CC('T','R','S','O'), GF_ID3V2_FRAME_TSIZ = GF_4CC('T','S','I','Z'), + GF_ID3V2_FRAME_TSO2 = GF_4CC('T','S','O','2'), + GF_ID3V2_FRAME_TSOA = GF_4CC('T','S','O','A'), + GF_ID3V2_FRAME_TSOC = GF_4CC('T','S','O','C'), + GF_ID3V2_FRAME_TSOT = GF_4CC('T','S','O','T'), + GF_ID3V2_FRAME_TSOP = GF_4CC('T','S','O','P'), GF_ID3V2_FRAME_TSRC = GF_4CC('T','S','R','C'), GF_ID3V2_FRAME_TSSE = GF_4CC('T','S','S','E'), GF_ID3V2_FRAME_TYER = GF_4CC('T','Y','E','R'), @@ -1194,14 +1378,24 @@ enum { /*! tag is a string*/ GF_ITAG_STR=0, - /*! tag is an int*/ - GF_ITAG_INT, - /*! tag is a fraction*/ - GF_ITAG_FRAC, - /*! tag is a boolean*/ + /*! tag is an 8 bit int*/ + GF_ITAG_INT8, + /*! tag is a 16 bit int*/ + GF_ITAG_INT16, + /*! tag is a 32 bit int*/ + GF_ITAG_INT32, + /*! tag is an 64 bits int*/ + GF_ITAG_INT64, + /*! tag is a boolean (8bit) */ GF_ITAG_BOOL, - /*! tag is a string but name is matched as substring*/ - GF_ITAG_SUBSTR, + /*! tag is ID3 genre tag, either 32 bit int or string*/ + GF_ITAG_ID3_GENRE, + /*! tag is an fraction on 6 bytes (first 2 unused)*/ + GF_ITAG_FRAC6, + /*! tag is an fraction on 8 bytes (first 2 and last 2 unused)*/ + GF_ITAG_FRAC8, + /*! tag is a file*/ + GF_ITAG_FILE, }; /*! finds a tag by its ID3 value \param id3tag ID3 tag value @@ -1223,9 +1417,9 @@ s32 gf_itags_find_by_name(const char *tag_name); /*! gets tag associated type \param tag_idx tag index - \return corresponding tag type, 0 if error + \return corresponding tag type, -1 if error */ -u32 gf_itags_get_type(u32 tag_idx); +s32 gf_itags_get_type(u32 tag_idx); /*! gets tag associated name \param tag_idx tag index @@ -1233,6 +1427,12 @@ u32 gf_itags_get_type(u32 tag_idx); */ const char *gf_itags_get_name(u32 tag_idx); +/*! gets tag associated alternative names + \param tag_idx tag index + \return corresponding tag name, NULL if none +*/ +const char *gf_itags_get_alt_name(u32 tag_idx); + /*! gets tag associated itunes tag \param tag_idx tag index \return corresponding itunes tag, 0 if error @@ -1294,6 +1494,158 @@ enum { }; +/*! CICP code points for color primaries */ +enum +{ + GF_CICP_PRIM_RESERVED_0 = 0, + GF_CICP_PRIM_BT709, + GF_CICP_PRIM_UNSPECIFIED, + GF_CICP_PRIM_RESERVED_3, + GF_CICP_PRIM_BT470M, + GF_CICP_PRIM_BT470G, + GF_CICP_PRIM_SMPTE170, + GF_CICP_PRIM_SMPTE240, + GF_CICP_PRIM_FILM, + GF_CICP_PRIM_BT2020, + GF_CICP_PRIM_SMPTE428, + GF_CICP_PRIM_SMPTE431, + GF_CICP_PRIM_SMPTE432, + + GF_CICP_PRIM_EBU3213=22, + + GF_CICP_PRIM_LAST +}; + +/*! CICP code points for color transfer */ +enum +{ + GF_CICP_TRANSFER_RESERVED_0 = 0, + GF_CICP_TRANSFER_BT709, + GF_CICP_TRANSFER_UNSPECIFIED, + GF_CICP_TRANSFER_RESERVED_3, + GF_CICP_TRANSFER_BT470M, + GF_CICP_TRANSFER_BT470BG, + GF_CICP_TRANSFER_SMPTE170, + GF_CICP_TRANSFER_SMPTE240, + GF_CICP_TRANSFER_LINEAR, + GF_CICP_TRANSFER_LOG100, + GF_CICP_TRANSFER_LOG316, + GF_CICP_TRANSFER_IEC61966, + GF_CICP_TRANSFER_BT1361, + GF_CICP_TRANSFER_SRGB, + GF_CICP_TRANSFER_BT2020_10, + GF_CICP_TRANSFER_BT2020_12, + GF_CICP_TRANSFER_SMPTE2084, + GF_CICP_TRANSFER_SMPTE428, + GF_CICP_TRANSFER_STDB67, //prores only + + GF_CICP_TRANSFER_LAST +}; + + +/*! CICP code points for matrix coefficients */ +enum +{ + GF_CICP_MX_IDENTITY = 0, + GF_CICP_MX_BT709, + GF_CICP_MX_UNSPECIFIED, + GF_CICP_MX_RESERVED_3, + GF_CICP_MX_FCC47, + GF_CICP_MX_BT601_625, + GF_CICP_MX_SMPTE170, + GF_CICP_MX_SMPTE240, + GF_CICP_MX_YCgCo, + GF_CICP_MX_BT2020, + GF_CICP_MX_BT2020_CL, + GF_CICP_MX_YDzDx, + + GF_CICP_MX_LAST + //the rest is reserved +}; + +/*! parse CICP color primaries + \param val CICP color primaries name +\return 0xFFFFFFFF if error , value otherwise +*/ +u32 gf_cicp_parse_color_primaries(const char *val); + +/*! get CICP color primaries name +\param cicp_prim CICP color primaries code +\return name or "unknown"" if error +*/ +const char *gf_cicp_color_primaries_name(u32 cicp_prim); + +/*! get CICP color primaries names +\return coma-separated list of GPAC names for CICP color primaries +*/ +const char *gf_cicp_color_primaries_all_names(); + +/*! parse CICP color transfer + \param val CICP color transfer name +\return 0xFFFFFFFF if error , value otherwise +*/ +u32 gf_cicp_parse_color_transfer(const char *val); + +/*! get CICP color transfer name +\param cicp_trans CICP color transfer code +\return name or "unknown"" if error +*/ +const char *gf_cicp_color_transfer_name(u32 cicp_trans); + +/*! get CICP color transfer names +\return coma-separated list of GPAC names for CICP color transfer +*/ +const char *gf_cicp_color_transfer_all_names(); + +/*! parse CICP color matrix coefficients + \param val CICP color matrix coefficients name +\return 0xFFFFFFFF if error , value otherwise +*/ +u32 gf_cicp_parse_color_matrix(const char *val); + +/*! get CICP color matrix coefficients name +\param cicp_mx CICP color matrix coefficients code +\return name or "unknown"" if error +*/ +const char *gf_cicp_color_matrix_name(u32 cicp_mx); + +/*! get CICP color matrix names +\return coma-separated list of GPAC names for CICP color matrix +*/ +const char *gf_cicp_color_matrix_all_names(); + + +/*! stereo frame packing types */ +enum +{ + /*! monoscopic video*/ + GF_STEREO_NONE = 0, + /*! left eye in top half of video, right eye in bottom half of video*/ + GF_STEREO_TOP_BOTTOM, + /*! left eye in left half of video, right eye in right half of video*/ + GF_STEREO_LEFT_RIGHT, + /*! stereo mapped through mesh*/ + GF_STEREO_CUSTOM, + /*! left eye in right half of video, right eye in left half of video*/ + GF_STEREO_RIGHT_LEFT, + /*! left eye in bottom half of video, right eye in top half of video*/ + GF_STEREO_BOTTOM_TOP, +}; + +/*! 360 projection types */ +enum +{ + /*! flat video*/ + GF_PROJ360_NONE = 0, + /*! cube map projection video is upper half: right, left, up, lower half: down, front, back*/ + GF_PROJ360_CUBE_MAP, + /*! Equirectangular projection / video*/ + GF_PROJ360_EQR, + /*! Mesh projection (not supported yet)*/ + GF_PROJ360_MESH +}; + + /*! @} */ #ifdef __cplusplus diff --git a/include/gpac/crypt.h b/include/gpac/crypt.h index 0fcb3d3..439f6c5 100644 --- a/include/gpac/crypt.h +++ b/include/gpac/crypt.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre -* Copyright (c) Telecom ParisTech 2000-2019 +* Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Crypto Tools sub-project @@ -65,7 +65,9 @@ typedef enum { /*! CBC chaining mode*/ GF_CBC = 0, /*! CTR chaining mode*/ - GF_CTR = 1 + GF_CTR = 1, + /*! ECB (no chaining), payload must be a multiple of 16-bytes blocks*/ + GF_ECB = 2, } GF_CRYPTO_MODE; /*! Algorithm mode to use*/ @@ -113,7 +115,7 @@ GF_Err gf_crypt_set_IV(GF_Crypt *gfc, const void *iv, u32 size); /*! gets the IV of the algorithm. The size will hold the size of the state and the state must have enough bytes to hold it (17 is enough for AES 128). -In CTR mode, the first byte will be set to the counter value (number of bytes consummed in last block), or 0 if all bytes were consummed +In CTR mode, the first byte will be set to the counter value (number of bytes consumed in last block), or 0 if all bytes were consumed \param gfc the target crytpo context \param iv filled with the current IV \param size will be set to the IV size (16 for AES CBC? 17 for AES CTR) diff --git a/include/gpac/crypt_tools.h b/include/gpac/crypt_tools.h index 68f73f8..4a97192 100644 --- a/include/gpac/crypt_tools.h +++ b/include/gpac/crypt_tools.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Media Tools sub-project @@ -67,6 +67,9 @@ enum GF_CRYPT_TYPE_ADOBE = GF_4CC('a','d','k','m'), /*! PIFF CTR-128 encryption*/ GF_CRYPT_TYPE_PIFF = GF_4CC('p','i','f','f'), + /*! HLS Sample encryption*/ + GF_CRYPT_TYPE_SAES = GF_4CC('s','a','e','s'), + }; /*! Selective encryption modes */ @@ -92,6 +95,38 @@ enum GF_CRYPT_SELENC_CLEAR_FORCED, }; +/*! Key info structure, one per defined key in the DRM XML doc*/ +typedef struct +{ + //keep first 3 bin128 at the begining for data alignment + /*! KEY ID*/ + bin128 KID; + /*! key value*/ + bin128 key; + /*! constant IV or initial IV if not constant*/ + u8 IV[16]; + + /*! hls_info defined*/ + char *hls_info; + /*!IV size */ + u8 IV_size; + /*! constant IV size */ + u8 constant_IV_size; +} GF_CryptKeyInfo; + +/*! key roll modes*/ +typedef enum +{ + /*! change keys every keyRoll AUs*/ + GF_KEYROLL_SAMPLES = 0, + /*! roll keys at each SAP type 1 or 2 for streams with SAPs*/ + GF_KEYROLL_SAPS, + /*! change keys every keyRoll DASH segments*/ + GF_KEYROLL_SEGMENTS, + /*! change keys every keyRoll periods*/ + GF_KEYROLL_PERIODS, +} GF_KeyRollType; + /*! Crypto information for one media stream*/ typedef struct { @@ -99,8 +134,6 @@ typedef struct u32 scheme_type; /*! ID of track / PID / ... to be encrypted*/ u32 trackID; - /*! Initialization vector of the first sample/AU in track/media for CENC. For IMA/OMA, the first 8 bytes contain the salt data.*/ - unsigned char first_IV[16]; /*! URI of key management system / rightsIssuerURL*/ char *KMS_URI; /*! Scheme URI or contentID for OMA*/ @@ -132,26 +165,22 @@ typedef struct and also add support for multiple keys in ISMA ?*/ /*! default encryption state for samples*/ u32 IsEncrypted; - /*! size of init vector: 0, 8 or 16*/ - u8 IV_size; - /*! number of KEY IDs and Keys defined*/ - u32 KID_count; - /*! KEY IDs defined*/ - bin128 *KIDs; + /*! number of defined keys*/ + u32 nb_keys; /*! keys defined*/ - bin128 *keys; + GF_CryptKeyInfo *keys; + /*! default key index to use*/ u32 defaultKeyIdx; - /*! roll period of keys (change keys every keyRoll AUs)*/ + /*! roll period of keys*/ u32 keyRoll; + /*! roll type */ + GF_KeyRollType roll_type; /*! number of bytes to leave in the clear for non NAL-based tracks. Only used in cbcs mode*/ u32 clear_bytes; + /*! CENS/CBCS pattern */ u8 crypt_byte_block, skip_byte_block; - /*! cponstant IV size */ - u8 constant_IV_size; - /*! constant IV */ - unsigned char constant_IV[16]; /* ! for avc1 ctr CENC edition 1 */ Bool allow_encrypted_slice_header; @@ -169,6 +198,20 @@ typedef struct /*! force using type set in XML rather than type indicated in file when decrypting*/ Bool force_type; + + /*! generate random keys and key values*/ + Bool rand_keys; + + /*! randomly encrypts subsample if rand() % subs_rand is 0*/ + u32 subs_rand; + /*! list of VCL NAL/OBU indices to encrypt, 1-based*/ + char *subs_crypt; + /*! use multiple keys per sample*/ + Bool multi_key; + /*! roll key over subsamples. If 0, roll by 1 every encrypted sample. If 1 (-1==0) disable key roll*/ + u32 mkey_roll_plus_one; + /*!coma-separated list of indices of keys to use per subsample. Value 0 means keep clear. If less indices than subsamples, keep subsamples in clear*/ + char *mkey_subs; } GF_TrackCryptInfo; /*! Crypto information*/ @@ -182,6 +225,8 @@ typedef struct Bool has_common_key; /*! intern to parser*/ Bool in_text_header; + /*! intern to parser*/ + GF_Err last_parse_error; } GF_CryptInfo; /*! loads a given crypto configuration file. Full doc is available at https://gpac.wp.imt.fr/mp4box/encryption/common-encryption/ diff --git a/include/gpac/dash.h b/include/gpac/dash.h index 7cda853..dc93219 100644 --- a/include/gpac/dash.h +++ b/include/gpac/dash.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2012-2019 + * Copyright (c) Telecom ParisTech 2012-2022 * All rights reserved * * This file is part of GPAC / Adaptive HTTP Streaming sub-project @@ -45,6 +45,7 @@ extern "C" { */ #include +#include #ifndef GPAC_DISABLE_DASH_CLIENT @@ -56,14 +57,14 @@ static const char * const GF_DASH_MPD_MIME_TYPES[] = { "application/dash+xml", " /*! * All the possible Mime-types for M3U8 files */ -static const char * const GF_DASH_M3U8_MIME_TYPES[] = { "video/x-mpegurl", "audio/x-mpegurl", "application/x-mpegurl", "application/vnd.apple.mpegurl", NULL}; +static const char * const GF_DASH_M3U8_MIME_TYPES[] = { "video/x-mpegurl", "audio/x-mpegurl", "application/x-mpegURL", "application/vnd.apple.mpegURL", NULL}; /*! * All the possible Mime-types for Smooth files */ static const char * const GF_DASH_SMOOTH_MIME_TYPES[] = { "application/vnd.ms-sstr+xml", NULL}; -/*! DASH Event type. The DASH client communitcaes with the user through a callback mechanism using events*/ +/*! DASH Event type. The DASH client communicates with the user through a callback mechanism using events*/ typedef enum { /*! event sent if an error occurs when setting up manifest*/ @@ -74,7 +75,7 @@ typedef enum GF_DASH_EVENT_PERIOD_SETUP_ERROR, /*! event sent once the first segment of each selected group is fetched - user should load playback chain(s) at this point*/ GF_DASH_EVENT_CREATE_PLAYBACK, - /*! event sent when reseting groups at period switch or at exit - user should unload playback chain(s) at this point*/ + /*! event sent when resetting groups at period switch or at exit - user should unload playback chain(s) at this point*/ GF_DASH_EVENT_DESTROY_PLAYBACK, /*! event sent once a new segment becomes available*/ GF_DASH_EVENT_SEGMENT_AVAILABLE, @@ -82,15 +83,15 @@ typedef enum GF_DASH_EVENT_QUALITY_SWITCH, /*! position in timeshift buffer has changed (eg, paused)*/ GF_DASH_EVENT_TIMESHIFT_UPDATE, - /*! event sent when timeshift buffer is overflown - the group_idx param contains the max number of dropped segments of all representations droped by the client, or -1 if play pos is ahead of live */ + /*! event sent when timeshift buffer is overflown - the group_idx param contains the max number of dropped segments of all representations dropped by the client, or -1 if play pos is ahead of live */ GF_DASH_EVENT_TIMESHIFT_OVERFLOW, - /*! event send when we need the decoding statistics*/ + /*! event sent when we need the decoding statistics*/ GF_DASH_EVENT_CODEC_STAT_QUERY, - /*! event send when no threading to trigger segment download abort*/ + /*! event sent when no threading to trigger segment download abort*/ GF_DASH_EVENT_ABORT_DOWNLOAD, - /*! event send whenever cache is full, to allow client to dispatch any segment*/ + /*! event sent whenever cache is full, to allow client to dispatch any segment*/ GF_DASH_EVENT_CACHE_FULL, - /*! event send when all groups are done in a period*/ + /*! event sent when all groups are done in a period - if group_idx is 1, this announces a time discontinuity for next period*/ GF_DASH_EVENT_END_OF_PERIOD, } GF_DASHEventType; @@ -148,6 +149,10 @@ struct _gf_dash_io u32 (*get_total_size)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session); /*! get the total size on bytes for the session*/ u32 (*get_bytes_done)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session); + + /*! callback when manifest (DASH, HLS) or sub-playlist (HLS) is updated*/ + void (*manifest_updated)(GF_DASHFileIO *dashio, const char *manifest_name, const char *local_path, s32 group_idx); + }; /*! DASH client object*/ @@ -168,31 +173,20 @@ typedef enum GF_DASH_SELECT_BANDWIDTH_HIGHEST_TILES } GF_DASHInitialSelectionMode; -/*! DASH client threading mode*/ -typedef enum -{ - /*! no threads used, gf_dash_process shall be called on regular basis*/ - GF_DASH_THREAD_NONE = 0, - /*! single thread used for MPD and segment download*/ - GF_DASH_THREAD_SINGLE, - /*! one thread for MPD and each independent representations*/ - GF_DASH_THREAD_ALL -} GF_DASHThreadMode; /*! create a new DASH client \param dash_io DASH callbacks to the user -\param thread_mode threading mode of the dash client \param max_cache_duration maximum duration in milliseconds for the cached media. If less than \code mpd@minBufferTime \endcode , \code mpd@minBufferTime \endcode is used -\param auto_switch_count forces representation switching every auto_switch_count segments, set to 0 to disable +\param auto_switch_count forces representation switching (quality up if positive, down if negative) every auto_switch_count segments, set to 0 to disable \param keep_files do not delete files from the cache \param disable_switching turn off bandwidth switching algorithm \param first_select_mode indicates which representation to select upon startup \param initial_time_shift_value sets initial buffering: if between 0 and 100, this is a percentage of the time shift window of the session. If greater than 100, this is a time shift in milliseconds. \return a new DASH client */ -GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, GF_DASHThreadMode thread_mode, +GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, u32 max_cache_duration, - u32 auto_switch_count, + s32 auto_switch_count, Bool keep_files, Bool disable_switching, GF_DASHInitialSelectionMode first_select_mode, @@ -232,6 +226,12 @@ const char *gf_dash_get_url(GF_DashClient *dash); */ Bool gf_dash_is_m3u8(GF_DashClient *dash); +/*! tells whether we are playing some MS SmoothStreaming +\param dash the target dash client +\return GF_TRUE if the manifest is SmoothStreaming +*/ +Bool gf_dash_is_smooth_streaming(GF_DashClient *dash); + /*! gets title and source for this MPD \param dash the target dash client \param title set to the title of the manifest (may be NULL) @@ -242,9 +242,8 @@ void gf_dash_get_info(GF_DashClient *dash, const char **title, const char **sour /*! switches quality up or down \param dash the target dash client \param switch_up indicates if the quality should be increased (GF_TRUE) or decreased (GF_FALSE) -\param force_immediate_switch if GF_TRUE, aborts all current downloads, remove downloaded segments not yet played and switch. Otherwise, existing switching will only happen once the existing downloaded segments have been played */ -void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool force_immediate_switch); +void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up); /*! indicates whether the DASH client is running or not \param dash the target dash client @@ -329,13 +328,33 @@ s32 gf_dash_get_dependent_group_index(GF_DashClient *dash, u32 group_idx, u32 gr */ Bool gf_dash_is_group_selectable(GF_DashClient *dash, u32 group_idx); -/*! selects a group for playback. If other groups are alternate to this group (through the group attribute), they are automatically deselected +/*! selects a group for playback. If group selection is enabled, other groups are alternate to this group (through the group attribute), they are automatically deselected \param dash the target dash client \param group_idx the 0-based index of the target group \param select if GF_TRUE, will select this group and disable any alternate group. If GF_FALSE, only deselects the group */ void gf_dash_group_select(GF_DashClient *dash, u32 group_idx, Bool select); +/*! gets group ID (through the group attribute), -1 if undefined +\param dash the target dash client +\param group_idx the 0-based index of the target group +\return ID of the group +*/ +s32 gf_dash_group_get_id(GF_DashClient *dash, u32 group_idx); + +/*! enables group selection through the group attribute +\param dash the target dash client +\param enable if GF_TRUE, group selection will be done whenever selecting a new group +*/ +void gf_dash_enable_group_selection(GF_DashClient *dash, Bool enable); + +/*! checks if first segment (used to initialize) was an init segment or the first in a sequence (aka M2TS) +\param dash the target dash client +\param group_idx the 0-based index of the target group +\return GF_TRUE if first segment was a media segment +*/ +Bool gf_dash_group_init_segment_is_media(GF_DashClient *dash, u32 group_idx); + /*! performs selection of representations based on language code \param dash the target dash client \param lang_code_rfc_5646 the language code used by the default group selection @@ -362,10 +381,11 @@ const char *gf_dash_group_get_segment_init_url(GF_DashClient *dash, u32 group_id This is used for full segment encryption modes of MPEG-2 TS segments. key_IV is optional \param dash the target dash client \param group_idx the 0-based index of the target group +\param crypto_type set to 0 if no encryption in segments, 1 if full segment encryption, 2 if CENC/per-sample encryption is used - may be NULL \param key_IV set to the IV used for the first media segment (can be NULL) -\return the key URL of the first media segment +\return the key URL of the first media segment, either a URN or a resolved URL */ -const char *gf_dash_group_get_segment_init_keys(GF_DashClient *dash, u32 group_idx, bin128 *key_IV); +const char *gf_dash_group_get_segment_init_keys(GF_DashClient *dash, u32 group_idx, u32 *crypto_type, bin128 *key_IV); /*! returns the language of the group \param dash the target dash client @@ -384,7 +404,7 @@ u32 gf_dash_group_get_audio_channels(GF_DashClient *dash, u32 group_idx); /*! gets time shift buffer depth of the group \param dash the target dash client \param group_idx the 0-based index of the target group -\return time shift buffer depth of the group, -1 means infinity +\return time shift buffer depth in ms of the group, -1 means infinity */ u32 gf_dash_group_get_time_shift_buffer_depth(GF_DashClient *dash, u32 group_idx); @@ -473,26 +493,26 @@ Bool gf_dash_group_enum_descriptor(GF_DashClient *dash, u32 group_idx, GF_DashDe \param switching_end_range set to end byte offset of the switching segment if needed (optional, may be NULL) \param original_url set to original URL value of the segment (optional, may be NULL) \param has_next_segment set to GF_TRUE if next segment location is known (unthreaded mode) or next segment is downloaded (threaded mode) (optional, may be NULL) -\param key_url set to the key URL of the next segment for MPEG-2 TS full segment encryption (optional, may be NULL) +\param key_url set to the key URL of the next segment for MPEG-2 TS full segment encryption (optional, may be NULL). The URL is either a URN or a resolved URL \param key_IV set to the key initialization vector of the next segment for MPEG-2 TS full segment encryption (optional, may be NULL) -\return GF_BUFFER_TOO_SMALL if no segment found, GF_EOS if end of session or error if any +\return GF_BUFFER_TOO_SMALL if no segment found, GF_EOS if end of session, GF_URL_REMOVED if segment is disabled (but all output info is OK, this can be ignored and considered as GF_OK by the user) or error if any */ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 group_idx, u32 dependent_representation_index, const char **url, u64 *start_range, u64 *end_range, s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range, const char **original_url, Bool *has_next_segment, const char **key_url, bin128 *key_IV); -/*! same as gf_dash_group_get_next_segment_location but query the current downloaded segment +/*! gets some info on the segment \param dash the target dash client \param group_idx the 0-based index of the target group -\param url set to the URL of the next segment -\param switching_index set to the quality index of the segment (optional, may be NULL) -\param switching_url set to the URL of the switching segment if needed (optional, may be NULL) -\param original_url set to original URL value of the segment (optional, may be NULL) -\param switched set to GF_TRUE if current segment being downloaded follows an aborted download (optional, may be NULL) -\return GF_BUFFER_TOO_SMALL if no segment found, GF_EOS if end of session or error if any +\param dependent_representation_index index of the dependent representation to query, 0-based +\param seg_name set to the segment name, without base url - optional, may be NULL +\param seg_number set to the segment number for $Number$ addressing - optional, may be NULL +\param seg_time set to the segment start time - optional, may be NULL +\param seg_dur_ms set to the segment estimated duration in ms - optional, may be NULL +\param init_segment set to the init segment name, without base url - optional, may be NULL +\return error if any, GF_BUFFER_TOO_SMALL if no segments queued for download */ -GF_EXPORT -GF_Err gf_dash_group_probe_current_download_segment_location(GF_DashClient *dash, u32 group_idx, const char **url, s32 *switching_index, const char **switching_url, const char **original_url, Bool *switched); +GF_Err gf_dash_group_next_seg_info(GF_DashClient *dash, u32 group_idx, u32 dependent_representation_index, const char **seg_name, u32 *seg_number, GF_Fraction64 *seg_time, u32 *seg_dur_ms, const char **init_segment); /*! checks if loop was detected in playback. This is mostly used for broadcast (eMBMS, ROUTE) based on pcap replay. \param dash the target dash client @@ -501,35 +521,42 @@ GF_Err gf_dash_group_probe_current_download_segment_location(GF_DashClient *dash */ Bool gf_dash_group_loop_detected(GF_DashClient *dash, u32 group_idx); -/*! returns number of seconds at which playback shall start for the group in the current period. -The first segment available for the period will be so that gf_dash_group_get_start_range is in this range after the caller -adjusts it with PTO (eg the returned time is in period timeline, not media timeline) +/*! checks if group is using low latency delivery. \param dash the target dash client \param group_idx the 0-based index of the target group -\return media playback start range in seconds*/ -Double gf_dash_group_get_start_range(GF_DashClient *dash, u32 group_idx); +\return GF_TRUE if low latency is used, GF_FALSE otherwise +*/ +Bool gf_dash_is_low_latency(GF_DashClient *dash, u32 group_idx); -/*! discards the first media resource in the queue of this group +/*! gets average duration of segments for the current rep. \param dash the target dash client \param group_idx the 0-based index of the target group +\param duration set to average segment duration +\param timescale set to timescale used to exprss duration +\return error if any */ -void gf_dash_group_discard_segment(GF_DashClient *dash, u32 group_idx); +GF_Err gf_dash_group_get_segment_duration(GF_DashClient *dash, u32 group_idx, u32 *duration, u32 *timescale); -/*! gets the number of media resources available in the cache for this group +/*! gets ID of active representaion. \param dash the target dash client \param group_idx the 0-based index of the target group -\param group_is_done setto GF_TRUE if group is done playing -\return number of segments ready +\return ID of representation, NULL if error */ -u32 gf_dash_group_get_num_segments_ready(GF_DashClient *dash, u32 group_idx, Bool *group_is_done); +const char *gf_dash_group_get_representation_id(GF_DashClient *dash, u32 group_idx); -/*! get the maximum number of media resources that can be put in the cache for this group in threaded mode. -In unthreaded mode, only the next URL is available and the caller is responsible for fetching the media +/*! returns number of seconds at which playback shall start for the group in the current period. +The first segment available for the period will be so that gf_dash_group_get_start_range is in this range after the caller +adjusts it with PTO (eg the returned time is in period timeline, not media timeline) +\param dash the target dash client +\param group_idx the 0-based index of the target group +\return media playback start range in seconds*/ +Double gf_dash_group_get_start_range(GF_DashClient *dash, u32 group_idx); + +/*! discards the first media resource in the queue of this group \param dash the target dash client \param group_idx the 0-based index of the target group -\return maximum number of cached segments */ -u32 gf_dash_group_get_max_segments_in_cache(GF_DashClient *dash, u32 group_idx); +void gf_dash_group_discard_segment(GF_DashClient *dash, u32 group_idx); /*! indicates to the DASH engine that the group playback has been stopped by the user \param dash the target dash client @@ -554,6 +581,13 @@ GF_Err gf_dash_group_get_presentation_time_offset(GF_DashClient *dash, u32 group */ Bool gf_dash_in_last_period(GF_DashClient *dash, Bool check_eos); +/*! checks if the group is playing +\param dash the target dash client +\param group_idx the 0-based index of the target group +\return GF_TRUE if group is done playing +*/ +Bool gf_dash_get_group_done(GF_DashClient *dash, u32 group_idx); + /*! gets current period switching status for the session. \param dash the target dash client \return possible values: @@ -612,9 +646,13 @@ void gf_dash_set_speed(GF_DashClient *dash, Double speed); /*! updates media bandwidth for the given group. Only allowed for groups without dependencies to other groups \param dash the target dash client \param group_idx the 0-based index of the target group +\param bits_per_sec current download rate in bits per seconds +\param total_bytes total size of segment being downloaded +\param bytes_done number of bytes already downloaded in current segment +\param us_since_start time elapsed in microseconds since segment has been scheduled for download \return error if any */ -GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 group_idx); +GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 group_idx, u32 bits_per_sec, u64 total_bytes, u64 bytes_done, u64 us_since_start); /*! enables UTC drift computation using HTTP header "Server-UTC: UTC", where UTC is in ms \param dash the target dash client @@ -634,6 +672,12 @@ Bool gf_dash_is_dynamic_mpd(GF_DashClient *dash); */ u32 gf_dash_get_min_buffer_time(GF_DashClient *dash); +/*! gets the maximum segment duration in session +\param dash the target dash client +\return the maximum segment duration in ms +*/ +u32 gf_dash_get_max_segment_duration(GF_DashClient *dash); + /*! gets the difference between the local UTC clock and the one reported by the server \param dash the target dash client \return difference in milliseconds @@ -662,18 +706,19 @@ GF_Err gf_dash_set_max_resolution(GF_DashClient *dash, u32 width, u32 height, u8 */ GF_Err gf_dash_set_min_timeout_between_404(GF_DashClient *dash, u32 min_timeout_between_404); -/*! sets time in ms after which 404 request for a segment will indicate segment lost. The clien always retries for segment availability time + segment duration. This allows extanding slightly the probe time (used when segment durations varies, or for VBR broadcast). The default value is 100 ms. +/*! sets time in ms after which 404 request for a segment will indicate segment lost. The client always retries for segment availability time + segment duration. This allows extending slightly the probe time (used when segment durations varies, or for VBR broadcast). The default value is 100 ms. \param dash the target dash client \param expire_after_ms delay in milliseconds \return error if any */ GF_Err gf_dash_set_segment_expiration_threshold(GF_DashClient *dash, u32 expire_after_ms); -/*! only enables the given group - this shall be set before calling \ref gf_dash_open. If group_idx is <0 (default) no groups will be disabled +/*! only enables the given groups - this shall be set before calling \ref gf_dash_open. If NULL, no groups will be disabled \param dash the target dash client -\param group_idx the 0-based index of the target group +\param groups_idx list of 0-based index of the target groups to enable, +\param nb_groups number of group indexes in list */ -void gf_dash_debug_group(GF_DashClient *dash, s32 group_idx); +void gf_dash_debug_groups(GF_DashClient *dash, const u32 *groups_idx, u32 nb_groups); /*! split all adatation sets so that they contain only one representation (quality) \param dash the target dash client @@ -717,6 +762,24 @@ void gf_dash_set_switching_probe_count(GF_DashClient *dash, u32 switch_probe_cou */ void gf_dash_set_agressive_adaptation(GF_DashClient *dash, Bool enable_agressive_switch); +/*! enables single-range requests for LL-HLS byterange, rather than issuing a request per PART. This assumes that: + - each URI in the different parts is the SAME + - byte ranges are contiguous in the URL + +Errors will be thrown if these are not met on future parts and merging will be disabled, however the scheduled buggy segment will NOT be disarded + +\param dash the target dash client +\param enable_single_range if GF_TRUE, enables single range, otherwise disables it +*/ +void gf_dash_enable_single_range_llhls(GF_DashClient *dash, Bool enable_single_range); + +/*! create a new DASH client +\param dash the target dash cleint +\param auto_switch_count forces representation switching (quality up if positive, down if negative) every auto_switch_count segments, set to 0 to disable +\param auto_switch_loop if false (default when creating dasher), restart at lowest quality when higher quality is reached and vice-versa. If true, quality switches decreases then increase in loop +*/ +void gf_dash_set_auto_switch(GF_DashClient *dash, s32 auto_switch_count, Bool auto_switch_loop); + /*! returns active period start \param dash the target dash client \return period start in milliseconds @@ -750,6 +813,7 @@ u32 gf_dash_group_get_num_components(GF_DashClient *dash, u32 group_idx); void gf_dash_disable_speed_adaptation(GF_DashClient *dash, Bool disable); /*! DASH/HLS quality information structure*/ +//UPDATE DASHQualityInfoNat in libgpac.py whenever modifying this structure !! typedef struct { /*! bandwidth in bits per second*/ @@ -767,9 +831,9 @@ typedef struct /*! video interlaced flag*/ Bool interlaced; /*! video framerate numerator*/ - u32 fps_den; - /*! video framerate denominator*/ u32 fps_num; + /*! video framerate denominator*/ + u32 fps_den; /*! video sample aspect ratio numerator*/ u32 par_num; /*! video sample aspect ratio denominator*/ @@ -782,6 +846,12 @@ typedef struct Bool disabled; /*! selected flag*/ Bool is_selected; + /*! AST offset in seconds, 0 if not low latency*/ + Double ast_offset; + /*! average segment duration, 0 if unknown*/ + Double average_duration; + /*! list of segmentURLs if known, NULL otherwise. Used for onDemand profile to get segment sizes*/ + const GF_List *seg_urls; } GF_DASHQualityInfo; /*! gets information on a given quality @@ -793,6 +863,15 @@ typedef struct */ GF_Err gf_dash_group_get_quality_info(GF_DashClient *dash, u32 group_idx, u32 quality_idx, GF_DASHQualityInfo *quality); +/*! gets segment template info used by group +\param dash the target dash client +\param group_idx the 0-based index of the target group +\param segment_timeline_timescale set to segment timeline timescale, or to 0 if no segment timeline +\param init_url set to initialization URL (template, timeline or base URL for VoD) as indicated in manifest (no resolution to base URL) +\return segment template, NULL if no templates used. Memory must be freed by caller +*/ +char *gf_dash_group_get_template(GF_DashClient *dash, u32 group_idx, u32 *segment_timeline_timescale, const char **init_url); + /*! checks automatic switching mode \param dash the target dash client \return GF_TRUE if automatic quality switching is enabled @@ -821,13 +900,6 @@ GF_Err gf_dash_group_select_quality(GF_DashClient *dash, u32 group_idx, const ch \return the current quality index for the given group*/ s32 gf_dash_group_get_active_quality(GF_DashClient *dash, u32 group_idx); -/*! gets download rate for a given group -\param dash the target dash client -\param group_idx the 0-based index of the target group -\return download rate in bytes per second -*/ -u32 gf_dash_group_get_download_rate(GF_DashClient *dash, u32 group_idx); - /*! forces NTP of the DASH client to be the given NTP \param dash the target dash client \param server_ntp NTP timestamp to set as server clock @@ -835,7 +907,7 @@ u32 gf_dash_group_get_download_rate(GF_DashClient *dash, u32 group_idx); void gf_dash_override_ntp(GF_DashClient *dash, u64 server_ntp); /*! Tile adaptation mode -This mode specifies how bitrate is allocated accross tiles of the same video +This mode specifies how bitrate is allocated across tiles of the same video */ typedef enum { @@ -866,6 +938,13 @@ typedef enum */ void gf_dash_set_tile_adaptation_mode(GF_DashClient *dash, GF_DASHTileAdaptationMode mode, u32 tile_rate_decrease); + +/*! consider tile with highest quality degradation hints (not visible ones or not gazed at) as lost, triggering a GF_URL_REMOVE upon \ref gf_dash_group_get_next_segment_location calls. Mostly used to debug tiling adaptation +\param dash the target dash client +\param disable_tiles if GF_TRUE, tiles with highest quality degradation hints will not be played. +*/ +void gf_dash_disable_low_quality_tiles(GF_DashClient *dash, Bool disable_tiles); + /*! gets current tile adaptation mode \param dash the target dash client \return tile adaptation mode*/ @@ -932,6 +1011,13 @@ Bool gf_dash_all_groups_done(GF_DashClient *dash); */ void gf_dash_set_period_xlink_query_string(GF_DashClient *dash, const char *query_string); +/*! sets MPD chaining mode +\param dash the target dash client +\param chaining_mode if 0, no chaining. If 1, chain at end. If 2 chain on error or at end +*/ +void gf_dash_set_chaining_mode(GF_DashClient *dash, u32 chaining_mode); + + /*! DASH client adaptation algorithm*/ typedef enum { /*! no adaptation*/ @@ -949,7 +1035,9 @@ typedef enum { /*! BOLA-U*/ GF_DASH_ALGO_BOLA_U, /*! BOLA-O*/ - GF_DASH_ALGO_BOLA_O + GF_DASH_ALGO_BOLA_O, + /*! Custom*/ + GF_DASH_ALGO_CUSTOM } GF_DASHAdaptationAlgorithm; /*! sets dash adaptation algorithm. Cannot be called on an active session @@ -961,26 +1049,28 @@ void gf_dash_set_algo(GF_DashClient *dash, GF_DASHAdaptationAlgorithm algo); /*! sets group download status of the last downloaded segment for non threaded modes \param dash the target dash client \param group_idx the 0-based index of the target group +\param dep_rep_idx the 0-based index of the current dependent rep \param err error status of the download, GF_OK if no error */ -void gf_dash_set_group_download_state(GF_DashClient *dash, u32 group_idx, GF_Err err); +void gf_dash_set_group_download_state(GF_DashClient *dash, u32 group_idx, u32 dep_rep_idx, GF_Err err); /*! sets group download statistics of the last downloaded segment for non threaded modes \param dash the target dash client \param group_idx the 0-based index of the target group +\param dep_rep_idx the 0-based index of the dependent rep \param bytes_per_sec transfer rates in bytes per seconds \param file_size segment size in bytes -\param bytes_done number of received bytes \param is_broadcast set to GF_TRUE if the file is received over a multicast/broadcast link such as eMBMS or ROUTE (i.e. file was pushed to cache) +\param us_since_start time in microseconds since start of the download */ -void gf_dash_group_store_stats(GF_DashClient *dash, u32 group_idx, u32 bytes_per_sec, u32 file_size, u32 bytes_done, Bool is_broadcast); +void gf_dash_group_store_stats(GF_DashClient *dash, u32 group_idx, u32 dep_rep_idx, u32 bytes_per_sec, u64 file_size, Bool is_broadcast, u64 us_since_start); -/*! sets availabilityStartTime shift for ATSC. By default the ATSC tune-in is done by matching the last received segment name -to the segment template and deriving the ATSC UTC reference from that. The function allows shifting the computed value by a given amount. +/*! sets availabilityStartTime shift for ROUTE. By default the ROUTE tune-in is done by matching the last received segment name +to the segment template and deriving the ROUTE UTC reference from that. The function allows shifting the computed value by a given amount. \param dash the target dash client -\param ast_shift clock shift in milliseconds of the ATSC receiver tune-in. Positive values shift the clock in the future, negative ones in the past +\param ast_shift clock shift in milliseconds of the ROUTE receiver tune-in. Positive values shift the clock in the future, negative ones in the past */ -void gf_dash_set_atsc_ast_shift(GF_DashClient *dash, u32 ast_shift); +void gf_dash_set_route_ast_shift(GF_DashClient *dash, u32 ast_shift); /*! gets the minimum wait time before calling \ref gf_dash_process again for unthreaded mode \param dash the target dash client @@ -991,9 +1081,85 @@ u32 gf_dash_get_min_wait_ms(GF_DashClient *dash); /*! gets the adaptation set ID of a given group \param dash the target dash client \param group_idx the 0-based index of the target group -\return the adaptation set ID +\return the adaptation set ID, -1 if not set */ -u32 gf_dash_group_get_as_id(GF_DashClient *dash, u32 group_idx); +s32 gf_dash_group_get_as_id(GF_DashClient *dash, u32 group_idx); + +/*! check if the group has an init segment associated +\param dash the target dash client +\param group_idx the 0-based index of the target group +\return GF_TRUE if init segment is present, GF_FALSE otherwise +*/ +Bool gf_dash_group_has_init_segment(GF_DashClient *dash, u32 group_idx); + +//any change to the structure below MUST be reflected in libgpac.py !! + +/*! Information passed to DASH custom algorithm*/ +typedef struct +{ + /*! last segment download rate in bits per second */ + u32 download_rate; + /*! size of last downloaded segment*/ + u32 file_size; + /*! current playback speed*/ + Double speed; + /*! max supported playback speed according to associated decoder stats*/ + Double max_available_speed; + /*! display width of the video in pixels, 0 if audio stream*/ + u32 display_width; + /*! display height of the video in pixels, 0 if audio stream*/ + u32 display_height; + /*! index of currently selected quality*/ + u32 active_quality_idx; + /*! minimum buffer level in milliseconds below witch rebuffer will happen*/ + u32 buffer_min_ms; + /*! maximum buffer level allowed in milliseconds. Packets won't get dropped if overflow, but the algorithm should try not to overflow this buffer*/ + u32 buffer_max_ms; + /*! current buffer level in milliseconds*/ + u32 buffer_occupancy_ms; + /*! degradation hint, 0 means no degradation, 100 means tile completely hidden*/ + u32 quality_degradation_hint; + /*! cumulated download rate of all active groups - 0 means all files are local*/ + u32 total_rate; +} GF_DASHCustomAlgoInfo; + +/*! Callback function for custom rate adaptation +\param udta user data +\param group_idx index of group to adapt +\param base_group_idx index of associated base group if group is a dependent group +\param force_lower_complexity set to true if the dash client would like a lower complexity +\param stats statistics for last downloaded segment +\return value can be: +- the index of the new quality to select (as listed in group.reps[]) +- `-1` to not take decision now and postpone it until dependent groups are done +- `-2` to disable quality +- any other negative value means error + */ +typedef s32 (*gf_dash_rate_adaptation)(void *udta, u32 group_idx, u32 base_group_idx, Bool force_lower_complexity, GF_DASHCustomAlgoInfo *stats); + +/*! Callback function for custom rate monitor, not final yet +\param udta user data +\param group_idx index of group to adapt +\param bits_per_sec estimated download rate (not premultiplied by playback speed) +\param total_bytes size of segment being downloaded, 0 if unknown +\param bytes_done bytes received for segment +\param us_since_start microseconds ellapse since segment was sheduled for download +\param buffer_dur_ms current buffer duration in milliseconds +\param current_seg_dur duration of segment being downloaded, 0 if unknown +\return quality index (>=0) to switch to after abort, -1 to do nothing (no abort), -2 for internal algorithms having already setup the desired quality and requesting only abort + */ +typedef s32 (*gf_dash_download_monitor)(void *udta, u32 group_idx, u32 bits_per_sec, u64 total_bytes, u64 bytes_done, u64 us_since_start, u32 buffer_dur_ms, u32 current_seg_dur); + + +/*! sets custom rate adaptation logic +\param dash the target dash client +\param udta user data to pass back to callback functions +\param algo_custom rate adaptation custom logic +\param download_monitor_custom download monitor custom logic + */ +void gf_dash_set_algo_custom(GF_DashClient *dash, void *udta, + gf_dash_rate_adaptation algo_custom, + gf_dash_download_monitor download_monitor_custom); #endif //GPAC_DISABLE_DASH_CLIENT diff --git a/include/gpac/download.h b/include/gpac/download.h index ea15ca3..907e649 100644 --- a/include/gpac/download.h +++ b/include/gpac/download.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2021 * All rights reserved * * This file is part of GPAC / common tools sub-project @@ -154,13 +154,18 @@ typedef enum /*!signal that the session has been deconnected*/ GF_NETIO_DISCONNECTED, /*!downloader session failed (error code set) or done/destroyed (no error code)*/ - GF_NETIO_STATE_ERROR + GF_NETIO_STATE_ERROR, + /*!signal that a new session is being requested on that same connection (h2, h3) + This is only used for server sessions*/ + GF_NETIO_REQUEST_SESSION, + /*! stream has been canceled by remote peer*/ + GF_NETIO_CANCEL_STREAM, } GF_NetIOStatus; /*!session download flags*/ typedef enum { - /*!session is not threaded, the user must explicitely fetch the data , either with the function gf_dm_sess_fetch_data + /*!session is not threaded, the user must explicitly fetch the data , either with the function gf_dm_sess_fetch_data or the function gf_dm_sess_process- if the session is threaded, the user must call gf_dm_sess_process to start the session*/ GF_NETIO_SESSION_NOT_THREADED = 1, /*! session data is cached or not */ @@ -174,6 +179,8 @@ typedef enum GF_NETIO_SESSION_MEMORY_CACHE = 1<<4, /*! do not delete files after download*/ GF_NETIO_SESSION_KEEP_CACHE = 1<<5, + /*! do not delete files after download of first resource (used for init segments)*/ + GF_NETIO_SESSION_KEEP_FIRST_CACHE = 1<<6, } GF_NetIOFlags; @@ -384,7 +391,7 @@ const char *gf_dm_sess_get_resource_name(GF_DownloadSession *sess); #ifndef GPAC_DISABLE_CORE_TOOLS /*! Downloads a file over the network using a download manager -\param dm The download manager to use, function will use all associated cache ressources +\param dm The download manager to use, function will use all associated cache resources \param url The url to download \param filename The filename to download \param start_range start position of a byte range @@ -488,11 +495,12 @@ GF_Err gf_dm_sess_get_header_sizes_and_times(GF_DownloadSession *sess, u32 *req_ Forces session to use memory storage for future downloads \param sess the current session +\param force_cache_type if 1, cache will be kept even if session is reassigned. If 2, cache will ne kept for next resource downloaded, then no caching for subsequent resources (used for init segments) */ -void gf_dm_sess_force_memory_mode(GF_DownloadSession *sess); +void gf_dm_sess_force_memory_mode(GF_DownloadSession *sess, u32 force_cache_type); /*! -Registers a locacl cache provider (bypassing the http session), used when populating cache from input data (atsc for example) +Registers a local cache provider (bypassing the http session), used when populating cache from input data (ROUTE for example) \param dm the download manager \param local_cache_url_provider_cbk callback function to the cache provider. The callback function shall return GF_TRUE if the requested URL is provided by this local cache @@ -506,8 +514,7 @@ Adds a local entry in the cache \param dm the download manager \param szURL the URL this resource is caching -\param data data of the resource -\param size size of the resource +\param blob blob object holding the data of the resource \param start_range start range of the data in the resource \param end_range start range of the data in the resource. If both start_range and end_range are 0, the data is the complete resource \param mime associated MIME type if any @@ -515,7 +522,7 @@ Adds a local entry in the cache \param download_time_ms indicates the download time of the associated resource, if known, 0 otherwise. \return a cache entry structure */ -const DownloadedCacheEntry gf_dm_add_cache_entry(GF_DownloadManager *dm, const char *szURL, u8 *data, u64 size, u64 start_range, u64 end_range, const char *mime, Bool clone_memory, u32 download_time_ms); +DownloadedCacheEntry gf_dm_add_cache_entry(GF_DownloadManager *dm, const char *szURL, GF_Blob *blob, u64 start_range, u64 end_range, const char *mime, Bool clone_memory, u32 download_time_ms); /*! Forces HTTP headers for a given cache entry diff --git a/include/gpac/events.h b/include/gpac/events.h index 93523ce..3bf16c7 100644 --- a/include/gpac/events.h +++ b/include/gpac/events.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2020 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Events management @@ -151,7 +151,7 @@ typedef struct Bool disable_vsync; - // resources must be resetup before next render step (this is mainly due to discard all openGL textures and cached objects) - inly used when sent from plugin to term + // resources must be resetup before next render step (this is mainly due to discard all OpenGL textures and cached objects) - inly used when sent from plugin to term Bool hw_reset; } GF_EventVideoSetup; @@ -304,7 +304,7 @@ typedef struct u8 type; /*the URL the auth request is for*/ const char *site_url; - /*user name (provided buffer can hold 50 bytes). It may already be formated, or an empty ("") string*/ + /*user name (provided buffer can hold 50 bytes). It may already be formatted, or an empty ("") string*/ char *user; /*password (provided buffer can hold 50 bytes)*/ char *password; diff --git a/include/gpac/evg.h b/include/gpac/evg.h index c1789a2..0cc2555 100644 --- a/include/gpac/evg.h +++ b/include/gpac/evg.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Embedded Vector Graphics engine @@ -132,7 +132,7 @@ typedef enum GF_RASTER_HIGH_SPEED, /*! raster should use fast mode and good quality if possible*/ GF_RASTER_MID, - /*! raster should use full antialiasing*/ + /*! raster should use full antialiasing - this is the default for all new surfaces*/ GF_RASTER_HIGH_QUALITY } GF_RasterQuality; @@ -154,6 +154,33 @@ void gf_evg_stencil_delete(GF_EVGStencil *stencil); */ GF_Err gf_evg_stencil_set_matrix(GF_EVGStencil *stencil, GF_Matrix2D *mat); +/*! gets stencil transformation matrix +\param stencil the target stencil +\param mat the 2D matrix to fetch +\return TRUE if resulting matrix is fetched, false otherwise (matrix is identity or does not apply to this stencil class) +*/ +Bool gf_evg_stencil_get_matrix(GF_EVGStencil * stencil, GF_Matrix2D *mat); + +/*! sets stencil transformation matrix auto mode. + +When auto matrix mode is activated, the stencil matrix only describes texture mapping transform in uv space (normalized UV coordinates, OpenGL like), +and final transformation to raster coordinates is done internally. +When auto matrix mode is not activated,, the stencil matrix must describe the complete transformation from uv space to raster coordinates (consequently, the matrix usually includes the final path transformation). + +Stencils are by default created in auto matrix mode. + +\param stencil the target stencil +\param auto_on If true, the surface current matrix will be added to the stencil matrix when drawing, otherwise the stencil matrix is in final surface coordinates +\return error if any +*/ +GF_Err gf_evg_stencil_set_auto_matrix(GF_EVGStencil * stencil, Bool auto_on); + +/*! sets stencil transformation matrix auto mode. +\param stencil the target stencil +\return true if auto mode is enabled, false otherwise +*/ +Bool gf_evg_stencil_get_auto_matrix(GF_EVGStencil * stencil); + /*! gets stencil type \param stencil the target stencil \return stencil type @@ -167,6 +194,12 @@ GF_StencilType gf_evg_stencil_type(GF_EVGStencil *stencil); */ GF_Err gf_evg_stencil_set_brush_color(GF_EVGStencil *stencil, GF_Color color); +/*! gets color for solid brush stencil +\param stencil the target stencil +\return the stencil color +*/ +GF_Color gf_evg_stencil_get_brush_color(GF_EVGStencil * stencil); + /*! sets gradient repeat mode for a gradient stencil \note this may be called before the gradient is setup \param stencil the target stencil @@ -219,7 +252,7 @@ GF_Err gf_evg_stencil_set_gradient_interpolation(GF_EVGStencil *stencil, Fixed * */ GF_Err gf_evg_stencil_push_gradient_interpolation(GF_EVGStencil *stencil, Fixed pos, GF_Color col); -/*! sets global alpha blending level for a texture or gradient stencil +/*! sets global alpha blending level for a stencil The alpha channel will be combined with the color matrix if any \warning do not use with solid brush stencil \param stencil the target stencil @@ -228,6 +261,12 @@ The alpha channel will be combined with the color matrix if any */ GF_Err gf_evg_stencil_set_alpha(GF_EVGStencil *stencil, u8 alpha); +/*! gets global alpha blending level of a stencil +\param stencil the target stencil +\return the alpha value between 0 (full transparency) and 255 (full opacityy) +*/ +u8 gf_evg_stencil_get_alpha(GF_EVGStencil *stencil); + /*! sets pixel data for a texture stencil \param stencil the target stencil \param pixels texture data starting from top row @@ -287,6 +326,20 @@ GF_Err gf_evg_stencil_set_texture_parametric(GF_EVGStencil *stencil, u32 width, */ GF_Err gf_evg_stencil_set_mapping(GF_EVGStencil *stencil, GF_TextureMapFlags map_mode); +/*! sets padding color in RGBA + If texture repeat is disabled and pad color is set, this color is used when outside of image, otherwise pixel is fetch from image border +\param stencil the target stencil +\param pad_color color to use , 0 disables color padding +\return error if any +*/ +GF_Err gf_evg_stencil_set_pad_color(GF_EVGStencil * stencil, GF_Color pad_color); + +/*! gets padding color in RGBA +\param stencil the target stencil +\return color used , 0 if error +*/ +u32 gf_evg_stencil_get_pad_color(GF_EVGStencil * stencil); + /*! sets filtering mode for a texture stencil \param stencil the target stencil \param filter_mode texture filtering mode to set @@ -295,14 +348,20 @@ GF_Err gf_evg_stencil_set_mapping(GF_EVGStencil *stencil, GF_TextureMapFlags map GF_Err gf_evg_stencil_set_filter(GF_EVGStencil *stencil, GF_TextureFilter filter_mode); /*! sets color matrix of a stencil -\warning ignored for solid brush stencil \param stencil the target stencil \param cmat the color matrix to use. If NULL, resets current color matrix \return error if any */ GF_Err gf_evg_stencil_set_color_matrix(GF_EVGStencil *stencil, GF_ColorMatrix *cmat); -/*! gets pixel at given position (still experimental) +/*! gets color matrix of a stencil +\param stencil the target stencil +\param cmat filled with current color matrix of stencil +\return error if any + */ +GF_Err gf_evg_stencil_get_color_matrix(GF_EVGStencil *stencil, GF_ColorMatrix *cmat); + +/*! gets pixel at given position in ARGB format \param stencil the target stencil \param x horizontal coord \param y vertical coord @@ -310,31 +369,47 @@ GF_Err gf_evg_stencil_set_color_matrix(GF_EVGStencil *stencil, GF_ColorMatrix *c */ u32 gf_evg_stencil_get_pixel(GF_EVGStencil *stencil, s32 x, s32 y); +/*! gets pixel at given position in AYUV format +\param stencil the target stencil +\param x horizontal coord +\param y vertical coord +\return pixel value + */ +u32 gf_evg_stencil_get_pixel_yuv(GF_EVGStencil *stencil, s32 x, s32 y); + +/*! gets pixel at given position in ARGB format for more than 8 bits textures +\param stencil the target stencil +\param x horizontal coord +\param y vertical coord +\return pixel value + */ +u64 gf_evg_stencil_get_pixel_wide(GF_EVGStencil *stencil, s32 x, s32 y); + +/*! gets pixel at given position in AYUV format for more than 8 bits textures +\param stencil the target stencil +\param x horizontal coord +\param y vertical coord +\return pixel value + */ +u64 gf_evg_stencil_get_pixel_yuv_wide(GF_EVGStencil *stencil, s32 x, s32 y); + /*! gets ARGB pixel at a given position The position is given as normalize coordinates (between 0.0 and 1.0), {0.0,0.0} is top-left, {1.0,1.0} is bottom-right \param stencil the target stencil \param x horizontal coord \param y vertical coord -\param r output r component -\param g output g component -\param b output b component -\param a output a component -\return error if any +\return output r, r, g, a components */ -GF_Err gf_evg_stencil_get_pixel_f(GF_EVGStencil *stencil, Float x, Float y, Float *r, Float *g, Float *b, Float *a); +GF_Vec4 gf_evg_stencil_get_pixel_f(GF_EVGStencil *stencil, Float x, Float y); /*! gets AYUV pixel at a given position The position is given as normalize coordinates (between 0.0 and 1.0), {0.0,0.0} is top-left, {1.0,1.0} is bottom-right \param stencil the target stencil \param x horizontal coord \param y vertical coord -\param Y output y component -\param U output u component -\param V output v component -\param A output a component -\return error if any +\return output y, u, v, a components */ -GF_Err gf_evg_stencil_get_pixel_yuv_f(GF_EVGStencil *stencil, Float x, Float y, Float *Y, Float *U, Float *V, Float *A); +GF_Vec4 gf_evg_stencil_get_pixel_yuv_f(GF_EVGStencil *stencil, Float x, Float y); /*! creates a canvas surface object \param center_coords if GF_TRUE, indicates mathematical-like coord system (0,0) at the center of the canvas, otherwise indicates computer-like coord system (0,0) top-left corner @@ -346,6 +421,12 @@ GF_EVGSurface *gf_evg_surface_new(Bool center_coords); */ void gf_evg_surface_delete(GF_EVGSurface *surf); +/*! enables threading on a canvas surface object (can only be called once per surface) +\param surf the target surface +\param nb_threads number of additional threads to use for rendering. -1 use all availables core +\return error if any, GF_BAD_PARAM if threading was already allocated, GF_IO_ERR if only one core available and nb_threads not assigned to a positive value*/ +GF_Err gf_evg_enable_threading(GF_EVGSurface *surf, s32 nb_threads); + /*! attaches a surface object to a texture stencil object \param surf the surface object \param sten the stencil object (shll be a texture stencil) @@ -372,6 +453,18 @@ GF_Err gf_evg_surface_attach_to_buffer(GF_EVGSurface *surf, u8 *pixels, u32 widt */ GF_Err gf_evg_surface_set_raster_level(GF_EVGSurface *surf, GF_RasterQuality level); +/*! gets rasterizer precision +\param surf the surface object +\return the raster quality level +*/ +GF_RasterQuality gf_evg_surface_get_raster_level(GF_EVGSurface *surf); + +/*! Force next path fill to use antialias, reset at each \ref gf_evg_surface_set_path +\param surf the surface object +\return error if any +*/ +GF_Err gf_evg_surface_force_aa(GF_EVGSurface *surf); + /*! sets the given matrix as the current transformations for all drawn paths \note this is only used for 2D rasterizer, and ignored in 3D mode \param surf the surface object @@ -382,6 +475,13 @@ GF_Err gf_evg_surface_set_matrix(GF_EVGSurface *surf, GF_Matrix2D *mat); /*! sets the given matrix as the current transformations for all drawn paths. The matrix shall be a projection matrix (ortho or perspective) with normalized coordinates in [-1,1]. It may also contain a modelview part. + +Perspective correct mapping is supported for textures and gradients: +- the bottom-left corner of the path bounds is texture coordinate 0,0 +- the top-right corner of the path bounds is texture coordinate 1,1 + +\warning When 3D matrices are used, filling a path shall be done with a stencil in auto matrix mode. + \note this is only used for 2D rasterizer, and ignored in 3D mode \param surf the surface object \param mat the matrix to set; if NULL, resets the current transformation @@ -397,6 +497,12 @@ When a clipper is enabled, nothing is drawn outside of the clipper. The clipper */ GF_Err gf_evg_surface_set_clipper(GF_EVGSurface *surf, GF_IRect *rc); +/*! checks if clipper is active +\param surf the surface object +\return GF_TRUE if clipper is active, GF_FALSE otherwise +*/ +Bool gf_evg_surface_use_clipper(GF_EVGSurface *surf); + /*! sets the given path as the current one for drawing \warning This will internally copy the path after transformation with the current transfom. Changing the surface transform will have no effect unless calling this function again. The clipper and stencil mode may be changed at will @@ -413,11 +519,63 @@ If the stencil is a solid brush and its alpha value is 0, the surface is cleared \note this can be called several times with the same current path \note this is only used for 2D rasterizer, and ignored in 3D mode \param surf the surface object -\param stencil the stencil to use to fill a path +\param stencil the stencil to use to fill a path, if NULL uses 2D shader if setup \return error if any */ GF_Err gf_evg_surface_fill(GF_EVGSurface *surf, GF_EVGStencil *stencil); + +/*! Operands for multitexture operations*/ +typedef enum { + /*! no multitexture*/ + GF_EVG_OPERAND_NONE = 0, + /*! mix texture 1 and texure 2 using coefficient in first param, returning tx1*coef + tx2*(1-coef) but forcing alpha to full opacity*/ + GF_EVG_OPERAND_MIX, + /*! mix texture 1 and texure 2 using coefficient in first param, returning tx1*coef + tx2*(1-coef), including alpha channel */ + GF_EVG_OPERAND_MIX_ALPHA, + /*! replace alpha of texture 1 with alpha of texture 2 + if first param is 0 or not set, use alpha channel from texture 2 + if first param is 1, use red channel from texture 2 + if first param is 2, use green/Cb/U channel from texture 2 + if first param is 3, use blue/Cr/V channel from texture 2 + */ + GF_EVG_OPERAND_REPLACE_ALPHA, + /*! replace alpha of texture 1 with (1-alpha) of texture 2 + if first param is 0 or not set, use alpha channel from texture 2 + if first param is 1, use red/Y channel from texture 2 + if first param is 2, use green/Cb/U channel from texture 2 + if first param is 3, use blue/Cr/V channel from texture 2 + */ + GF_EVG_OPERAND_REPLACE_ONE_MINUS_ALPHA, + /*! mix texture 1 and texure 2 using alpha coef of texture 3 but forcing alpha to full opacity + if first param is 0 or not set, use alpha channel from texture 3 + if first param is 1, use red channel from texture 3 + if first param is 2, use green/Cb/U channel from texture 3 + if first param is 3, use blue/Cr/V channel from texture 3 + */ + GF_EVG_OPERAND_MIX_DYN, + /*! mix texture 1 and texure 2 using alpha coef of texture 3, including alpha channel. + if first param is 0 or not set, use alpha channel from texture 3 + if first param is 1, use red channel from texture 3 + if first param is 2, use green/Cb/U channel from texture 3 + if first param is 3, use blue/Cr/V channel from texture 3 + */ + GF_EVG_OPERAND_MIX_DYN_ALPHA, + /*! use texture 1 for odd fill and texture 2 for even fill*/ + GF_EVG_OPERAND_ODD_FILL, +} GF_EVGMultiTextureMode; + +/*! draw (filling) the current path on a surface using a compinaison of stencils and current clipper if any. +\param surf the surface object +\param operand stencil combine effect +\param sten1 the first stencil to use, if NULL assumes shader and ignores operand +\param sten2 the second stencil to use, may be NULL depending on operand +\param sten3 the third stencil to use, may be NULL depending on operand +\param params the parameters to control the operand +\return error if any +*/ +GF_Err gf_evg_surface_multi_fill(GF_EVGSurface *surf, GF_EVGMultiTextureMode operand, GF_EVGStencil *sten1, GF_EVGStencil *sten2, GF_EVGStencil *sten3, Float params[4]); + /*! clears given pixel rectangle on a surface with the given color \warning this ignores any clipper set on the surface \param surf the surface object @@ -510,10 +668,11 @@ typedef enum GF_EVG_QUAD_STRIP, } GF_EVGPrimitiveType; -/*! creates a new 3D software rasterizer - \note use \ref gf_evg_surface_delete for destruction - \return NULL if error*/ -GF_EVGSurface *gf_evg_surface3d_new(); +/*! enables 3D software rasterizer for surface + \param surf the target 3D surface + \return error if any*/ +GF_Err gf_evg_surface_enable_3d(GF_EVGSurface *surf); + /*! sets projection matrix \note this is only used for 3D rasterizer, and fails 2D mode \param surf the target 3D surface @@ -609,10 +768,12 @@ typedef enum { /*! fragment is invalid (discarded or error) */ GF_EVG_FRAG_INVALID = 0, - /*! fragment is RGB */ + /*! fragment is RGB float*/ GF_EVG_FRAG_RGB, + GF_EVG_FRAG_RGB_PACK, /*! fragment is YUV */ GF_EVG_FRAG_YUV, + GF_EVG_FRAG_YUV_PACK, } GF_EVGFragmentType; /*! Parameters for the fragment callback */ @@ -624,36 +785,56 @@ typedef struct Float screen_y; /*! screen z in NDC - input param*/ Float screen_z; - /*! depth - input and output param*/ + /*! depth - input and output param - 3D shaders only*/ Float depth; - /*! primitive index in the current \ref gf_evg_surface_draw_array call, 0 being the first primitive - input param*/ + /*! primitive index in the current \ref gf_evg_surface_draw_array call, 0 being the first primitive - input param - 3D shaders only*/ u32 prim_index; - /*! index of first vertex in the current primitive - input param*/ + /*! index of first vertex in the current primitive - input param - 3D shaders only*/ u32 idx1; - /*! index of second vertex in the current primitive (for lines or triangles/quads) - input param*/ + /*! index of second vertex in the current primitive (for lines or triangles/quads) - input param - 3D shaders only*/ u32 idx2; - /*! index of third vertex in the current primitive (for triangles/quads) - input param*/ + /*! index of third vertex in the current primitive (for triangles/quads) - input param - 3D shaders only*/ u32 idx3; - /*! primitive type - input param*/ + /*! primitive type - input param - 3D shaders only*/ GF_EVGPrimitiveType ptype; /*! fragment color, must be written if fragment is not discarded - output value*/ GF_Vec4 color; + /*! fragment color in pack 32 bit ARGB/AYUV*/ + u32 color_pack; + /*! fragment color in pack 64 bit ARGB/AYUV*/ + u64 color_pack_wide; /*! fragment valid state - output value*/ GF_EVGFragmentType frag_valid; /*vars for lerp*/ - /*perspective correct interpolation is done according to openGL eq 14.9 + /*perspective correct interpolation is done according to OpenGL eq 14.9 f = (a*fa/wa + b*fb/wb + c*fc/wc) / (a/w_a + b/w_b + c/w_c) */ - /*! perspective corrected barycentric, eg bc1/q1, bc2/q2, bc3/q3 - these are constant throughout the fragment*/ + /*! perspective corrected barycentric, eg bc1/q1, bc2/q2, bc3/q3 - 3D shaders only*/ Float pbc1, pbc2, pbc3; - /*! perspective divider + /*! perspective divider - 3D shaders only \note this is also 1/W of the fragment, eg opengl gl_fragCoord.w */ Float persp_denum; + /* private for shader, valid between \ref gf_evg_fragment_shader_init (init, cleanup) calls */ + void *shader_udta; + + /*! horizontal texture coordinate, 0 is left of image - 2D shaders only */ + u32 tx_x; + /*! vertical texture coordinate, 0 is top of image - 2D shaders only */ + u32 tx_y; + /*! texture width - 2D shaders only */ + u32 tx_width; + /*! texture height - 2D shaders only */ + u32 tx_height; + + /*! coverage value between 0 and 0xFF - 2D shaders only */ + u8 coverage; + /*! odd / even flag for path drawn with zero/non-zero fill rule - 2D shaders only */ + u8 odd_flag; + } GF_EVGFragmentParam; @@ -680,14 +861,26 @@ typedef struct \param fragp fragment paramters \return GF_TRUE if success; GF_FALSE if error*/ typedef Bool (*gf_evg_fragment_shader)(void *udta, GF_EVGFragmentParam *fragp); -/*! assigns fragment shader to the rasterizer -\note this is only used for 3D rasterizer, and fails 2D mode + +/*! callback type for fragment shader init, called once before each primitive - may be NULL + \param udta opaque data passed back to caller + \param fragp fragment paramters + \param th_id index of thread context + \param is_cleanup if TRUE indicates and of primitive rendering, otherwise begin + \return GF_TRUE if success; GF_FALSE if error*/ +typedef Bool (*gf_evg_fragment_shader_init)(void *udta, GF_EVGFragmentParam *fragp, u32 th_id, Bool is_cleanup); + + +/*! assigns fragment shader to the rasterizer. +\warning If multithread is enabled, the shader must be thread-safe +This can be used for 3D and 2D modes. In 2D mode, texture coordinates are derived from path bounds \param surf the target 3D surface \param shader the fragment shader callback to use +\param shader_init the fragment shader init callback to use \param shader_udta opaque data to pass to the callback function \return error if any */ -GF_Err gf_evg_surface_set_fragment_shader(GF_EVGSurface *surf, gf_evg_fragment_shader shader, void *shader_udta); +GF_Err gf_evg_surface_set_fragment_shader(GF_EVGSurface *surf, gf_evg_fragment_shader shader, gf_evg_fragment_shader_init shader_init, void *shader_udta); /*! callback type for vertex shader \param udta opaque data passed back to caller @@ -856,6 +1049,40 @@ u64 gf_evg_argb_to_ayuv_wide(GF_EVGSurface *surf, u64 col); */ u64 gf_evg_ayuv_to_argb_wide(GF_EVGSurface *surf, u64 col); +/*! global alpha mask values */ +typedef enum +{ + /*! global alpha mask not used */ + GF_EVGMASK_NONE = 0, + /*! subsequent draw operations will target the global alpha mask */ + GF_EVGMASK_DRAW, + /*! subsequent draw operations will target the global alpha mask, but alpha mask is not cleared */ + GF_EVGMASK_DRAW_NO_CLEAR, + /*! subsequent draw operations will be filtered with the global alpha mask */ + GF_EVGMASK_USE, + /*! subsequent draw operations will be filtered with 1 minus the global alpha mask */ + GF_EVGMASK_USE_INV, + /*! combine draw and use: the mask is set to 0xFF, each pixel drawn turns the mask value to 0 */ + GF_EVGMASK_RECORD, +} GF_EVGMaskMode; + +/*! sets global alpha mask mode + +The global alpha mask is an 8-bit alpha channel the size of the surface. Any resize operation on the surface will reset the alpha mask +Typcial usage for the alpha mask is to setup the surface, use GF_EVGMASK_DRAW to draw your mask then GF_EVGMASK_USE to apply the mask on your draw calls + +Whenever the mask mode is changed to GF_EVGMASK_DRAW, the alpha masked is cleared +\param surf the target surface +\param mask_mode the current mask mode +\return error if any +*/ +GF_Err gf_evg_surface_set_mask_mode(GF_EVGSurface *surf, GF_EVGMaskMode mask_mode); + +/*! gets global alpha mask mode +\param surf the target surface +\return the current mask mode +*/ +GF_EVGMaskMode gf_evg_surface_get_mask_mode(GF_EVGSurface *surf); /*! @} */ diff --git a/include/gpac/filters.h b/include/gpac/filters.h index ff66847..85fd869 100644 --- a/include/gpac/filters.h +++ b/include/gpac/filters.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2017-2020 + * Copyright (c) Telecom ParisTech 2017-2022 * All rights reserved * * This file is part of GPAC / filters sub-project @@ -55,52 +55,53 @@ This file contains all exported functions for filter management of the GPAC fram API Documentation of the filter managment system of GPAC. The filter management in GPAC is built using the following core objects: -- \ref GF_FilterSession in charge of - loading filters from register, managing argument parsing and co - resolving filter graphs to handle PID connection(s) - tracking data packets and properties exchanged on PIDs - scheduling tasks between filters - ensuring thread-safe filter state: a filter may be called from any thread in the session (unless explicitely asked not to), but only by a single thread at any time. +- \ref GF_FilterSession in charge of: + - loading filters from register, managing argument parsing and co + - resolving filter graphs to handle PID connection(s) + - tracking data packets and properties exchanged on PIDs + - scheduling tasks between filters + - ensuring thread-safe filter state: a filter may be called from any thread in the session (unless explicitly asked not to), but only by a single thread at any time. - \ref __gf_filter_register static structure describing possible entry points of the filter, possible arguments and input output PID capabilities. Each filter share the same API (register definition) regardless of its type: source/sink, mux/demux, encode/decode, raw media processing, encoded media processing, ... - \ref GF_Filter is an instance of the filter register. A filter implementation typical tasks are: - accepting new input PIDs (for non source filters) - defining new output PIDs (for non sink filters), applying any property change due to filter processing - consuming packets on the input PIDs - dispatching packets on the output PIDs + - accepting new input PIDs (for non source filters) + - defining new output PIDs (for non sink filters), applying any property change due to filter processing + - consuming packets on the input PIDs + - dispatching packets on the output PIDs - \ref GF_FilterPid handling the connections between two filters. - PID natively supports fan-out (one filter PID connecting to multiple destinations). - A PID is in charge of dispatching packets to possible destinations and storing PID properties in sync with dispatched packets. - Whenever PID properties change, the next packet sent on that PID is associated with the new state, and the destination filter(s) will be called + - PID natively supports fan-out (one filter PID connecting to multiple destinations). + - A PID is in charge of dispatching packets to possible destinations and storing PID properties in sync with dispatched packets. + - Whenever PID properties change, the next packet sent on that PID is associated with the new state, and the destination filter(s) will be called upon fetching the new packet. This is the one of the two reentrant code of a filter, the other one being the \ref GF_FEVT_INFO_UPDATE event. - When blocking mode is not disabled at the session filter, a PID is also in charge of managing its occupancy through either a number of packets or the + - When blocking mode is not disabled at the session filter, a PID is also in charge of managing its occupancy through either a number of packets or the cumulated duration of the packets it is holding. - Whenever a PID holds too much data, it enters a blocking state. A filter with ALL its output PIDs in a blocked state won't be scheduled + - Whenever a PID holds too much data, it enters a blocking state. A filter with ALL its output PIDs in a blocked state won't be scheduled for processing. This is a semi-blocking design, which imply that if a filter has one of its PIDs in a non blocking state, it will be scheduled for processing. If a PID has multiple destinations and one of the destination consumes faster than the other one, the filter is currently not blocking (this might change in the near future). - A PID is in charge of managing the packet references across filters, by performing memory management of allocated data packets + - A PID is in charge of managing the packet references across filters, by performing memory management of allocated data packets (avoid alloc/free at each packet but rather recycle the memory) and tracking shared packets references. - \ref GF_FilterPacket holding data to dispatch from a filter on a given PID. - Packets are always associated to a single output PID, ie it is not possible for a filter to send one packet to multiple PIDs, the data has to be cloned. - Packets have default attributes such as timestamps, size, random access status, start/end frame, etc, as well as optional properties. - All packets are reference counted. - A packet can hold allocated block on the output PID, a pointer to some filter internal data, a data reference to a single input packet, or a frame interface object used for accessing data or OpenGL textures of the emitting filter. + - Packets are always associated to a single output PID, ie it is not possible for a filter to send one packet to multiple PIDs, the data has to be cloned. + - Packets have default attributes such as timestamps, size, random access status, start/end frame, etc, as well as optional properties. + - All packets are reference counted. + - A packet can hold allocated block on the output PID, a pointer to some filter internal data, a data reference to a single input packet, or a frame interface object used for accessing data or OpenGL textures of the emitting filter. Packets holding data references rather than copy are notified back to their creators upon destruction. - \ref __gf_prop_val holding various properties for a PID or a packet - Properties can be copied/merged between input and output PIDs, or input and output packets. These properties are reference counted. - Two kinds of properties are defined, built-in ones which use a 32 bit identifier (usually a four character code), and user properties identified by a string. - PID properties are defined by the filter creating the PID. They can be overridden/added after being set by the filter by specifying fragment properties + - Properties can be copied/merged between input and output PIDs, or input and output packets. These properties are reference counted. + - Two kinds of properties are defined, built-in ones which use a 32 bit identifier (usually a four character code), and user properties identified by a string. + - PID properties are defined by the filter creating the PID. They can be overridden/added after being set by the filter by specifying fragment properties in the filter arguments. For example \code fin=src=myfile.foo:#FEXT=bar \endcode will override the file extension property (FEXT) foo to bar AFTER the PID is being defined. - \ref __gf_filter_event used to pass various events (play/stop/buffer requirements/...) up and down the filter chain. This part of the API will likely change in the future, being merged with the global GF_Event of GPAC. GPAC comes with a set of built-in filters in libgpac. It is also possible to define external filters in dynamic libraries. GPAC will look for such libraries - in folders listed in GPAC config file section core, key mod-dirs. The files SHALL be named gf_* and export a function called RegisterFilter + in default module folder and folders listed in GPAC config file section core, key mod-dirs. The files SHALL be named gf_* and export a function called RegisterFilter with the following prototype: + \param fsess is set to NULL unless meta filters are listed, in which case the filter register should list all possible meta filters it supports \return a GF_FilterRegister structure used for instantiating the filter. -const GF_FilterRegister *RegisterFilter(GF_FilterSession *fsess); +\code const GF_FilterRegister *RegisterFilter(GF_FilterSession *fsess);\endcode */ @@ -203,42 +204,45 @@ typedef enum GF_FS_SCHEDULER_DIRECT } GF_FilterSchedulerType; -/*! Flag set to indicate meta filters should be loaded. A meta filter is a filter providing various subfilters. -The subfilters are usually not exposed as filters, only the parent one is. -When set, all subfilters are exposed. This should only be set when inspecting filters help*/ +/*! Flag set to indicate meta filters should be loaded. A meta filter is a filter providing various sub-filters. +The sub-filters are usually not exposed as filters, only the parent one is. +When set, all sub-filters are exposed. This should only be set when inspecting filters help*/ #define GF_FS_FLAG_LOAD_META 1<<1 -/*! Flag set to disable the blocking mode of the filter session. The default is a semi-blocking mode, cf \ref gf_filter_pid_would_block*/ -#define GF_FS_FLAG_NO_BLOCKING 1<<2 +/*! Flag set to run session in non-blocking mode. Each call to \ref gf_fs_run will return as soon as there are no more pending tasks on the main thread */ +#define GF_FS_FLAG_NON_BLOCKING 1<<2 /*! Flag set to disable internal caching of filter graph connections. If disabled, the graph will be recomputed at each link resolution (less memory occupancy but slower)*/ #define GF_FS_FLAG_NO_GRAPH_CACHE 1<<3 -/*! Flag set to disable main thread. Such sessions shall be run using \ref gf_fs_run_step*/ -#define GF_FS_FLAG_NO_MAIN_THREAD 1<<4 /*! Flag set to disable session regulation (no sleep)*/ -#define GF_FS_FLAG_NO_REGULATION 1<<5 +#define GF_FS_FLAG_NO_REGULATION 1<<4 /*! Flag set to disable data probe*/ -#define GF_FS_FLAG_NO_PROBE (1<<6) +#define GF_FS_FLAG_NO_PROBE (1<<5) /*! Flag set to disable source reassignment (e.g. switching from fin to ffdmx) in PID resolution*/ -#define GF_FS_FLAG_NO_REASSIGN (1<<7) +#define GF_FS_FLAG_NO_REASSIGN (1<<6) /*! Flag set to print enabled/disabled edges for debug of PID resolution*/ -#define GF_FS_FLAG_PRINT_CONNECTIONS (1<<8) +#define GF_FS_FLAG_PRINT_CONNECTIONS (1<<7) /*! Flag set to disable argument checking*/ -#define GF_FS_FLAG_NO_ARG_CHECK (1<<9) +#define GF_FS_FLAG_NO_ARG_CHECK (1<<8) /*! Disables reservoir for packets and properties, uses much less memory but much more alloc/free*/ -#define GF_FS_FLAG_NO_RESERVOIR (1<<10) -/*! Throws an error if any PID in the filter graph cannot be linked. The default behaviour is tu run the session even when some PIDs are not connected*/ -#define GF_FS_FLAG_FULL_LINK (1<<11) +#define GF_FS_FLAG_NO_RESERVOIR (1<<9) +/*! Throws an error if any PID in the filter graph cannot be linked. The default behavior is to run the session even when some PIDs are not connected*/ +#define GF_FS_FLAG_FULL_LINK (1<<10) +/*! Flag set to disable implicit linking + By default the session runs in implicit linking when no link directives are set on any filter: linking aborts after the first successfull pid if destination is not a sink, or links only to sinks otherwise. + \note This implies that the order in which filters are added to the session matters +*/ +#define GF_FS_FLAG_NO_IMPLICIT (1<<11) /*! Creates a new filter session. This will also load all available filter registers not blacklisted. \param nb_threads number of extra threads to allocate. A negative value means all core used by session (eg nb_cores-1 extra threads) \param type scheduler type \param flags set of above flags for the session. Modes set by flags cannot be changed at runtime -\param blacklist string containing comma-separated names of filters to disable +\param blacklist string containing comma-separated names of filters to disable. If first character is '-', this describes a whitelist, i.e. only filters listed in this string will be allowed \return the created filter session */ GF_FilterSession *gf_fs_new(s32 nb_threads, GF_FilterSchedulerType type, u32 flags, const char *blacklist); /*! Creates a new filter session, loading parameters from gpac config. This will also load all available filter registers not blacklisted. -\param flags set of flags for the session. Only \ref GF_FS_FLAG_LOAD_META and \ref GF_FS_FLAG_NO_MAIN_THREAD are used, other flags +\param flags set of flags for the session. Only \ref GF_FS_FLAG_LOAD_META, \ref GF_FS_FLAG_NON_BLOCKING , \ref GF_FS_FLAG_NO_GRAPH_CACHE and \ref GF_FS_FLAG_PRINT_CONNECTIONS are used, other flags are set from config file or command line \return the created filter session */ GF_FilterSession *gf_fs_new_defaults(u32 flags); @@ -248,7 +252,7 @@ GF_FilterSession *gf_fs_new_defaults(u32 flags); */ void gf_fs_del(GF_FilterSession *session); /*! Loads a given filter by its register name. Filter are created using their register name, with options appended as a list of colon-separated Name=Value pairs. -Value can be omitted for booleans, defaulting to true (eg :noedit). Using '!' before the name negates the result (eg :!moof_first). +Value can be omitted for boolean, defaulting to true (eg :noedit). Using '!' before the name negates the result (eg :!moof_first). Name can be omitted for enumerations (eg :disp=pbo is equivalent to :pbo), provided that filter developers pay attention to not reuse enum names in one filter. \param session filter session @@ -266,6 +270,10 @@ GF_Filter *gf_fs_load_filter(GF_FilterSession *session, const char *name, GF_Err Bool gf_fs_filter_exists(GF_FilterSession *session, const char *name); /*! Runs the session + +If the session is non-blocking ( created with \ref GF_FS_FLAG_NON_BLOCKING), process all tasks of oldest scheduled filter, process any pending PID connections and returns. +Otherwise (session is blocking), runs until session is over or aborted. + \param session filter session \return error if any, or GF_EOS. The last errors can be retrieved using \ref gf_fs_get_last_connect_error and \ref gf_fs_get_last_process_error */ @@ -310,12 +318,6 @@ GF_Err gf_fs_set_max_sleep_time(GF_FilterSession *session, u32 max_sleep); */ u32 gf_fs_get_max_resolution_chain_length(GF_FilterSession *session); -/*! Runs session in non blocking mode: process all tasks of oldest scheduled filter, process any pending PID connections and returns. -This can only be used if the flag \ref GF_FS_FLAG_NO_MAIN_THREAD was specified at session creation time -\param session filter session -*/ -void gf_fs_run_step(GF_FilterSession *session); - /*! Stops the session, waiting for all additional threads to complete \param session filter session \return error if any @@ -352,7 +354,7 @@ GF_Filter *gf_fs_load_source(GF_FilterSession *session, const char *url, const c /*! Loads a destination filter from a URL and arguments \param session filter session -\param url URL of the source to load. Can ba a local file name, a full path (/.., \\...) or a full URL with scheme (eg http://, tcp://) +\param url URL of the source to load. Can be a local file name, a full path (/.., \\...) or a full URL with scheme (eg http://, tcp://) \param args arguments for the filter, see \ref gf_fs_load_filter \param parent_url parent URL of the source, or NULL if none \param err if not NULL, is set to error code if any @@ -386,32 +388,50 @@ void gf_fs_remove_filter_register(GF_FilterSession *session, GF_FilterRegister * /*! Posts a user task to the session \param session filter session -\param task_execute the callback function for the task. The callback can return GF_TRUE to reschedule the task, in which case the task will be rescheduled -immediately or after reschedule_ms. +\param task_execute the callback function for the task. The callback can return: + - GF_FALSE to cancel the task + - GF_TRUE to reschedule the task, in which case the task will be rescheduled immediately or after reschedule_ms. \param udta_callback callback user data passed back to the task_execute function \param log_name log name of the task. If NULL, default is "user_task" \return the error code if any */ GF_Err gf_fs_post_user_task(GF_FilterSession *session, Bool (*task_execute) (GF_FilterSession *fsess, void *callback, u32 *reschedule_ms), void *udta_callback, const char *log_name); +/*! Session flush types*/ +typedef enum +{ + /*! Do not flush session: everything is discarded, potentially breaking output files*/ + GF_FS_FLUSH_NONE=0, + /*! Flush all pending data before closing sessions: sources will be forced into end of stream and all emitted packets will be processed*/ + GF_FS_FLUSH_ALL, + /*! Stop session (resetting buffers) and flush pipeline*/ + GF_FS_FLUSH_FAST +} GF_FSFlushType; + /*! Aborts the session. This can be called within a callback task to stop the session. Do NOT use \ref gf_fs_stop from within a user task callback, this will deadlock the session \param session filter session -\param do_flush if set to true, sources will be forced into end of stream and all emitted packets will be processed. Otherwise everything is discarded, potentially breaking output files +\param flush_type flush method to use \return the error code if any */ -GF_Err gf_fs_abort(GF_FilterSession *session, Bool do_flush); +GF_Err gf_fs_abort(GF_FilterSession *session, GF_FSFlushType flush_type); /*! Checks if the session is processing its last task. This can be called within a callback task to check if this is the last task, in order to avoid rescheduling the task \param session filter session \return GF_TRUE if no more task, GF_FALSE otherwise */ Bool gf_fs_is_last_task(GF_FilterSession *session); +/*! Checks if the session is in its final flush state (shutdown) +\param session filter session +\return GF_TRUE if no session is aborting, GF_FALSE otherwise +*/ +Bool gf_fs_in_final_flush(GF_FilterSession *session); + /*! Checks if a given MIME type is supported as input \param session filter session \param mime MIME type to query \return GF_TRUE if MIME is supported */ -Bool gf_fs_mime_supported(GF_FilterSession *session, const char *mime); +Bool gf_fs_is_supported_mime(GF_FilterSession *session, const char *mime); /*! Sets UI callback event @@ -431,6 +451,24 @@ void gf_fs_print_stats(GF_FilterSession *session); */ void gf_fs_print_connections(GF_FilterSession *session); +/*! Prints the list of filters not connected using \code LOG_APP@LOG_WARNING \endcode +\param session filter session +*/ +void gf_fs_print_non_connected(GF_FilterSession *session); + +/*! Prints the list of filters not connected using \code LOG_APP@LOG_WARNING \endcode +\param session filter session +\param ignore_sinks if set, do not warn if some sinks are not connected (mostly used for playback cases) +*/ +void gf_fs_print_non_connected_ex(GF_FilterSession *session, Bool ignore_sinks); + +/*! Prints the list of arguments specified but not used by the filter session using \code LOG_APP@LOG_WARNING \endcode + \note This is simply a wrapper to \ref gf_fs_enum_unmapped_options +\param session filter session +\param ignore_args ignore unused arguments if present in this comma-seperated list - may be NULL +*/ +void gf_fs_print_unused_args(GF_FilterSession *session, const char *ignore_args); + /*! Prints all possible connections between filter registries to logs using \code LOG_APP@LOG_INFO \endcode \param session filter session \param filter_name if not null, only prints input connection for this filter register @@ -456,7 +494,8 @@ Bool gf_fs_check_filter_register_cap(const GF_FilterRegister *filter_reg, u32 in */ void gf_fs_enable_reporting(GF_FilterSession *session, Bool reporting_on); -/*! Locks global session mutex - mostly used to query filter reports and avoids concurrent destruction of a filter +/*! Locks global session mutex - mostly used to query filter reports and avoids concurrent destruction of a filter. + When adding a filter in an already running session, the session must be locked if set_source is to be used. \param session filter session \param do_lock if GF_TRUE, session is locked, otherwise session is unlocked */ @@ -468,11 +507,18 @@ void gf_fs_lock_filters(GF_FilterSession *session, Bool do_lock); */ u32 gf_fs_get_filters_count(GF_FilterSession *session); +/*! Gets a filter by its current index in the session +\param session filter session +\param idx index in the filter session +\return filter, or NULL if none found +*/ +GF_Filter *gf_fs_get_filter(GF_FilterSession *session, u32 idx); + /*! Type of filter*/ typedef enum { - /*! Unknown filter type*/ - GF_FS_STATS_FILTER_UNKNOWN, + /*! Generic filter type accepting input(s) and producing output(s)*/ + GF_FS_STATS_FILTER_GENERIC, /*! raw input (file, socket, pipe) filter type*/ GF_FS_STATS_FILTER_RAWIN, /*! demultiplexer filter type*/ @@ -540,7 +586,7 @@ typedef struct u64 nb_out_pck; /*!set to GF_TRUE if filter has seen end of stream*/ Bool in_eos; - /*!set to GF_TRUE if filter has seen end of stream*/ + /*!set to the filter class type*/ GF_FSFilterType type; /*!set to streamtype of output PID if single output, GF_STREAM_UNKNOWN otherwise*/ u32 stream_type; @@ -548,7 +594,7 @@ typedef struct u32 codecid; /*! timestamp and timescale of last packet emitted on output pids*/ GF_Fraction64 last_ts_sent; - /*! timestamp and timescale of last packet droped on input pids*/ + /*! timestamp and timescale of last packet dropped on input pids*/ GF_Fraction64 last_ts_drop; } GF_FilterStats; @@ -565,7 +611,7 @@ GF_Err gf_fs_get_filter_stats(GF_FilterSession *session, u32 idx, GF_FilterStats \param session filter session \param idx index of argument to query, 0 being first argument; this value is automatically incremented \param argname set to argument name -\param argtype set to argument type: 0 was a filter param (eg:arg=val), 1 was a global arg (eg --arg=val) and 2 was a global meta arg (eg -+arg=val) +\param argtype set to argument type: 0 was a filter param (eg :arg=val), 1 was a global arg (eg --arg=val) and 2 was a global meta arg (eg -+arg=val) \return GF_TRUE if success, GF_FALSE if nothing more to enumerate */ Bool gf_fs_enum_unmapped_options(GF_FilterSession *session, u32 *idx, char **argname, u32 *argtype); @@ -599,9 +645,70 @@ void gf_fs_send_update(GF_FilterSession *session, const char *fid, GF_Filter *fi */ GF_Err gf_fs_load_script(GF_FilterSession *session, const char *jsfile); +/*! get max download rate allowed by download manager +\param session filter session +\return max rate in bps +*/ +u32 gf_fs_get_http_max_rate(GF_FilterSession *session); + +/*! set max download rate allowed by download manager +\param session filter session +\param rate max rate in bps +\return error if any +*/ +GF_Err gf_fs_set_http_max_rate(GF_FilterSession *session, u32 rate); + + +/*! get current download rate of download manager, all active resources together +\param session filter session +\return current rate in bps +*/ +u32 gf_fs_get_http_rate(GF_FilterSession *session); + +/*! check if a URL is likely to be supported +\param session filter session +\param url the URL to test +\param parent_url the parent URL +\return GF_TRUE if a filter for such a source could be loaded +*/ +Bool gf_fs_is_supported_source(GF_FilterSession *session, const char *url, const char *parent_url); + +/*! callback functions for external monitoring of filter creation or destruction +\param udta user data passed back to callback +\param filter created or destroyed filter +\param is_destroy if GF_TRUE, the filter is being destroyed, otherwise it is being created + */ +typedef void (*gf_fs_on_filter_creation)(void *udta, GF_Filter *filter, Bool is_destroy); + +/*! assign callbacks for filter creation and destruction monitoring +\param session filter session +\param on_create_destroy filter creation/destruction callback, may be NULL +\param udta user data for callbacks, may be NULL +\param force_sync execute tasks involving filter creation/setup and user tasks on main thread +\return error if any + */ +GF_Err gf_fs_set_filter_creation_callback(GF_FilterSession *session, gf_fs_on_filter_creation on_create_destroy, void *udta, Bool force_sync); + +/*! returns RT user data passed in \ref gf_fs_set_filter_creation_callback +\param session filter session +\return udta user data, NULL if error or none + */ +void *gf_fs_get_rt_udta(GF_FilterSession *session); + +/*! Fires an event on filter +\param session filter session +\param filter target filter - if NULL, event will be executed on all filters. Otherwise, the event will be executed directly if its type is \ref GF_FEVT_USER, and fired otherwise +\param evt event to fire +\param upstream if true, send event toward sinks, otherwise towards sources +\return GF_TRUE if event was sent, GF_FALSE otherwise + */ +Bool gf_fs_fire_event(GF_FilterSession *session, GF_Filter *filter, GF_FilterEvent *evt, Bool upstream); + /*! @} */ + + /*! \addtogroup fs_props Filter Properties \ingroup filters_grp @@ -612,70 +719,95 @@ Documents the property object used for PID and packets. */ /*! Property types*/ + +//DO NOT MODIFY WITHOUT APPLYNG SIMILAR CHANGE TO share/python/libgpac.py +//DO NOT CHANGE A VALUE ASSIGNMENT WITHOUT CHANGING GF_GSF_VERSION + typedef enum { /*! not allowed*/ - GF_PROP_FORBIDEN=0, + GF_PROP_FORBIDEN = 0, /*! signed 32 bit integer*/ - GF_PROP_SINT, + GF_PROP_SINT = 1, /*! unsigned 32 bit integer*/ - GF_PROP_UINT, + GF_PROP_UINT = 2, /*! signed 64 bit integer*/ - GF_PROP_LSINT, + GF_PROP_LSINT = 3, /*! unsigned 64 bit integer*/ - GF_PROP_LUINT, + GF_PROP_LUINT = 4, /*! boolean*/ - GF_PROP_BOOL, + GF_PROP_BOOL = 5, /*! 32 bit / 32 bit fraction*/ - GF_PROP_FRACTION, + GF_PROP_FRACTION = 6, /*! 64 bit / 64 bit fraction*/ - GF_PROP_FRACTION64, + GF_PROP_FRACTION64 = 7, /*! float (Fixed) number*/ - GF_PROP_FLOAT, + GF_PROP_FLOAT = 8, /*! double number*/ - GF_PROP_DOUBLE, + GF_PROP_DOUBLE = 9, /*! 2D signed integer vector*/ - GF_PROP_VEC2I, + GF_PROP_VEC2I = 10, /*! 2D double number vector*/ - GF_PROP_VEC2, + GF_PROP_VEC2 = 11, /*! 3D signed integer vector*/ - GF_PROP_VEC3I, - /*! 3D double number vector*/ - GF_PROP_VEC3, + GF_PROP_VEC3I = 12, /*! 4D signed integer vector*/ - GF_PROP_VEC4I, - /*! 4D double number vector*/ - GF_PROP_VEC4, - /*! Video Pixel format*/ - GF_PROP_PIXFMT, - /*! Audio PCM format*/ - GF_PROP_PCMFMT, + GF_PROP_VEC4I = 13, /*! string property, memory is duplicated when setting the property and managed internally*/ - GF_PROP_STRING, + GF_PROP_STRING = 14, /*! string property, memory is NOT duplicated when setting the property but is then managed (and free) internally. - Only used when setting a property, the type then defaults to GF_PROP_STRING*/ - GF_PROP_STRING_NO_COPY, + Only used when setting a property, the type then defaults to GF_PROP_STRING + DO NOT USE the associate string field upon return from setting the property, it might have been destroyed*/ + GF_PROP_STRING_NO_COPY= 15, /*! data property, memory is duplicated when setting the property and managed internally*/ - GF_PROP_DATA, + GF_PROP_DATA = 16, /*! const string property, memory is NOT duplicated when setting the property, stays user-managed*/ - GF_PROP_NAME, + GF_PROP_NAME = 17, /*! data property, memory is NOT duplicated when setting the property but is then managed (and free) internally. - Only used when setting a property, the type then defaults to GF_PROP_DATA*/ - GF_PROP_DATA_NO_COPY, + Only used when setting a property, the type then defaults to GF_PROP_DATA + DO NOT USE the associate data field upon return from setting the property, it might have been destroyed*/ + GF_PROP_DATA_NO_COPY= 18, /*! const data property, memory is NOT duplicated when setting the property, stays user-managed*/ - GF_PROP_CONST_DATA, + GF_PROP_CONST_DATA = 19, /*! user-managed pointer*/ - GF_PROP_POINTER, - /*! string list, memory is NOT duplicated when setting the property, the GF_List * of - the passed property is directly assigned to the new property and will be and managed internally (freed by the filter session)*/ - GF_PROP_STRING_LIST, + GF_PROP_POINTER = 20, + /*! string list, memory is NOT duplicated when setting the property, the passed array is directly assigned to the new property and will be and managed internally (freed by the filter session) + DO NOT USE the associate string array field upon return from setting the property, it might have been destroyed*/ + GF_PROP_STRING_LIST = 21, /*! unsigned 32 bit integer list, memory is ALWAYS duplicated when setting the property*/ - GF_PROP_UINT_LIST, + GF_PROP_UINT_LIST = 22, + /*! signed 32 bit integer list, memory is ALWAYS duplicated when setting the property*/ + GF_PROP_SINT_LIST = 23, + /*! 2D signed integer vector list, memory is ALWAYS duplicated when setting the property*/ + GF_PROP_VEC2I_LIST = 24, + /*! 4CC on unsigned 32 bit integer*/ + GF_PROP_4CC = 25, + /*! 4CC list on unsigned 32 bit integer, memory is ALWAYS duplicated when setting the property*/ + GF_PROP_4CC_LIST = 26, + + /*! last non-enum property*/ + GF_PROP_LAST_NON_ENUM, + + /*! All constants are defined after this - constants are stored as u32*/ + GF_PROP_FIRST_ENUM = 40, //GSF will code prop type using vlen, try to keep all values between 1 and 127 to only use 1 byte + /*! Video Pixel format*/ + GF_PROP_PIXFMT = GF_PROP_FIRST_ENUM, + /*! Audio PCM format*/ + GF_PROP_PCMFMT = GF_PROP_FIRST_ENUM+1, + /*! CICP Color Primaries*/ + GF_PROP_CICP_COL_PRIM = GF_PROP_FIRST_ENUM+2, + /*! CICP Color Transfer Characteristics*/ + GF_PROP_CICP_COL_TFC = GF_PROP_FIRST_ENUM+3, + /*! CICP Color Matrix*/ + GF_PROP_CICP_COL_MX = GF_PROP_FIRST_ENUM+4, /*! not allowed*/ - GF_PROP_LAST_DEFINED, + GF_PROP_LAST_DEFINED } GF_PropType; +/*! GSF version (coded on 8 bits in gsf format) */ +#define GF_GSF_VERSION 2 + /*! Data property*/ typedef struct { @@ -685,15 +817,6 @@ typedef struct u32 size; } GF_PropData; -/*! List of unsigned int property*/ -typedef struct -{ - /*! array of unsigned integers */ - u32 *vals; - /*! number of items in array */ - u32 nb_items; -} GF_PropUIntList; - /*! 2D signed integer vector property*/ typedef struct { @@ -703,6 +826,7 @@ typedef struct s32 y; } GF_PropVec2i; + /*! 2D double number vector property*/ typedef struct { @@ -723,17 +847,6 @@ typedef struct s32 z; } GF_PropVec3i; -/*! 3D double number vector property*/ -typedef struct -{ - /*! x coord */ - Double x; - /*! y coord */ - Double y; - /*! z coord */ - Double z; -} GF_PropVec3; - /*! 4D signed integer vector property*/ typedef struct { @@ -747,18 +860,42 @@ typedef struct s32 w; } GF_PropVec4i; -/*! 4D double number vector property*/ + +/*! List of strings property - do not change field order !*/ typedef struct { - /*! x coord */ - Double x; - /*! y coord */ - Double y; - /*! z coord */ - Double z; - /*! w coord */ - Double w; -} GF_PropVec4; + /*! array of unsigned integers */ + char **vals; + /*! number of items in array */ + u32 nb_items; +} GF_PropStringList; + +/*! List of unsigned int property - do not change field order !*/ +typedef struct +{ + /*! array of unsigned integers */ + u32 *vals; + /*! number of items in array */ + u32 nb_items; +} GF_PropUIntList; + +/*! List of signed int property - do not change field order !*/ +typedef struct +{ + /*! array of signed integers */ + s32 *vals; + /*! number of items in array */ + u32 nb_items; +} GF_PropIntList; + +/*! List of unsigned int property*/ +typedef struct +{ + /*! array of vec2i */ + GF_PropVec2i *vals; + /*! number of items in array */ + u32 nb_items; +} GF_PropVec2iList; /*! Property value used by PIDs and packets*/ struct __gf_prop_val @@ -791,12 +928,8 @@ struct __gf_prop_val GF_PropVec2 vec2; /*! 3D signed integer vector value of property */ GF_PropVec3i vec3i; - /*! 3D double vector value of property */ - GF_PropVec3 vec3; /*! 4D signed integer vector value of property */ GF_PropVec4i vec4i; - /*! 4D double vector value of property */ - GF_PropVec4 vec4; /*! data value of property. For non const data type, the memory is freed by filter session. Otherwise caller is responsible to free it at end of filter/session*/ GF_PropData data; @@ -805,9 +938,13 @@ struct __gf_prop_val /*! pointer value of property */ void *ptr; /*! string list value of property - memory is handled by filter session (always copy)*/ - GF_List *string_list; + GF_PropStringList string_list; /*! unsigned integer list value of property - memory is handled by filter session (always copy)*/ GF_PropUIntList uint_list; + /*! signed integer list value of property - memory is handled by filter session (always copy)*/ + GF_PropIntList sint_list; + /*! vec2i list value of property - memory is handled by filter session (always copy)*/ + GF_PropVec2iList v2i_list; } value; }; @@ -842,6 +979,7 @@ enum GF_PROP_PID_PLAYBACK_MODE = GF_4CC('P','B','K','M'), GF_PROP_PID_SCALABLE = GF_4CC('S','C','A','L'), GF_PROP_PID_TILE_BASE = GF_4CC('S','A','B','T'), + GF_PROP_PID_TILE_ID = GF_4CC('P','T','I','D'), GF_PROP_PID_LANGUAGE = GF_4CC('L','A','N','G'), GF_PROP_PID_SERVICE_NAME = GF_4CC('S','N','A','M'), GF_PROP_PID_SERVICE_PROVIDER = GF_4CC('S','P','R','O'), @@ -855,6 +993,7 @@ enum GF_PROP_PID_UNFRAMED_FULL_AU = GF_4CC('P','F','R','F'), GF_PROP_PID_DURATION = GF_4CC('P','D','U','R'), GF_PROP_PID_NB_FRAMES = GF_4CC('N','F','R','M'), + GF_PROP_PID_FRAME_OFFSET = GF_4CC('F','R','M','O'), GF_PROP_PID_FRAME_SIZE = GF_4CC('C','F','R','S'), GF_PROP_PID_TIMESHIFT_DEPTH = GF_4CC('P','T','S','D'), GF_PROP_PID_TIMESHIFT_TIME = GF_4CC('P','T','S','T'), @@ -874,6 +1013,7 @@ enum GF_PROP_PID_UNFRAMED_LATM = GF_4CC('L','A','T','M'), GF_PROP_PID_DELAY = GF_4CC('M','D','L','Y'), GF_PROP_PID_CTS_SHIFT = GF_4CC('M','D','T','S'), + GF_PROP_PID_NO_PRIMING = GF_4CC('A','S','K','P'), GF_PROP_PID_WIDTH = GF_4CC('W','I','D','T'), GF_PROP_PID_HEIGHT = GF_4CC('H','E','I','G'), GF_PROP_PID_PIXFMT = GF_4CC('P','F','M','T'), @@ -898,9 +1038,17 @@ enum GF_PROP_PID_SRD_REF = GF_4CC('S','R','D','R'), GF_PROP_PID_SRD_MAP = GF_4CC('S','R','D','M'), GF_PROP_PID_ALPHA = GF_4CC('V','A','L','P'), + GF_PROP_PID_MIRROR = GF_4CC('V','M','I','R'), + GF_PROP_PID_ROTATE = GF_4CC('V','R','O','T'), + GF_PROP_PID_CLAP_W = GF_4CC('C','L','P','W'), + GF_PROP_PID_CLAP_H = GF_4CC('C','L','P','H'), + GF_PROP_PID_CLAP_X = GF_4CC('C','L','P','X'), + GF_PROP_PID_CLAP_Y = GF_4CC('C','L','P','Y'), + GF_PROP_PID_NUM_VIEWS = GF_4CC('P','N','B','V'), GF_PROP_PID_DOLBY_VISION = GF_4CC('D','O','V','I'), GF_PROP_PID_BITRATE = GF_4CC('R','A','T','E'), GF_PROP_PID_MAXRATE = GF_4CC('M','R','A','T'), + GF_PROP_PID_TARGET_RATE = GF_4CC('T','B','R','T'), GF_PROP_PID_DBSIZE = GF_4CC('D','B','S','Z'), GF_PROP_PID_MEDIA_DATA_SIZE = GF_4CC('M','D','S','Z'), GF_PROP_PID_CAN_DATAREF = GF_4CC('D','R','E','F'), @@ -950,9 +1098,7 @@ enum GF_PROP_PID_OMA_PREVIEW_RANGE = GF_4CC('O','D','P','R'), GF_PROP_PID_CENC_PSSH = GF_4CC('P','S','S','H'), GF_PROP_PCK_CENC_SAI = GF_4CC('S','A','I','S'), - GF_PROP_PID_KID = GF_4CC('S','K','I','D'), - GF_PROP_PID_CENC_IV_SIZE = GF_4CC('S','A','I','V'), - GF_PROP_PID_CENC_IV_CONST = GF_4CC('C','B','I','V'), + GF_PROP_PID_CENC_KEY_INFO = GF_4CC('C','B','I','V'), GF_PROP_PID_CENC_PATTERN = GF_4CC('C','P','T','R'), GF_PROP_PID_CENC_STORE = GF_4CC('C','S','T','R'), GF_PROP_PID_CENC_STSD_MODE = GF_4CC('C','S','T','M'), @@ -964,6 +1110,8 @@ enum GF_PROP_PCK_IDXFILENAME = GF_4CC('I','N','A','M'), GF_PROP_PCK_FILESUF = GF_4CC('F','S','U','F'), GF_PROP_PCK_EODS = GF_4CC('E','O','D','S'), + GF_PROP_PCK_CUE_START = GF_4CC('P','C','U','S'), + GF_PROP_PID_MAX_FRAME_SIZE = GF_4CC('M','F','R','S'), GF_PROP_PID_AVG_FRAME_SIZE = GF_4CC('A','F','R','S'), GF_PROP_PID_MAX_TS_DELTA = GF_4CC('M','T','S','D'), @@ -976,6 +1124,9 @@ enum GF_PROP_PID_ISOM_HANDLER = GF_4CC('I','H','D','L'), GF_PROP_PID_ISOM_TRACK_FLAGS = GF_4CC('I','T','K','F'), GF_PROP_PID_ISOM_TRACK_MATRIX = GF_4CC('I','T','K','M'), + GF_PROP_PID_ISOM_ALT_GROUP = GF_4CC('I','A','L','G'), + GF_PROP_PID_ISOM_FORCE_NEGCTTS = GF_4CC('I','F','N','C'), + GF_PROP_PID_DISABLED = GF_4CC('I','T','K','D'), GF_PROP_PID_PERIOD_ID = GF_4CC('P','E','I','D'), GF_PROP_PID_PERIOD_START = GF_4CC('P','E','S','T'), GF_PROP_PID_PERIOD_DUR = GF_4CC('P','E','D','U'), @@ -999,6 +1150,8 @@ enum GF_PROP_PID_CLAMP_DUR = GF_4CC('D','C','M','D'), GF_PROP_PID_HLS_PLAYLIST = GF_4CC('H','L','V','P'), GF_PROP_PID_HLS_GROUPID = GF_4CC('H','L','G','I'), + GF_PROP_PID_HLS_EXT_MASTER = GF_4CC('H','L','M','X'), + GF_PROP_PID_HLS_EXT_VARIANT = GF_4CC('H','L','V','X'), GF_PROP_PID_DASH_CUE = GF_4CC('D','C','U','E'), GF_PROP_PID_DASH_SEGMENTS = GF_4CC('D','C','N','S'), GF_PROP_PID_CODEC = GF_4CC('C','O','D','S'), @@ -1007,24 +1160,86 @@ enum GF_PROP_PID_PRIMARY_ITEM = GF_4CC('P','I','T','M'), + GF_PROP_PID_PLAY_BUFFER = GF_4CC('P','B','P','L'), + GF_PROP_PID_MAX_BUFFER = GF_4CC('P','B','M','X'), + GF_PROP_PID_RE_BUFFER = GF_4CC('P','B','R','E'), + GF_PROP_PID_VIEW_IDX = GF_4CC('V','I','D','X'), + GF_PROP_PID_COLR_PRIMARIES = GF_4CC('C','P','R','M'), GF_PROP_PID_COLR_TRANSFER = GF_4CC('C','T','R','C'), GF_PROP_PID_COLR_MX = GF_4CC('C','M','X','C'), GF_PROP_PID_COLR_RANGE = GF_4CC('C','F','R','A'), + GF_PROP_PID_COLR_CHROMAFMT = GF_4CC('C','F','M','T'), GF_PROP_PID_COLR_CHROMALOC = GF_4CC('C','L','O','C'), - GF_PROP_PID_COLR_SPACE = GF_4CC('C','S','P','C'), + GF_PROP_PID_CONTENT_LIGHT_LEVEL = GF_4CC('C','L','L','I'), + GF_PROP_PID_MASTER_DISPLAY_COLOUR = GF_4CC('M','D','C','V'), GF_PROP_PID_SRC_MAGIC = GF_4CC('P','S','M','G'), GF_PROP_PID_MUX_INDEX = GF_4CC('T','I','D','X'), GF_PROP_NO_TS_LOOP = GF_4CC('N','T','S','L'), + GF_PROP_PID_MHA_COMPATIBLE_PROFILES = GF_4CC('M','H','C','P'), GF_PROP_PCK_FRAG_START = GF_4CC('P','F','R','B'), GF_PROP_PCK_FRAG_RANGE = GF_4CC('P','F','R','R'), GF_PROP_PCK_SIDX_RANGE = GF_4CC('P','F','S','R'), GF_PROP_PCK_MOOF_TEMPLATE = GF_4CC('M','F','T','P'), + GF_PROP_PCK_INIT = GF_4CC('P','C','K','I'), GF_PROP_PID_RAWGRAB = GF_4CC('P','G','R','B'), GF_PROP_PID_KEEP_AFTER_EOS = GF_4CC('P','K','A','E'), GF_PROP_PID_COVER_ART = GF_4CC('P','C','O','V'), + GF_PROP_PID_ORIG_FRAG_URL = GF_4CC('O','F','R','A'), + + GF_PROP_PID_ROUTE_IP = GF_4CC('R','S','I','P'), + GF_PROP_PID_ROUTE_PORT = GF_4CC('R','S','P','N'), + GF_PROP_PID_ROUTE_NAME = GF_4CC('R','S','F','N'), + GF_PROP_PID_ROUTE_CAROUSEL = GF_4CC('R','S','C','R'), + GF_PROP_PID_ROUTE_SENDTIME = GF_4CC('R','S','S','T'), + + GF_PROP_PID_STEREO_TYPE = GF_4CC('P','S','T','T'), + GF_PROP_PID_PROJECTION_TYPE = GF_4CC('P','P','J','T'), + GF_PROP_PID_VR_POSE = GF_4CC('P','P','O','S'), + GF_PROP_PID_CUBE_MAP_PAD = GF_4CC('P','C','M','P'), + GF_PROP_PID_EQR_CLAMP = GF_4CC('P','E','Q','C'), + + GF_PROP_PID_SCENE_NODE = GF_4CC('P','S','N','D'), + GF_PROP_PID_ORIG_CRYPT_SCHEME = GF_4CC('P','O','C','S'), + GF_PROP_PID_TIMESHIFT_SEGS = GF_4CC('P','T','S','N'), + + + //internal for HLS playlist reference, gives a unique ID identifying media mux, and indicated in packets carrying child playlists + GF_PROP_PCK_HLS_REF = GF_4CC('H','P','L','R'), + //internal for HLS low latency + GF_PROP_PID_LLHLS = GF_4CC('H','L','S','L'), + GF_PROP_PCK_HLS_FRAG_NUM = GF_4CC('H','L','S','N'), + //we also use this property on PID to signal sample-accurate seek info is present + GF_PROP_PCK_SKIP_BEGIN = GF_4CC('P','C','K','S'), + GF_PROP_PCK_SKIP_PRES = GF_4CC('P','C','K','D'), + //internal for DASH forward mode + GF_PROP_PID_DASH_FWD = GF_4CC('D','F','W','D'), + GF_PROP_PCK_DASH_MANIFEST = GF_4CC('D','M','P','D'), + GF_PROP_PCK_HLS_VARIANT = GF_4CC('D','H','L','V'), + GF_PROP_PID_DASH_PERIOD_START = GF_4CC('D','P','S','T'), + GF_PROP_PCK_HLS_VARIANT_NAME = GF_4CC('D','H','L','N'), + GF_PROP_PID_HLS_KMS = GF_4CC('H','L','S','K'), + GF_PROP_PID_HLS_IV = GF_4CC('H','L','S','I'), //internal property indicating pointer to associated GF_DownloadSession - GF_PROP_PID_DOWNLOAD_SESSION = GF_4CC('G','H','T','T') + GF_PROP_PID_DOWNLOAD_SESSION = GF_4CC('G','H','T','T'), + + //PID has temi information + GF_PROP_PID_HAS_TEMI = GF_4CC('P','T','E','M'), + //PID has no init segment associated (file foward mode of dasher) + GF_PROP_PID_NO_INIT = GF_4CC('P','N','I','N'), + + GF_PROP_PID_IS_MANIFEST = GF_4CC('P','H','S','M'), + + GF_PROP_PCK_XPS_MASK = GF_4CC('P','X','P','M'), + GF_PROP_PCK_END_RANGE = GF_4CC('P','C','E','R'), + + /*! Internal property used for FFMPEG codec ID + + Property can be: + - pointer to codec context: only for ffdmx with old ffmpeg versions) + - uint: AVCODEC_ID_* ffdmx with newer versions or ffenc output + */ + GF_PROP_PID_FFMPEG_CODEC_ID = GF_4CC('F','C','I','D'), }; /*! Block patching requirements for FILE pids, as signaled by GF_PROP_PID_DISABLE_PROGRESSIVE @@ -1050,12 +1265,19 @@ const char *gf_props_4cc_get_name(u32 prop_4cc); u32 gf_props_4cc_get_type(u32 prop_4cc); /*! Checks if two properties are equal -\param p1 first property to compare -\param p2 second property to compare +\param p1 first property to compare - shall not be NULL +\param p2 second property to compare - shall not be NULL \return GF_TRUE if properties are equal, GF_FALSE otherwise */ Bool gf_props_equal(const GF_PropertyValue *p1, const GF_PropertyValue *p2); +/*! Same as \ref gf_props_equal but do not match string with value "*" to string with value different from "*" +\param p1 first property to compare - shall not be NULL +\param p2 second property to compare - shall not be NULL +\return GF_TRUE if properties are equal, GF_FALSE otherwise +*/ +Bool gf_props_equal_strict(const GF_PropertyValue *p1, const GF_PropertyValue *p2); + /*! Gets the readable name for a property type \param type property type \return readable name @@ -1074,13 +1296,45 @@ const char *gf_props_get_type_desc(GF_PropType type); */ GF_PropType gf_props_parse_type(const char *name); +/*! Check if a property type is an enum type +\param type property type +\return GF_TRUE if constant, GF_FALSE otherwise +*/ +Bool gf_props_type_is_enum(GF_PropType type); + +/*! Parse a enum type property string +\param type property type +\param value value to parse +\return value, 0xFFFFFFFF if error +*/ +u32 gf_props_parse_enum(u32 type, const char *value); + +/*! Get the name of a constant type property value +\param type property type +\param value value of constant +\return value, 0xFFFFFFFF if error +*/ +const char *gf_props_enum_name(u32 type, u32 value); + +/*! Get the possible names of an enum type property +\param type property type +\return comma-seperated list of possible values +*/ +const char *gf_props_enum_all_names(u32 type); + +/*! Get the base type of a property type. Properties with same base type can be safely type-casted +\param type property type +\return base property type +*/ +u32 gf_props_get_base_type(u32 type); + /*! Parses a property value from string \param type property type to parse \param name property name to parse (for logs) \param value string containing the value to parse \param enum_values string containig enum_values, or NULL. enum_values are used for unsigned int properties, take the form "a|b|c" and resolve to 0|1|2. -\param list_sep_char value of the list seperator character to use +\param list_sep_char value of the list separator character to use \return the parsed property value */ GF_PropertyValue gf_props_parse_value(u32 type, const char *name, const char *value, const char *enum_values, char list_sep_char); @@ -1088,23 +1342,34 @@ GF_PropertyValue gf_props_parse_value(u32 type, const char *name, const char *va /*! Maximum string size to use when dumping a property*/ #define GF_PROP_DUMP_ARG_SIZE 100 +/*! Data property dump mode*/ +typedef enum +{ + /*! do not dump data*/ + GF_PROP_DUMP_DATA_NONE=0, + /*! dump data if less than 40 bytes, otherwise dump ptr address and CRC*/ + GF_PROP_DUMP_DATA_INFO, + /*! dump data to parsable property, as ADDRESS+'@'+POINTER*/ + GF_PROP_DUMP_DATA_PTR, +} GF_PropDumDataMode; + /*! Dumps a property value to string \param att property value \param dump buffer holding the resulting value for types requiring string conversions (integers, ...) -\param dump_data if set data will be dumped in hexadecimal. Otherwise, data buffer is not dumped +\param dump_data_mode data dump mode \param min_max_enum optional, gives the min/max or enum string when the property is a filter argument \return string */ -const char *gf_props_dump_val(const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], Bool dump_data, const char *min_max_enum); +const char *gf_props_dump_val(const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], GF_PropDumDataMode dump_data_mode, const char *min_max_enum); /*! Dumps a property value to string, resolving any built-in types (pix formats, codec id, ...) \param p4cc property 4CC \param att property value \param dump buffer holding the resulting value for types requiring string conversions (integers, ...) -\param dump_data if set data will be dumped in hexadecimal. Otherwise, data buffer is not dumped +\param dump_data_mode data dump mode \return string */ -const char *gf_props_dump(u32 p4cc, const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], Bool dump_data); +const char *gf_props_dump(u32 p4cc, const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], GF_PropDumDataMode dump_data_mode); /*! Resets a property value, freeing allocated data or strings depending on the property type \param prop property 4CC @@ -1148,10 +1413,15 @@ u32 gf_props_get_id(const char *name); */ u8 gf_props_4cc_get_flags(u32 prop_4cc); + /*! Helper macro to set signed int property */ #define PROP_SINT(_val) (GF_PropertyValue){.type=GF_PROP_SINT, .value.sint = _val} /*! Helper macro to set unsigned int property */ #define PROP_UINT(_val) (GF_PropertyValue){.type=GF_PROP_UINT, .value.uint = _val} +/*! Helper macro to set an enum property */ +#define PROP_ENUM(_val, _type) (GF_PropertyValue){.type=_type, .value.uint = _val} +/*! Helper macro to set 4CC unsigned int property */ +#define PROP_4CC(_val) (GF_PropertyValue){.type=GF_PROP_4CC, .value.uint = _val} /*! Helper macro to set long signed int property */ #define PROP_LONGSINT(_val) (GF_PropertyValue){.type=GF_PROP_LSINT, .value.longsint = _val} /*! Helper macro to set long unsigned int property */ @@ -1188,14 +1458,12 @@ u8 gf_props_4cc_get_flags(u32 prop_4cc); #define PROP_VEC2(_val) (GF_PropertyValue){.type=GF_PROP_VEC2, .value.vec2 = _val} /*! Helper macro to set 2D integer vector property */ #define PROP_VEC2I(_val) (GF_PropertyValue){.type=GF_PROP_VEC2I, .value.vec2i = _val} -/*! Helper macro to set 2D integer vector property from intergers*/ +/*! Helper macro to set 2D integer vector property from integers*/ #define PROP_VEC2I_INT(_x, _y) (GF_PropertyValue){.type=GF_PROP_VEC2I, .value.vec2i.x = _x, .value.vec2i.y = _y} -/*! Helper macro to set 3D float vector property */ -#define PROP_VEC3(_val) (GF_PropertyValue){.type=GF_PROP_VEC3, .value.vec3 = _val} /*! Helper macro to set 3D integer vector property */ #define PROP_VEC3I(_val) (GF_PropertyValue){.type=GF_PROP_VEC3I, .value.vec3i = _val} -/*! Helper macro to set 4D float vector property */ -#define PROP_VEC4(_val) (GF_PropertyValue){.type=GF_PROP_VEC4, .value.vec4 = _val} +/*! Helper macro to set 3D integer vector property from integers*/ +#define PROP_VEC3I_INT(_x, _y, _z) (GF_PropertyValue){.type=GF_PROP_VEC3I, .value.vec3i.x = _x, .value.vec3i.y = _y, .value.vec3i.z = _z} /*! Helper macro to set 4D integer vector property */ #define PROP_VEC4I(_val) (GF_PropertyValue){.type=GF_PROP_VEC4I, .value.vec4i = _val} /*! Helper macro to set 4D integer vector property from integers */ @@ -1275,8 +1543,16 @@ typedef enum GF_FEVT_USER, /*! PLAY hint event, used to signal if block dispatch is needed or not for the source*/ GF_FEVT_PLAY_HINT, - /*! file delete event, sent upstream by dahser to notify file deletion*/ + /*! file delete event, sent upstream by dasher to notify file deletion, downstream by flist to ask for file deletion. The associated file processing (reading, writing) MUST be done when firing this event*/ GF_FEVT_FILE_DELETE, + + /*! DASH fragment (cmaf chunk) size info, sent down from muxers to manifest generators*/ + GF_FEVT_FRAGMENT_SIZE, + + /*! Encoder hints*/ + GF_FEVT_ENCODE_HINTS, + /*! NTP source clock send by other services (eg from TS to dash using TEMI) */ + GF_FEVT_NTP_REF, } GF_FEventType; /*! type: the type of the event*/ @@ -1296,36 +1572,42 @@ typedef struct FILTER_EVENT_BASE } GF_FEVT_Base; -/*! Event structure for GF_FEVT_PLAY, GF_FEVT_SET_SPEED*/ +/*! Event structure for GF_FEVT_PLAY, GF_FEVT_SET_SPEED, GF_FEVT_PLAY_HINT, GF_FEVT_STOP*/ typedef struct { FILTER_EVENT_BASE - /*! params for : ranges in sec - if range is <0, it means end of file (eg [2, -1] with speed>0 means 2 +oo) */ - Double start_range, end_range; - /*! params for GF_NET_CHAN_PLAY and GF_NET_CHAN_SPEED*/ + /*!GF_FEVT_PLAY only, play range in sec - if range is <0, it means end of file (eg [2, -1] with speed>0 means 2 +oo) */ + Double start_range; + /*!GF_FEVT_PLAY only, send range in sec - if range is less than start, ignored*/ + Double end_range; + /*! params for GF_FEVT_PLAY and GF_FEVT_SET_SPEED*/ Double speed; - /*! indicates playback should start from given packet number - used by dasher when reloading sources*/ + /*! GF_FEVT_PLAY only, indicates playback should start from given packet number - used by dasher when reloading sources*/ u32 from_pck; - /*! set when PLAY event is sent upstream to audio out, indicates HW buffer reset*/ + /*! GF_FEVT_PLAY only, set when PLAY event is sent upstream to audio out, indicates HW buffer reset*/ u8 hw_buffer_reset; - /*! params for GF_FEVT_PLAY only: indicates this is the first PLAY on an element inserted from bcast*/ + /*! GF_FEVT_PLAY only: indicates this is the first PLAY on an element inserted from bcast*/ u8 initial_broadcast_play; - /*! params for GF_NET_CHAN_PLAY only + /*! params for GF_FEVT_PLAY only 0: range is in media time 1: range is in timesatmps 2: range is in media time but timestamps should not be shifted (hybrid dash only for now) */ u8 timestamp_based; - /*! indicates the consumer only cares for the full file, not packets*/ + /*! GF_FEVT_PLAY only, indicates the consumer only cares for the full file, not packets*/ u8 full_file_only; - /*! indicates any current download should be aborted*/ + /*! + for GF_FEVT_PLAY: indicates any current download should be aborted + for GF_FEVT_PLAY_HINT if upstream event: indicates a HAS segment switch has occured (used by tileagg to flush reassembly buffers) + for GF_FEVT_STOP: indicates the source filter has already received stop/play events and cancel event just before source + */ u8 forced_dash_segment_switch; - /*! indicates non ref frames should be drawn for faster processing*/ + /*! GF_FEVT_PLAY only, indicates non ref frames should be drawn for faster processing*/ u8 drop_non_ref; - /*! indicates that a demuxer must not forward this event as a source seek because seek has already been done + /*! GF_FEVT_PLAY only, indicates that a demuxer must not forward this event as a source seek because seek has already been done (typically this play request is a segment play and byte range access within the file has already been performed by DASH client)*/ u8 no_byterange_forward; } GF_FEVT_Play; @@ -1339,13 +1621,13 @@ typedef struct u64 start_offset; /*! end offset in source*/ u64 end_offset; - /*! new path to switch to*/ + /*! GF_FEVT_SOURCE_SWITCH only, new path to switch to*/ const char *source_switch; - /*! indicates previous source was a DASH init segment and should be kept in memory cache*/ - u8 previous_is_init_segment; - /*! ignore cache expiration directive for HTTP*/ + /*!GF_FEVT_SOURCE_SWITCH only, indicates source is a DASH init segment and should be kept in memory cache*/ + u8 is_init_segment; + /*!GF_FEVT_SOURCE_SWITCH only, ignore cache expiration directive for HTTP*/ u8 skip_cache_expiration; - /*! hint block size for source, might not be respected*/ + /*! GF_FEVT_SOURCE_SEEK only, hint block size for source, might not be respected*/ u32 hint_block_size; } GF_FEVT_SourceSeek; @@ -1355,8 +1637,6 @@ typedef struct FILTER_EVENT_BASE /*! URL of segment this info is for, or NULL if single file*/ const char *seg_url; - /*! global sidx is signaled using is_init=1 and range in idx range*/ - Bool is_init; /*! media start range in segment file*/ u64 media_range_start; /*! media end range in segment file*/ @@ -1365,8 +1645,28 @@ typedef struct u64 idx_range_start; /*! index end range in segment file*/ u64 idx_range_end; + /*! global sidx is signaled using is_init=1 and range in idx range*/ + u8 is_init; + /*! if global sidx, indicates if this is is an insertion and that byte range previously received should be shifted*/ + u8 is_shift; } GF_FEVT_SegmentSize; +/*! Event structure for GF_FEVT_FRAGMENT_SIZE*/ +typedef struct +{ + FILTER_EVENT_BASE + /*! set to TRUE if last fragment in segment*/ + Bool is_last; + /*! media start range in segment file*/ + u64 offset; + /*! media end range in segment file*/ + u64 size; + /*! media duration of fragment*/ + GF_Fraction64 duration; + /*! fragment contains an IDR*/ + Bool independent; +} GF_FEVT_FragmentSize; + /*! Event structure for GF_FEVT_ATTACH_SCENE and GF_FEVT_RESET_SCENE For GF_FEVT_RESET_SCENE, THIS IS A DIRECT FILTER CALL NOT THREADSAFE, filters processing this event SHALL run on the main thread*/ typedef struct @@ -1374,6 +1674,8 @@ typedef struct FILTER_EVENT_BASE /*! Pointer to a GF_ObjectManager structure for this PID*/ void *object_manager; + /*! Pointer to a GF_Node structure for this PID if node decoder pid*/ + void *node; } GF_FEVT_AttachScene; /*! Event structure for GF_FEVT_QUALITY_SWITCH*/ @@ -1405,7 +1707,7 @@ typedef struct typedef struct { FILTER_EVENT_BASE - /*! URL to delete*/ + /*! URL to delete, or "__gpac_self__" when asking source filter to delete file */ const char *url; } GF_FEVT_FileDelete; @@ -1417,7 +1719,7 @@ typedef struct u32 min_x, max_x, min_y, max_y; /*! if set, only min_x, min_y are used and indicate the gaze direction in pixels in the visual with/height frame (0,0) being top-left*/ Bool is_gaze; -} GF_FEVT_VisibililityHint; +} GF_FEVT_VisibilityHint; /*! Event structure for GF_FEVT_BUFFER_REQ*/ @@ -1427,18 +1729,42 @@ typedef struct /*! indicates the max buffer to set on PID - the buffer is only activated on PIDs connected to decoders*/ u32 max_buffer_us; /*! indicates the max playout buffer to set on PID (buffer level triggering playback) - Note: this is not used internally by the blocking mechanisms, but may be needed by other filters to take decisions + \note This is not used internally by the blocking mechanisms, but may be needed by other filters to take decisions */ u32 max_playout_us; /*! indicates the min playout buffer to set on PID (buffer level triggering rebuffering) - Note: this is not used internally by the blocking mechanisms, but may be needed by other filters to take decisions + \note This is not used internally by the blocking mechanisms, but may be needed by other filters to take decisions */ u32 min_playout_us; /*! if set, only the PID target of the event will have the buffer req set; otherwise, the buffer requirement event is passed down the chain until a raw media PID is found or a decoder is found. Used for muxers*/ Bool pid_only; } GF_FEVT_BufferRequirement; -/*! Event object*/ + +/*! Event structure for GF_FEVT_ENCODE_HINT*/ +typedef struct +{ + FILTER_EVENT_BASE + + /*! duration of intra (IDR, closed GOP) as expected by the dasher */ + GF_Fraction intra_period; + +} GF_FEVT_EncodeHints; + + +/*! Event structure for GF_FEVT_NTP_REF*/ +typedef struct +{ + FILTER_EVENT_BASE + + /*! 64 bit NTP timestamp */ + u64 ntp; + +} GF_FEVT_NTPRef; + +/*! +Filter Event object + */ union __gf_filter_event { GF_FEVT_Base base; @@ -1447,10 +1773,13 @@ union __gf_filter_event GF_FEVT_AttachScene attach_scene; GF_FEVT_Event user_event; GF_FEVT_QualitySwitch quality_switch; - GF_FEVT_VisibililityHint visibility_hint; + GF_FEVT_VisibilityHint visibility_hint; GF_FEVT_BufferRequirement buffer_req; GF_FEVT_SegmentSize seg_size; + GF_FEVT_FragmentSize frag_size; GF_FEVT_FileDelete file_del; + GF_FEVT_EncodeHints encode_hints; + GF_FEVT_NTPRef ntp; }; /*! Gets readable name for event type @@ -1471,7 +1800,7 @@ const char *gf_filter_event_name(GF_FEventType type); The API for filters documents declaration of filters, their creation and functions available to interact with the filter session. The gf_filter_* functions shall only be called from within a given filter, this filter being the target of the function. This is not checked at runtime. -Calling these functions on other filters will result in unpredictable behaviour, very likely crashes in multi-threading conditions. +Calling these functions on other filters will result in unpredictable behavior, very likely crashes in multi-threading conditions. A filter is instanciated through a filter register. The register holds entry points to a filter, arguments of a filter (basically property values) and capabilities. @@ -1510,6 +1839,14 @@ typedef enum GF_FS_ARG_META = 1<<5, /*! internal flag used by meta filters (ffmpeg & co) to indicate the description of the argument is a dynamic allocated memory*/ GF_FS_ARG_META_ALLOC = 1<<6, + /*! internal flag used by filters acting as sinks (gsfmx in file mode) to allow retrieving dst url but avoid being used as direct sinks*/ + GF_FS_ARG_SINK_ALIAS = 1<<7, + /*! if set indicates that the argument is updatable only as a direct synchronous call (typically used for shared data). + If so, the value will only be updated if the update directly targets the filter, and the global filter mutex will be locked before calling update_arg. + It is however recommended for the calling app to lock the target filter whenever shared data is modified (see vout filter overlay argument for example) + The filter should lock itself whenever appropriate using \ref gf_filter_lock + */ + GF_FS_ARG_UPDATE_SYNC = 1<<8, } GF_FSArgumentFlags; /*! Structure holding arguments for a filter*/ @@ -1560,6 +1897,8 @@ typedef struct #define CAP_SINT(_f, _a, _b) { .code=_a, .val={.type=GF_PROP_SINT, .value.sint = _b}, .flags=(_f) } /*! Shortcut macro to assign unsigned integer capability type*/ #define CAP_UINT(_f, _a, _b) { .code=_a, .val={.type=GF_PROP_UINT, .value.uint = _b}, .flags=(_f) } +/*! Shortcut macro to assign unsigned integer capability type*/ +#define CAP_4CC(_f, _a, _b) { .code=_a, .val={.type=GF_PROP_4CC, .value.uint = _b}, .flags=(_f) } /*! Shortcut macro to assign signed long integer capability type*/ #define CAP_LSINT(_f, _a, _b) { .code=_a, .val={.type=GF_PROP_LSINT, .value.longsint = _b}, .flags=(_f) } /*! Shortcut macro to assign unsigned long integer capability type*/ @@ -1628,6 +1967,8 @@ enum #define GF_CAPS_INPUT_OUTPUT (GF_CAPFLAG_IN_BUNDLE|GF_CAPFLAG_INPUT|GF_CAPFLAG_OUTPUT) /*! Shortcut macro to set for optional input and output capability flags*/ #define GF_CAPS_INPUT_OUTPUT_OPT (GF_CAPFLAG_IN_BUNDLE|GF_CAPFLAG_INPUT|GF_CAPFLAG_OUTPUT|GF_CAPFLAG_OPTIONAL) +/*! Shortcut macro to set for excluded input capability flags*/ +#define GF_CAPS_IN_OUT_EXCLUDED (GF_CAPFLAG_IN_BUNDLE|GF_CAPFLAG_INPUT|GF_CAPFLAG_OUTPUT|GF_CAPFLAG_EXCLUDED) /*! Filter capability description*/ typedef struct @@ -1669,12 +2010,69 @@ void gf_filter_get_session_caps(GF_Filter *filter, GF_FilterSessionCaps *caps); */ void gf_filter_set_session_caps(GF_Filter *filter, GF_FilterSessionCaps *caps); +/*! Check if the filter is an instance of a filter register +\param filter filter to test +\param freg filter register to test +\return GF_TRUE if filter is an instance of this register, GF_FALSE otehrwise +*/ +Bool gf_filter_is_instance_of(GF_Filter *filter, const GF_FilterRegister *freg); + + +/*! Aborts a filter, discarding and stopping all input PIDs and sending EOS on all output PIDs +\param filter filter to abort +*/ +void gf_filter_abort(GF_Filter *filter); + + +/*! Locks a filter. A filter should only lock itself when using updatable arguments of type GF_FS_ARG_UPDATE_SYNC +\param filter filter to lock +\param do_lock if GF_TRUE, locks the filter global mutex, otherwise unlocks it +*/ +void gf_filter_lock(GF_Filter *filter, Bool do_lock); + + + +/*! Lock global filter session. This is needed when assigning source IDs after a connect source or destination to the loaded source to connect in an async way +\param filter target filter +\param do_lock if GF_TRUE, locks the filter session global mutex, otherwise unlocks it +*/ +void gf_filter_lock_all(GF_Filter *filter, Bool do_lock); + +/*! Force all output pids created for this filter to require a source ID for linking. + + This is used by filters loading subchains to enforce that filters from these subchain only connect to each other or the target filter but not other filters outside this chain. + Filters using this function must setup source IDs on filters of the sunchain(s) they load. + +\param filter target filter +*/ +void gf_filter_require_source_id(GF_Filter *filter); + +/*! Sets opaque runtime data for filter - used by bindings +\param filter target filter +\param udta data to set +\return error if any +*/ +GF_Err gf_filter_set_rt_udta(GF_Filter *filter, void *udta); +/*! Gets opaque runtime data for filter - used by bindings +\param filter target filter +\return associated data or NULL +*/ +void *gf_filter_get_rt_udta(GF_Filter *filter); + + /*! Filter probe score, used when probing a URL/MIME or when probing formats from data*/ typedef enum { /*! (de)mux format is not supported*/ GF_FPROBE_NOT_SUPPORTED = 0, - /*! (de)mux format is supported with potentially missing features*/ + /*! + For demux only: format is maybe a match but garbage data was found at the start + */ + GF_FPROBE_MAYBE_NOT_SUPPORTED, + /*! + - for demux: format is maybe a match and can maybe be demuxed + - for mux: format is supported with potentially missing features + */ GF_FPROBE_MAYBE_SUPPORTED, /*! (de)mux format is supported*/ GF_FPROBE_SUPPORTED, @@ -1719,26 +2117,30 @@ typedef enum GF_FS_REG_HIDE_WEIGHT = 1<<4, /*! Usually set for filters acting as sources but without exposing an src argument. This prevents throwing warnings on arguments not handled by the filter*/ GF_FS_REG_ACT_AS_SOURCE = 1<<5, - /*! Indicates the filter is likely to block for a long time (typically, network IO). - In multithread mode, this prevents the filter to be scheduled on the main thread, blocking video or audio output. - Ignored in single thread mode.*/ - GF_FS_REG_BLOCKING = 1<<6, + /*! Indicates the filter can connect to another instance of the same class (avoids cyclic detection in linker graph) + Filters of the same class can only connect directly to each other if the destination filter is explictly loaded */ + GF_FS_REG_ALLOW_CYCLIC = 1<<6, /*! Indicates the filter PIDs may be dynamically added during process (e.g.M2TS, GSF, etc). This will prevent deactivating a filter when none of its output PIDs are connected*/ GF_FS_REG_DYNAMIC_PIDS = 1<<7, /*! Indicates the filter is a script-based filter. The registry is not valid until the script is loaded*/ GF_FS_REG_SCRIPT = 1<<8, - /*! Indicates the filter is a meta filter, wrapping various underlying filters (e.g., FFmpeg)*/ + /*! Indicates the filter is a meta filter, wrapping various underlying filters (e.g. FFmpeg)*/ GF_FS_REG_META = 1<<9, - /*! Indicates that this filter, when dynamically loaded, allows the link resolver to redirect PID connection to this filter rather than to its next explicetly loaded filter in the chain. + /*! Indicates that this filter, when dynamically loaded, allows the link resolver to redirect PID connection to this filter rather than to its next explicitly loaded filter in the chain. This is typically used by mux filters */ GF_FS_REG_DYNAMIC_REDIRECT = 1<<10, /*! Indicates the filter requires graph resolver (typically because it creates new destinations/sinks at run time)*/ GF_FS_REG_REQUIRES_RESOLVER = 1<<11, + /*! + For sink filters, indicates the filter forces remux of input PIDs of type GF_STREAM_FILE (prevents direct file copy) + For source filters, indicates the PIDs should be remuxed to a destination filter with force remux set + */ + GF_FS_REG_FORCE_REMUX = 1<<12, - /*! flag dynamically set at runtime for registries loaded through shared libraries*/ - GF_FS_REG_DYNLIB = 0x80000000 + /*! flag dynamically set at runtime for custom filters*/ + GF_FS_REG_CUSTOM = 0x40000000, } GF_FSRegisterFlags; /*! The filter register. Registries are loaded once at the start of the session and shall never be modified after that. @@ -1767,7 +2169,8 @@ struct __gf_filter_register const GF_FilterArgs *args; /*! mandatory - callback for filter processing - This function is called whenever packets are available on the input PID and buffer space is available on the output. + + This function is called whenever packets are available on the input PID and buffer space is available on the output. The session will by default monitor a filter for errors, and throw en error if a filter is not consuming nor producing packets for a given amount of process calls. In some cases, it might be needed to not consume nor produce a packet for a given time (for example, waiting for a packet drop before reconfiguring a filter). A filter must signal this using \ref gf_filter_ask_rt_reschedule, possibly with no timeout. @@ -1778,19 +2181,23 @@ struct __gf_filter_register */ GF_Err (*process)(GF_Filter *filter); - /*! optional for sources, mandatory for filters and sinks - callback for PID update may be called several times + /*! optional for sources, mandatory for filters and sinks (any filter with an input cap set) - callback for PID update may be called several times on the same PID if PID config is changed. Since discontinuities may happen at any time, and a filter may fetch packets in burst, - this function may be called while the filter is calling \ref gf_filter_pid_get_packet (this is the only reentrant call for filters) + this function may be called while the filter is calling \ref gf_filter_pid_get_packet (this is the only reentrant call for filters). + If an error is returned, the PID object shall no longer be used by the filter. \param filter the target filter \param PID the input PID to configure \param is_remove indicates the input PID is removed \return error if any. - a return error of GF_REQUIRES_NEW_INSTANCE indicates the PID cannot be processed in this instance but could be in a clone of the filter. - a return error of GF_FILTER_NOT_SUPPORTED indicates the PID cannot be processed and no alternate chain resolution would help - a return error of GF_BAD_PARAM indicates the PID cannot be processed and no alternate chain resolution would help, and throws a log error message - ano other return error will trigger a reconfigure of the chain to find another filter unless disabled at session level. + - a return error of GF_REQUIRES_NEW_INSTANCE indicates the PID cannot be processed in this instance but could be in a clone of the filter. + - a return error of GF_FILTER_NOT_SUPPORTED indicates the PID cannot be processed and no alternate chain resolution would help + - a return error of GF_EOS silently discard the input pid (same as GF_FILTER_NOT_SUPPORTED but does not throw error) + - a return error of GF_BAD_PARAM, GF_SERVICE_ERROR or GF_REMOTE_SERVICE_ERROR indicates the PID cannot be processed and no alternate chain resolution would help, and throws a log error message + - any other return error will trigger a reconfigure of the chain to find another filter unless disabled at session level. + + If an error is returned when (re)configuring a pid, the function is called again with is_remove set to GF_TRUE */ GF_Err (*configure_pid)(GF_Filter *filter, GF_FilterPid *PID, Bool is_remove); @@ -1807,7 +2214,7 @@ struct __gf_filter_register /*! optional - callback for arguments update. If GF_OK is returned, the filter private stack is updated accordingly. If function is NULL, all updatable arguments will be changed in the filter private stack without the filter being notified. - If argument is a meta argument, it is the filter responsability to handle the update, as meta arguments do not live on the filter provate stack. + If argument is a meta argument, it is the filter responsability to handle the update, as meta arguments do not live on the filter private stack. If the filter is a meta filter and argument is not declared in the argument list, the function is always called. \param filter the target filter @@ -1818,8 +2225,8 @@ struct __gf_filter_register GF_Err (*update_arg)(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *new_val); /*! optional - process a given event. Retruns TRUE if the event has to be canceled, FALSE otherwise - If a downstream (towards source) event is not canceled, it will be forwarded to each input PID of the filter. - If you need to forward the event only to one input pid, send a copy of the event to the desired input and cancel the event. + - If a downstream (towards source) event is not canceled, it will be forwarded to each input PID of the filter. + - If you need to forward the event only to one input pid, send a copy of the event to the desired input and cancel the event. \param filter the target filter \param evt the event to process \return GF_TRUE if the event should be canceled, GF_FALSE otherwise @@ -1846,7 +2253,7 @@ struct __gf_filter_register /*! optional, usually set by demuxers. This function probes the mime type of a data chunk, usually located at the start of the file. This function is called once the source is open, but is never called on an instanciated filter. The returned mime type (if any) is then used instead of the file extension for solving filter graph. - Note: demux filters should always exposed 2 input caps bundle, one for specifiying input cap by file extension and one for specifying input cap by mime type. + \note Demux filters should always exposed 2 input caps bundle, one for specifying input cap by file extension and one for specifying input cap by mime type. \param data data to probe \param size size of the data to probe \param score set to the probe score. Initially set to \ref GF_FPROBE_NOT_SUPPORTED before calling the function. If you are certain of the data type, use \ref GF_FPROBE_SUPPORTED, if unsure use \ref GF_FPROBE_MAYBE_SUPPORTED. If the format cannot be probed (bad design), set it to \ref GF_FPROBE_EXT_MATCH @@ -1855,7 +2262,7 @@ struct __gf_filter_register const char * (*probe_data)(const u8 *data, u32 size, GF_FilterProbeScore *score); /*! for filters having the same match of input capabilities for a PID, the filter with priority at the lowest value will be used - scalable decoders should use high values, so that they are only selected when enhancement layers are present*/ + \note Scalable decoders should use high values, so that they are only selected when enhancement layers are present*/ u8 priority; /*! optional for dynamic filter registries. Dynamic registries may declare any number of registries. The register_free function will be called to cleanup any allocated memory @@ -1891,7 +2298,7 @@ struct __gf_filter_register /*! version of the filter, usually only for external libs - Note: If this strings starts with "! " it indicates an error message at load time of the registry. This should only be set when \code gf_opts_get_bool("temp", "gendoc"); \endcode returns true, indicating the filter session is only loaded for documentation purposes (man/md generation and command line help). + \note If this strings starts with "! " it indicates an error message at load time of the registry. This should only be set when \code gf_opts_get_bool("temp", "gendoc"); \endcode returns true, indicating the filter session is only loaded for documentation purposes (man/md generation and command line help). */ const char *version; #ifndef GPAC_DISABLE_DOC @@ -1906,16 +2313,19 @@ struct __gf_filter_register - shall not use markdown - first line if present is author name and should be normally capitalized - second line if present is comma-separated list of contact info (eg http://foo.bar,mailto:foo@bar.com) + + If first character is a `-`, this field is interpreted as a configuration info (typically for meta filters such as ffmpeg). */ const char *author; /*! help of the filter. Conventions: - - describe any non-obvious behaviour of the filter here + - describe any non-obvious behavior of the filter here - markdown is allowed. Use '`' for code, "__" for italic, "**" for bold and "~~" for strikethrough. - mardown top-level sections shall use '#', second level '##', and so on - mardown bullet lists shall use "- ", " - " etc... - notes shall be identifed as a line starting with "Note: " - warnings shall be identifed as a line starting with "Warning: " - - the sequence "[-" is reserved for option links. It is formated as: + - examples shall be identifed as a line starting with "EX " + - the sequence "[-" is reserved for option links. It is formatted as: - "[-OPT]()": link to self page for option OPT - "[-OPT](LINK)": link to other page for option OPT. LINK can be: @@ -1973,6 +2383,9 @@ GF_DownloadManager *gf_filter_get_download_manager(GF_Filter *filter); struct _gf_ft_mgr *gf_filter_get_font_manager(GF_Filter *filter); /*! Asks task reschedule for a given delay. There is no guarantee that the task will be recalled at exactly the desired delay + + The function can be called several times while in process, the smallest reschedule time will be kept. + \param filter target filter \param us_until_next number of microseconds to wait before recalling this task */ @@ -1998,10 +2411,10 @@ GF_Err gf_filter_post_task(GF_Filter *filter, Bool (*task_execute) (GF_Filter *f /*! Sets callback function on source filter setup failure \param filter target filter \param source_filter the source filter to monitor -\param on_setup_error callback function to call upon source setup error +\param on_setup_error callback function to call upon source setup error - the callback can return GF_TRUE to cancel error reporting \param udta user data passed back to the task function */ -void gf_filter_set_setup_failure_callback(GF_Filter *filter, GF_Filter *source_filter, void (*on_setup_error)(GF_Filter *f, void *on_setup_error_udta, GF_Err e), void *udta); +void gf_filter_set_setup_failure_callback(GF_Filter *filter, GF_Filter *source_filter, Bool (*on_setup_error)(GF_Filter *f, void *on_setup_error_udta, GF_Err e), void *udta); /*! Notify a filter setup error. This is typically called when a source filter or a filter having accepted input PIDs detects an issue. For a source filter (no input PID), the failure callback will be called if any, and the filter will be removed. @@ -2056,8 +2469,7 @@ void gf_filter_block_eos(GF_Filter *filter, Bool do_block); /*! Connects a source to this filter. -Note: -Any filter loaded between the source and the calling filter will not use argument inheritance from the caller. +\note Any filter loaded between the source and the calling filter will not use argument inheritance from the caller. \param filter the target filter \param url url of source to connect to, with optional arguments. @@ -2143,6 +2555,9 @@ void gf_filter_get_clock_hint(GF_Filter *filter, u64 *time_in_us, GF_Fraction64 /*! Explicitly assigns a source ID to a filter. This shall be called before connecting the link_from filter If no ID is assigned to the linked filter, a dynamic one in the form of _%08X_ (using the filter mem address) will be used + +\warning In multithreaded sessions, the session must be locked before the filter creation step and unlocked after calling this function, otherwise graph resolution might happen before \ref gf_filter_set_source is called + \param filter the target filter \param link_from the filter to link from \param link_ext any link extensions allowed in link syntax: @@ -2157,9 +2572,19 @@ If no ID is assigned to the linked filter, a dynamic one in the form of _%08X_ ( */ GF_Err gf_filter_set_source(GF_Filter *filter, GF_Filter *link_from, const char *link_ext); +/*! Similar to \ref gf_filter_set_source + This should be used on source filters when the calling filter is expected to have more possible sources added in the future, thereby dynamically changing its source IDs. + Typically the compositor running the GUI is one such filter. This variant will make sure the sourceID used in the adaptation chain is always the ID of the source and not the source ID of the calling filter +\param filter the target filter +\param link_from the filter to link from +\param link_ext any link extensions allowed in link syntax: +\return error code if any +*/ +GF_Err gf_filter_set_source_restricted(GF_Filter *filter, GF_Filter *link_from, const char *link_ext); + /*! Explicitly reset sourceID of a filter. This shall be called before connecting the filter (eg creating PIDs). - This is mostly used to reset a source ID of a filter created from a destination (e.g., dasher creating muxers from the MPD URL) where the destination arguments could have sourceIDs specified/ + This is mostly used to reset a source ID of a filter created from a destination (e.g. dasher creating muxers from the MPD URL) where the destination arguments could have sourceIDs specified/ \param filter the target filter */ @@ -2178,8 +2603,19 @@ GF_Err gf_filter_assign_id(GF_Filter *filter, const char *filter_id); */ const char *gf_filter_get_id(GF_Filter *filter); +/*! Indicates the filter is a likely to block for a long time (typically, network IO). +In multithread mode, this prevents the filter to be scheduled on the main thread, blocking video or audio output. +By default, all filters are created as non-blocking. + +\param filter the target filter +\param is_blocking if GF_TRUE, indicates the filter is likely to block +*/ +void gf_filter_set_blocking(GF_Filter *filter, Bool is_blocking); + +/*! Overrides the filter caps with new caps for this instance. Typically used when an option of the filter changes the capabilities + +The new caps are only taken into account for future graph resolutions, any current link from/to the target filter will not be re-solved when calling this function. -/*! Overrides the filter register caps with new caps for this instance. Typically used when an option of the filter changes the capabilities \param filter the target filter \param caps the new set of capabilities to use for the filter. These are NOT copied and shall be valid for the lifetime of the filter \param nb_caps number of capabilities set @@ -2187,6 +2623,12 @@ const char *gf_filter_get_id(GF_Filter *filter); */ GF_Err gf_filter_override_caps(GF_Filter *filter, const GF_FilterCapability *caps, u32 nb_caps ); +/*! Indicates this filter acts as a sink and will be used as such in graph resolution. Such filters must provide a use_alias function in their registry. +\param filter the target filter +\return error code if any +*/ +GF_Err gf_filter_act_as_sink(GF_Filter *filter); + /*! Filter session separator set query*/ typedef enum { @@ -2202,7 +2644,7 @@ typedef enum GF_FS_SEP_NEG, } GF_FilterSessionSepType; -/*! Queries the character code used as a given separator type in argument names. Used for formating arguments when loading sources and destinations from inside a filter +/*! Queries the character code used as a given separator type in argument names. Used for formatting arguments when loading sources and destinations from inside a filter \param filter the target filter \param sep_type the separator type to query \return character code of the separator @@ -2221,6 +2663,12 @@ const char *gf_filter_get_dst_args(GF_Filter *filter); */ char *gf_filter_get_dst_name(GF_Filter *filter); +/*! Get the filter arguments. +\param filter the target filter +\return the argument string of the filter +*/ +const char *gf_filter_get_src_args(GF_Filter *filter); + /*! Sends an event on all input PIDs (downstream) or on all output PIDs (upstream) \param filter the target filter \param evt the event to send @@ -2244,9 +2692,9 @@ GF_Err gf_filter_reconnect_output(GF_Filter *filter); GF_Err gf_filter_set_event_target(GF_Filter *filter, Bool enable_events); /*! Looks for a built-in property value marked as informative on a filter on all PIDs (inputs and output) -This is a recursive call on both input and ouput chain. +This is a recursive call on both input and output chain. There is no guarantee that a queried property will still be valid at the setter side upon returning the call, the setter could have -already reassigned it to NULL. To avoids random behaviour, the property returned is reference counted so that it is not +already reassigned it to NULL. To avoids random behavior, the property returned is reference counted so that it is not destroyed by the setter while the caller uses it. Properties retrieved shall be released using \ref gf_filter_release_property. Failure to do so will cause memory leaks in the program. @@ -2279,7 +2727,7 @@ gf_filter_release_property(pe); const GF_PropertyValue *gf_filter_get_info(GF_Filter *filter, u32 prop_4cc, GF_PropertyEntry **propentry); /*! Looks for a property value on a filter on all PIDs (inputs and output). -This is a recursive call on both input and ouput chain +This is a recursive call on both input and output chain Properties retrieved shall be released using \ref gf_filter_release_property. See \ref gf_filter_pid_get_info for more details. \param filter the target filter \param prop_name the name of the property to fetch @@ -2289,7 +2737,7 @@ Properties retrieved shall be released using \ref gf_filter_release_property. Se const GF_PropertyValue *gf_filter_get_info_str(GF_Filter *filter, const char *prop_name, GF_PropertyEntry **propentry); /*! Release a property previously queried, only used for []_get_info_[] functions. -This is a recursive call on both input and ouput chain +This is a recursive call on both input and output chain \param propentry the property reference object to be released */ void gf_filter_release_property(GF_PropertyEntry *propentry); @@ -2340,7 +2788,7 @@ GF_Err gf_filter_remove_event_listener(GF_Filter *filter, GF_FSEventListener *el /*! Forwards an event to the filter session \param filter filter object \param evt the event forwarded -\param consumed if set, indicates the event was already consummed/processed before forwarding +\param consumed if set, indicates the event was already consumed/processed before forwarding \param skip_user if set, indicates the event should only be dispatched to event listeners. Otherwise, if a user is assigned to the session, the event is forwarded to the user \return the error code if any @@ -2363,7 +2811,7 @@ Bool gf_filter_all_sinks_done(GF_Filter *filter); /*! Gets a filter argument value as string for a given argument name.. \param filter filter object \param arg_name name of the filter argument -\param dump buffer in which any formating of argument value will take place +\param dump buffer in which any formatting of argument value will take place \return the string value of the argument, or NULL if argument is not found or is invalid */ const char *gf_filter_get_arg_str(GF_Filter *filter, const char *arg_name, char dump[GF_PROP_DUMP_ARG_SIZE]); @@ -2393,23 +2841,23 @@ Bool gf_filter_is_supported_mime(GF_Filter *filter, const char *mime); Bool gf_filter_ui_event(GF_Filter *filter, GF_Event *uievt); -/*! Registers filter as an openGL provider. This is only used by sink filters creating a openGL context, to avoid creating another context. Filters registered as OpenGL providers will run on the main thread. +/*! Registers filter as an OpenGL provider. This is only used by sink filters creating a OpenGL context, to avoid creating another context. Filters registered as OpenGL providers will run on the main thread. \param filter filter providing OpenGL context \param do_register if TRUE the filter carries a valid gl context, if FALSE the filter no longer carries a valid GL context */ void gf_filter_register_opengl_provider(GF_Filter *filter, Bool do_register); -/*! Requests openGL support for this filter. If no OpenGL providers exist, a default provider will be created (GL context creation on hidden window). Filters requiring OpenGL will run on the main thread. +/*! Requests OpenGL support for this filter. If no OpenGL providers exist, a default provider will be created (GL context creation on hidden window). Filters requiring OpenGL will run on the main thread. -\note Filters using openGL should not assume any persistent GL state among calls. Other filters using openGL might change the openGL context state (depth test, viewport, alpha blending, culling, etc...). +\note Filters using OpenGL should not assume any persistent GL state among calls. Other filters using OpenGL might change the OpenGL context state (depth test, viewport, alpha blending, culling, etc...). \param filter filter providing OpenGL context \return error code if any */ GF_Err gf_filter_request_opengl(GF_Filter *filter); -/*! Sets openGL context active for this filter. -\note There may be several openGL context created in the filter session, depending on activated filters. A filter using openGL must call this function before issuing any openGL calls +/*! Sets OpenGL context active for this filter. +\note There may be several OpenGL context created in the filter session, depending on activated filters. A filter using OpenGL must call this function before issuing any OpenGL calls \param filter filter asking for OpenGL context activation \return error code if any @@ -2420,7 +2868,7 @@ GF_Err gf_filter_set_active_opengl_context(GF_Filter *filter); /*! Count the number of source filters for the given filter matching the given protocol type. \param filter filter to inspect \param protocol_scheme scheme of the protocol to test, without ://, eg "http", "rtp", "https" -\param expand_proto if set to GF_TRUE, any source protocol with a name begining like protocol_scheme will be matched. For example, use this with "http" to match all http and https schemes. +\param expand_proto if set to GF_TRUE, any source protocol with a name beginning like protocol_scheme will be matched. For example, use this with "http" to match all http and https schemes. \param enum_pids user function to enumerate PIDs against which the source should be checked . If not set, all source filters will be checked. \param udta user data for the callback function \return the number of source filters matched by protocols @@ -2439,7 +2887,7 @@ void gf_filter_disable_inputs(GF_Filter *filter); /*! Checks if some PIDs are still not connected in the graph originating at filter. This is typically used by filters dynamically loading source filters to make sure all PIDs from the source are connected. -NOTE: this does not guarantee that no other PID remove or configure will happen later on, this depends on the source type and is unknown by GPAC's filter architecture. +\note This does not guarantee that no other PID remove or configure will happen later on, this depends on the source type and is unknown by GPAC's filter architecture. \param filter target filter \param stop_at_filter check connections until this filter. If NULL, connections are checked until upper (sink) end of graph \return GF_TRUE if any filter in the path has pending PID connections @@ -2493,12 +2941,13 @@ GF_Err gf_filter_update_status(GF_Filter *filter, u32 percent, char *szStatus); */ Bool gf_filter_end_of_session(GF_Filter *filter); -/*! used by meta-filters (ffmpeg and co) to report an option was set but not used by the filter. This is needed since these filters might not +/*! used by meta-filters (ffmpeg and co) to report used/unused options. This is needed since these filters might not know the set of available options at initialize() time. \param filter target filter \param arg name of the argument not used/found +\param was_found indicate that this option was found */ -void gf_filter_report_unused_meta_option(GF_Filter *filter, const char *arg); +void gf_filter_report_meta_option(GF_Filter *filter, const char *arg, Bool was_found); /*! used by script to set a per-instance description \param filter target filter @@ -2567,8 +3016,14 @@ GF_Err gf_filter_define_args(GF_Filter *filter, GF_FilterArgs *new_args); */ GF_FilterArgs *gf_filter_get_args(GF_Filter *filter); +/*! get per-instance caps +\param filter target filter +\param nb_caps set to the number of caps +\return the filter instance caps if any, NULL otherwise +*/ +const GF_FilterCapability *gf_filter_get_caps(GF_Filter *filter, u32 *nb_caps); -/*! probes mime type of a given block of data (should be begining of file ) +/*! probes mime type of a given block of data (should be beginning of file ) \param filter target filter \param data buffer to probe \param size size of buffer @@ -2597,6 +3052,76 @@ Bool gf_filter_in_parent_chain(GF_Filter *parent, GF_Filter *filter); */ GF_Err gf_filter_get_stats(GF_Filter *filter, GF_FilterStats *stats); + +/*! Enumerates default arguments of a filter +\param filter filter session +\param idx the 0-based index of the argument to query +\return the argument definition, or NULL if error +*/ +const GF_FilterArgs *gf_filter_enumerate_args(GF_Filter *filter, u32 idx); + + +/*! Reslves URL against locales settings +\param filter filter +\param service_url URL of service to relocate +\param parent_url parent URL of service +\param out_relocated_url - must be GF_MAX_PATH size +\param out_localized_url - must be GF_MAX_PATH size +\return GF_TRUE if success +*/ +Bool gf_filter_relocate_url(GF_Filter *filter, const char *service_url, const char *parent_url, char *out_relocated_url, char *out_localized_url); + + +/*! Returns the register of a given filter +\param filter target filter +\return the register object, or NULL if error +*/ +const GF_FilterRegister *gf_filter_get_register(GF_Filter *filter); + +/*! Prints all possible connections between filter registries for a loaded filter using \code LOG_APP@LOG_INFO \endcode +\param filter filter object +\param print_fn optional callback function for print, otherwise print to stderr +*/ +void gf_filter_print_all_connections(GF_Filter *filter, void (*print_fn)(FILE *output, GF_SysPrintArgFlags flags, const char *fmt, ...) ); + +/*! Force a filter to run on main thread. + +\param filter filter object +\param do_tag if GF_TRUE, tags filter to run on main thread, otherwise untags filters + +\warning There shall be at most as many with do_tag=GF_FALSE as there were calls with do_tag=GF_TRUE +*/ +void gf_filter_force_main_thread(GF_Filter *filter, Bool do_tag); + +/*! Check if a filter is a sink, i.e. it has no output capabilities. + \note a filter may have no outputs but still not be a sink due to dynamic nature of filter linking +\param filter target filter +\return GF_TRUE if filter is a sink, GF_FALSE otherwise +*/ +Bool gf_filter_is_sink(GF_Filter *filter); + +/*! Check if a filter is a source, i.e. it has no input capabilities + \note a filter may have no inputs but still not be a source, typically the case for some custom filters loading their sources dynamically +\param filter target filter +\return GF_TRUE if filter is a source, GF_FALSE otherwise +*/ +Bool gf_filter_is_source(GF_Filter *filter); + +/*! Tags a filter in a given subsession, ignored in non-implicit mode. + +If sourceIDs are used on destination filter, subsession and source IDs are ignored. +If filters do not have the same subsession ID, they cannot link to each +If filters do not have the same sourceID, they cannot link to each other except if destination is a sink + +\note In non-implicit mode, subsession tagging must be done through filter option :FS= + +\param filter target filter +\param subsession_id subsession identifier +\param source_id subsession identifier +\return error if any +*/ +GF_Err gf_filter_tag_subsession(GF_Filter *filter, u32 subsession_id, u32 source_id); + /*! @} */ @@ -2652,14 +3177,16 @@ void gf_filter_pid_remove(GF_FilterPid *PID); \param out_pid the output PID to create or update. If no referer PID, a new PID will be created otherwise the PID will be updated \return error code if any */ -GF_Err gf_filter_pid_raw_new(GF_Filter *filter, const char *url, const char *local_file, const char *mime_type, const char *fext, u8 *probe_data, u32 probe_size, Bool trust_mime, GF_FilterPid **out_pid); +GF_Err gf_filter_pid_raw_new(GF_Filter *filter, const char *url, const char *local_file, const char *mime_type, const char *fext, const u8 *probe_data, u32 probe_size, Bool trust_mime, GF_FilterPid **out_pid); /*! Sets a new property on an output PID for built-in property names. -Previous properties (ones set before last packet dispatch) will still be valid. Property with same type/name will be reassigned -You need to remove them one by one using \ref gf_filter_pid_set_property with NULL property, or reset the properties with \ref gf_filter_pid_reset_properties. Setting a new property will trigger a PID reconfigure at the consumption point of the next dispatched packet. +Previous properties (ones set before last packet dispatch) will still be valid. You can remove any of them using \ref gf_filter_pid_set_property with NULL property, or reset the properties with \ref gf_filter_pid_reset_properties. +There cannot be two instances of a property a given type/name: +- If a property with same type/name exists and has the same value, assignment will be skipped: this avoids triggering PID reconfiguration when not needed. In that case, if the property contains memory to be passed to the filter session, this memory will be destroyed (eg GF_PROP_STRING_NO_COPY, GF_PROP_DATA_NO_COPY, GF_PROP_STRING_LIST). +- If the values differ, the property will be reassigned. There cannot be tow instances of a proerty value with a given type/name. -Warning: changing a property before the final end of stream (i.e. if no more packets are sent) will have no effect. You must use \ref gf_filter_pid_set_info and \ref gf_filter_pid_get_info for this. +Warning: changing a property at the final end of stream (i.e. if no more packets are sent) will have no effect. You must use \ref gf_filter_pid_set_info and \ref gf_filter_pid_get_info for this. \param PID the target filter PID \param prop_4cc the built-in property code to modify @@ -2687,8 +3214,10 @@ GF_Err gf_filter_pid_set_property_dyn(GF_FilterPid *PID, char *name, const GF_Pr /*! Sets a new info property on an output PID for built-in property names. Similar to \ref gf_filter_pid_set_property, but infos are not copied up the chain and to not trigger PID reconfiguration. First packet dispatched after calling this function will be marked, and its fetching by the consuming filter will trigger a process_event notification. -If the consumming filter copies properties from source packet to output packet, the flag will be passed to such new output packet. -Note: any property type can be used for info, except \ref GF_PROP_POINTER. +If the consuming filter copies properties from source packet to output packet, the flag will be passed to such new output packet. + +If an info property with same type/name exists and has the same value, assignment will be skipped. In that case, if the property contains memory to be passed to the filter session, this memory will be destroyed (eg GF_PROP_STRING_NO_COPY, GF_PROP_DATA_NO_COPY, GF_PROP_STRING_LIST). + \param PID the target filter PID \param prop_4cc the built-in property code to modify @@ -2727,6 +3256,19 @@ void gf_filter_pid_set_udta(GF_FilterPid *PID, void *udta); */ void *gf_filter_pid_get_udta(GF_FilterPid *PID); +/*! get user 32-bits flags +\param PID the target filter PID +\return flags +*/ +u32 gf_filter_pid_get_udta_flags(GF_FilterPid *PID); + +/*! set user 32-bits flags +\param PID the target filter PID +\param flags the flags (replaces the entire flags)) +\return error if any +*/ +GF_Err gf_filter_pid_set_udta_flags(GF_FilterPid *PID, u32 flags); + /*! Gets PID name. Mostly used for logging purposes \param PID the target filter PID \param name the new PID name. function ignored if NULL. @@ -2747,11 +3289,12 @@ const char *gf_filter_pid_get_filter_name(GF_FilterPid *PID); /*! Gets the source arguments of the PID, walking down the chain until the source filter \param PID the target filter PID +\param for_unicity if GF_TRUE, will return the arguments of the first filter responsible for a fan-out leading to this PID \return argument of the source filter */ -const char *gf_filter_pid_orig_src_args(GF_FilterPid *PID); +const char *gf_filter_pid_orig_src_args(GF_FilterPid *PID, Bool for_unicity); -/*! Gets the source filter name or class name for the PID, walking down the chain until the source filter (ony the first input PID of each filter is used). +/*! Gets the source filter name or class name for the PID, walking down the chain until the source filter (only the first input PID of each filter is used). \param PID the target filter PID \return argument of the source filter */ @@ -2783,6 +3326,13 @@ u32 gf_filter_pid_get_max_buffer(GF_FilterPid *PID); */ Bool gf_filter_pid_is_filter_in_parents(GF_FilterPid *PID, GF_Filter *filter); +/*! Checks if a given PID has a common filter with another PID in the parent graph +\param PID the target filter PID +\param other_pid the other PID to check +\return GF_TRUE if a filter is found that is outputing these two PIDs, GF_FALSE otherwise +*/ +Bool gf_filter_pid_share_origin(GF_FilterPid *PID, GF_FilterPid *other_pid); + /*! Gets current buffer levels of the PID \param PID the target filter PID \param max_units maximum number of packets allowed - can be 0 if buffer is measured in time @@ -2798,6 +3348,15 @@ Bool gf_filter_pid_get_buffer_occupancy(GF_FilterPid *PID, u32 *max_units, u32 * */ void gf_filter_pid_set_loose_connect(GF_FilterPid *PID); +/*! Adds PID properties from textual description - this does not reset the PID properties +\param PID the target filter PID +\param args one or more serialized properties to set, as documented in gpac -h doc +\param direct_merge if true, next packet to be sent will not trigger a property change +\param use_default_seps if GF_TRUE, the serialized properties are using the default separator set, otherwise they are using the current separator set of the session +\return Error if any +*/ +GF_Err gf_filter_pid_push_properties(GF_FilterPid *PID, char *args, Bool direct_merge, Bool use_default_seps); + /*! Negotiate a given property on an input PID for built-in properties Filters may accept some PID connection but may need an adaptaion chain to be able to process packets, eg change pixel format or sample rate @@ -2830,7 +3389,7 @@ GF_Err gf_filter_pid_negociate_property_dyn(GF_FilterPid *PID, char *name, const /*! Queries a negotiated built-in capability on an output PID Filters may check if a property negotiation was done on an output PID, and check the property value. -This can be done on an output PID in a filter->reconfigure_output if the filter accpets caps negotiation +This can be done on an output PID in a filter->reconfigure_output if the filter accepts caps negotiation This can be done on an input PID in a generic reconfigure_pid \param PID the target filter PID @@ -2950,7 +3509,7 @@ GF_Err gf_filter_pid_merge_properties(GF_FilterPid *dst_pid, GF_FilterPid *src_p /*! Gets a built-in property of the PID Warning: properties are only valid until the next configure_pid is called. Attempting to use a property value (either the pointer or one of the value) queried before the current configure_pid will result in - unpredictable behaviour, potentially crashes. + unpredictable behavior, potentially crashes. \param PID the target filter PID \param prop_4cc the code of the built-in property to retrieve \return the property if found or NULL otherwise @@ -3012,7 +3571,7 @@ Properties retrieved shall be released using \ref gf_filter_release_property. Se */ const GF_PropertyValue *gf_filter_pid_get_info(GF_FilterPid *PID, u32 prop_4cc, GF_PropertyEntry **propentry); -/*! Looks for a property value on a PIDs. This is a recursive call on both input and ouput chain +/*! Looks for a property value on a PIDs. This is a recursive call on both input and output chain Properties retrieved shall be released using \ref gf_filter_release_property. See \ref gf_filter_pid_get_info for more details. \param PID the target filter PID to query \param prop_name the name of the property to fetch @@ -3034,9 +3593,15 @@ This is a recursive call on input chain. The function is typically used to abort */ Bool gf_filter_pid_has_seen_eos(GF_FilterPid *PID); +/*! Checks for end of stream has been signaled a PID. Contrary to \ref gf_filter_pid_has_seen_eos this is not a recursive call and only checks the given pid. +\param PID the target filter PID +\return GF_TRUE if end of stream was signaled for that pid (there may be pending packets in queue) +*/ +Bool gf_filter_pid_eos_received(GF_FilterPid *PID); + /*! Checks for end of stream signaling on a PID. \param PID the target filter PID -\return GF_TRUE if end of stream was signaled on that PID +\return GF_TRUE if end of stream is set on that PID (no more packet in queue) */ Bool gf_filter_pid_is_eos(GF_FilterPid *PID); @@ -3081,7 +3646,7 @@ Bool gf_filter_pid_check_caps(GF_FilterPid *PID); /*! Checks if the PID would enter a blocking state if a new packet is sent. This function should be called by eg demuxers to regulate the rate at which they send packets -Note: PIDs are never fully blocking in GPAC, a filter requesting an output packet should usually get one unless something goes wrong +\note PIDs are never fully blocking in GPAC, a filter requesting an output packet should usually get one unless something goes wrong \param PID the target filter PID \return GF_TRUE if PID would enter blocking state , GF_FALSE otherwise */ @@ -3094,7 +3659,7 @@ Bool gf_filter_pid_would_block(GF_FilterPid *PID); u32 gf_filter_pid_get_timescale(GF_FilterPid *PID); /*! Clears the end of stream flag on a PID. -Note: the end of stream is automatically cleared when a new packet is dispatched; This function is used to clear it asap, before next packet dispacth (period switch in dash for example). +\note The end of stream is automatically cleared when a new packet is dispatched; This function is used to clear it asap, before next packet dispacth (period switch in dash for example). \param PID the target filter PID \param all_pids if sets, clear end oof stream for all PIDs coming from the same filter as the target PID */ @@ -3132,11 +3697,23 @@ Supported KEYWORD (case insensitive): GF_Err gf_filter_pid_resolve_file_template(GF_FilterPid *PID, char szTemplate[GF_MAX_PATH], char szFinalName[GF_MAX_PATH], u32 file_number, const char *file_suffix); +/*! Same as \ref gf_filter_pid_resolve_file_template but overrides file name with given name +\param PID the target filter PID +\param szTemplate source template to solve +\param szFinalName buffer for final name +\param file_number number of file to use +\param file_suffix if not null, will be appended after the value of the §File$ keyword if present +\param file_name if not null, will be used instead of PID URL or local path +\return error if any +*/ +GF_Err gf_filter_pid_resolve_file_template_ex(GF_FilterPid *PID, char szTemplate[GF_MAX_PATH], char szFinalName[GF_MAX_PATH], u32 file_number, const char *file_suffix, const char *file_name); + + /*! Sets discard mode on or off on an input PID. When discard is on, all input packets for this PID are no longer dispatched. This only affect the current PID, not the source filter(s) for that PID. -PID reconfigurations are still forwarded to the filter, so that a filter may decide to re-enable regular mode. +PID reconfigurations are still forwarded to the filter, so that a filter may decide to re-enable regular mode. Packets sent after a PID reconfiguration are kept until the PID is reconfigured, and discarded if the PID is still in discard mode. This is typically needed for filters that stop consuming data for a while (dash forced period duration for example) but may resume consumption later on (stream moving from period 1 to period 2 for example). @@ -3226,6 +3803,37 @@ GF_Err gf_filter_pid_allow_direct_dispatch(GF_FilterPid *PID); */ void *gf_filter_pid_get_alias_udta(GF_FilterPid *PID); +/*! Gets the filter owning the input PID +\param PID the target filter PID +\return the filter owning the PID or NULL if error +*/ +GF_Filter *gf_filter_pid_get_source_filter(GF_FilterPid *PID); + +/*! Enumerates the destination filters of an output PID +\param PID the target filter PID +\param idx the target destination index +\return the destination filter for the given index, or NULL if error +*/ +GF_Filter *gf_filter_pid_enum_destinations(GF_FilterPid *PID, u32 idx); + +/*! Ignore this PID in blocking mode estimations. + +This is typically used when a filter consumes N pids, with some at very low frequency for which an empty queue should not imply unblocking the filter to refill the queue. + +\param PID the target filter PID +\param do_ignore if GF_TRUE, the PID will not be considered when trying to unblock the filter +\return error if any +*/ +GF_Err gf_filter_pid_ignore_blocking(GF_FilterPid *PID, Bool do_ignore); + +/*! Gets next estimated time on this PID, ie last_pck(DTS+dur) or last_pck(CTS+dur) + +\param PID the target filter PID +\return GF_FILTER_NO_TS or estimated time +*/ +u64 gf_filter_pid_get_next_ts(GF_FilterPid *PID); + + /*! @} */ @@ -3248,18 +3856,26 @@ reassign output packet properties changed by the filter. In order to handle reordering of packets, it is possible to keep references to either packets (may block the filter chain), or packet properties. Packets shall always be dispatched in their processing order (decode order). If reordering upon reception is needed, or AU interleaving is used, a filter SHALL do the reordering. -However, packets do not have to be send in their creation order: a created packet is not assigned to PID buffers until it is send. +However, packets do not have to be send in their creation order: a created packet is not assigned to PID buffers until it is sent. @{ */ /*! Keeps a reference to the given input packet. The packet shall be released at some point using \ref gf_filter_pck_unref + + Filters keeping reference to packets should check if the packet is a blocking reference using gf_filter_pck_is_blocking_ref. If this is the case, the input chain will likely be blocked until the packet reference is released. \param pck the target input packet \return error if any */ GF_Err gf_filter_pck_ref(GF_FilterPacket **pck); +/*! Same as \ref gf_filter_pck_ref but doesn't use pointer to packet +\param pck the target input packet +\return the new reference to the packet +*/ +GF_FilterPacket *gf_filter_pck_ref_ex(GF_FilterPacket *pck); + /*! Remove a reference to the given input packet. The packet might be destroyed after that call. \param pck the target input packet */ @@ -3279,7 +3895,7 @@ The packet has by default no DTS, no CTS, no duration framing set to full frame \param PID the target output PID \param data_size the desired size of the packet - can be changed later \param data set to the writable buffer of the created packet -\return new packet or NULL if error +\return new packet or NULL if allocation error or not an output PID */ GF_FilterPacket *gf_filter_pck_new_alloc(GF_FilterPid *PID, u32 data_size, u8 **data); @@ -3290,19 +3906,19 @@ The packet has by default no DTS, no CTS, no duration framing set to full frame \param data the data block to dispatch \param data_size the size of the data block to dispatch \param destruct the callback function used to destroy the packet when no longer used - may be NULL -\return new packet or NULL if error +\return new packet or NULL if allocation error or not an output PID */ GF_FilterPacket *gf_filter_pck_new_shared(GF_FilterPid *PID, const u8 *data, u32 data_size, gf_fsess_packet_destructor destruct); /*! Allocates a new packet on the output PID referencing data of some input packet. The packet has by default no DTS, no CTS, no duration framing set to full frame (start=end=1) and all other flags set to 0 (including SAP type). \param PID the target output PID -\param data the data block to dispatch - if NULL, the entire data of the source packet is used -\param data_size the size of the data block to dispatch - if 0, the entire data of the source packet is used +\param data_offset offset in the source data block +\param data_size the size of the data block to dispatch - if 0, the entire data of the source packet beginning at offset is used \param source_packet the source packet this data belongs to (at least from the filter point of view). -\return new packet or NULL if error +\return new packet or NULL if allocation error or not an output PID */ -GF_FilterPacket *gf_filter_pck_new_ref(GF_FilterPid *PID, const u8 *data, u32 data_size, GF_FilterPacket *source_packet); +GF_FilterPacket *gf_filter_pck_new_ref(GF_FilterPid *PID, u32 data_offset, u32 data_size, GF_FilterPacket *source_packet); /*! Allocates a new packet on the output PID with associated allocated data. The packet has by default no DTS, no CTS, no duration framing set to full frame (start=end=1) and all other flags set to 0 (including SAP type). @@ -3310,7 +3926,7 @@ The packet has by default no DTS, no CTS, no duration framing set to full frame \param data_size the desired size of the packet - can be changed later \param data set to the writable buffer of the created packet \param destruct the callback function used to destroy the packet when no longer used - may be NULL -\return new packet or NULL if error +\return new packet or NULL if allocation error or not an output PID */ GF_FilterPacket *gf_filter_pck_new_alloc_destructor(GF_FilterPid *PID, u32 data_size, u8 **data, gf_fsess_packet_destructor destruct); @@ -3322,7 +3938,7 @@ Otherwise, the source data is assigned to the output packet. \param PID the target output PID \param pck_source the desired source packet to clone \param data set to the writable buffer of the created packet -\return new packet or NULL if error +\return new packet or NULL if allocation error or not an output PID */ GF_FilterPacket *gf_filter_pck_new_clone(GF_FilterPid *PID, GF_FilterPacket *pck_source, u8 **data); @@ -3330,10 +3946,25 @@ GF_FilterPacket *gf_filter_pck_new_clone(GF_FilterPid *PID, GF_FilterPacket *pck \param PID the target output PID \param pck_source the desired source packet to clone \param data set to the writable buffer of the created packet -\return new packet or NULL if error +\return new packet or NULL if allocation error or not an output PID */ GF_FilterPacket *gf_filter_pck_new_copy(GF_FilterPid *PID, GF_FilterPacket *pck_source, u8 **data); +/*! Creates a read-only detached copy of a packet from a source packet and copy all source properties to output. + +If the source packet uses a frame interface object or has no associated data, returns a copy of the packet. +If the source packet is referenced more than once (ie more than just the caller), a new packet on the output PID is allocated with source data copied. +Otherwise, the source data is assigned to the output packet. + +This is typically called by filters requiring read access to data for packets using frame interfaces +\warning The cloned packet will not have any dynamic properties set. + +\param pck_source the target source packet +\param cached_pck if not NULL, will try to reuse this packet if possible (if not possible, this packet will be destroyed) +\return new packet or NULL if allocation error or not an output PID +*/ +GF_FilterPacket *gf_filter_pck_dangling_copy(GF_FilterPacket *pck_source, GF_FilterPacket *cached_pck); + /*! Marks memory of a shared packet as non-writable. By default \ref gf_filter_pck_new_shared and \ref gf_filter_pck_new_ref allow write access to internal memory in case the packet can be cloned (single reference used). If your filter relies on the content of the shared memory for its internal state, packet must be marked as read-only to avoid later state corruption. @@ -3394,6 +4025,15 @@ GF_Err gf_filter_pck_set_property_str(GF_FilterPacket *pck, const char *name, co */ GF_Err gf_filter_pck_set_property_dyn(GF_FilterPacket *pck, char *name, const GF_PropertyValue *value); +/*! Checks if a packet has properties other than packet built-in ones + + This is typically needed to decide whether a packet with no data should be forwarded or not + +\param pck the target packet +\return GF_TRUE if packet has properties, GF_FALSE otherwise +*/ +Bool gf_filter_pck_has_properties(GF_FilterPacket *pck); + /*! Merge properties of source packet into destination packet but does NOT reset destination packet properties \param pck_src source packet \param pck_dst destination packet @@ -3575,6 +4215,8 @@ that the packet is a PATCH packet, replacing bytes located at gf_filter_pck_get_ inserting bytes located at gf_filter_pck_get_byte_offset in file if the interlaced flag of the packet is set. If the corrupted flag is set, this indicates the data will be replaced later on. A seek packet is not meant to be displayed but is needed for decoding. +\note If a packet is partially skiped but completely decoded, it shall not be marked as seek but have the property "SkipBegin" set. +\note Raw audio packets MUST be split at the proper boundary \param pck target packet \param is_seek indicates packet is seek frame \return error code if any @@ -3663,16 +4305,16 @@ GF_FilterClockType gf_filter_pid_get_clock_info(GF_FilterPid *PID, u64 *clock_va */ GF_FilterClockType gf_filter_pck_get_clock_type(GF_FilterPacket *pck); -/*! Sets packet carrousel info +/*! Sets packet carousel info \param pck target packet -\param version_number carrousel version number associated with this data chunk +\param version_number carousel version number associated with this data chunk \return error code if any */ GF_Err gf_filter_pck_set_carousel_version(GF_FilterPacket *pck, u8 version_number); -/*! Gets packet carrousel info +/*! Gets packet carousel info \param pck target packet -\return version_number carrousel version number associated with this data chunk +\return version_number carousel version number associated with this data chunk */ u8 gf_filter_pck_get_carousel_version(GF_FilterPacket *pck); @@ -3724,7 +4366,7 @@ GF_Err gf_filter_pck_set_seq_num(GF_FilterPacket *pck, u32 seq_num); /*! Gets packet sequence number info \param pck target packet -\return version_number carrousel version number associated with this data chunk +\return sequence number associated with this packet */ u32 gf_filter_pck_get_seq_num(GF_FilterPacket *pck); @@ -3786,7 +4428,7 @@ GF_FilterPacket *gf_filter_pck_new_frame_interface(GF_FilterPid *PID, GF_FilterF /*! Gets a frame interface associated with a packet if any. -Consummers will typically first check if the packet has associated data using \ref gf_filter_pck_get_data. +Consumers will typically first check if the packet has associated data using \ref gf_filter_pck_get_data. \param pck the target packet \return the associated frame interface object if any, or NULL otherwise @@ -3801,6 +4443,79 @@ This is typically used by sink filters to decide if they can hold references to */ Bool gf_filter_pck_is_blocking_ref(GF_FilterPacket *pck); +/*! @} */ + + +/*! +\addtogroup fs_props Filter Properties +\ingroup filters__cust_grp +\brief Custom Filter + +Custom filters are filters created by the app with no associated registry. +The app is responsible for assigning capabilities to the filter, and setting callback functions. +Each callback is optionnal, but a custom filter should at least have a process callback, and a configure_pid callback if not a source filter. + +Custom filters do not have any arguments exposed, and cannot be selected for sink or source filters. +If your app requires custom I/Os for source or sinks, use \ref GF_FileIO. +@{ + */ + +/*! Loads custom filter +\param session filter session +\param name name of filter to use - optional, may be NULL +\param flags flags for filter registry, currently only GF_FS_REG_MAIN_THREAD is used +\param e set to the error code if any - optional, may be NULL +\return filter or NULL if error +*/ +GF_Filter *gf_fs_new_filter(GF_FilterSession *session, const char *name, u32 flags, GF_Err *e); + +/*! Push a new capability for a custom filter +\param filter the target filter +\param code the capability code - cf \ref GF_FilterCapability +\param value the capability value - cf \ref GF_FilterCapability +\param name the capability name - cf \ref GF_FilterCapability +\param flags the capability flags - cf \ref GF_FilterCapability +\param priority the capability priority - cf \ref GF_FilterCapability +\return error if any + */ +GF_Err gf_filter_push_caps(GF_Filter *filter, u32 code, GF_PropertyValue *value, const char *name, u32 flags, u8 priority); + +/*! Set the process function for a custom filter +\param filter the target filter +\param process_cbk the process callback, may be NULL - cf process in \ref __gf_filter_register +\return error if any + */ +GF_Err gf_filter_set_process_ckb(GF_Filter *filter, GF_Err (*process_cbk)(GF_Filter *filter) ); + +/*! Set the PID configuration function for a custom filter +\param filter the target filter +\param configure_cbk the configure callback, may be NULL - cf configure_pid in \ref __gf_filter_register +\return error if any + */ +GF_Err gf_filter_set_configure_ckb(GF_Filter *filter, GF_Err (*configure_cbk)(GF_Filter *filter, GF_FilterPid *PID, Bool is_remove) ); + +/*! Set the process event function for a custom filter +\param filter the target filter +\param process_event_cbk the process event callback, may be NULL - cf process_event in \ref __gf_filter_register +\return error if any + */ +GF_Err gf_filter_set_process_event_ckb(GF_Filter *filter, Bool (*process_event_cbk)(GF_Filter *filter, const GF_FilterEvent *evt) ); + +/*! Set the reconfigure output function for a custom filter +\param filter the target filter +\param reconfigure_output_cbk the reconfigure callback, may be NULL - cf reconfigure_output_cbk in \ref __gf_filter_register +\return error if any + */ +GF_Err gf_filter_set_reconfigure_output_ckb(GF_Filter *filter, GF_Err (*reconfigure_output_cbk)(GF_Filter *filter, GF_FilterPid *PID) ); + +/*! Set the data prober function for a custom filter +\param filter the target filter +\param probe_data_cbk the data prober callback , may be NULL- cf probe_data in \ref __gf_filter_register +\return error if any + */ +GF_Err gf_filter_set_probe_data_cbk(GF_Filter *filter, const char * (*probe_data_cbk)(const u8 *data, u32 size, GF_FilterProbeScore *score) ); + + /*! @} */ #ifdef __cplusplus diff --git a/include/gpac/ietf.h b/include/gpac/ietf.h index 856e368..68c3b2b 100644 --- a/include/gpac/ietf.h +++ b/include/gpac/ietf.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project @@ -114,7 +114,7 @@ enum NC_RTSP_Option_not_support = 551, }; -/*! Gives string descritpion of error code +/*! Gives string description of error code \param ErrCode the RTSP error code \return the description of the RTSP error code */ @@ -139,7 +139,7 @@ typedef struct { } GF_RTSPRange; /*! parses a Range line and returns range header structure. This can be used for RTSP extension of SDP -Note: Only support for npt for now +\note Only support for npt for now \param range_buf the range string \return a newly allocated RTSP range */ @@ -293,6 +293,9 @@ typedef struct /*user data: this is never touched by the lib, its intend is to help stacking RTSP commands in your app*/ void *user_data; + /*user flags: this is never touched by the lib, its intend is to help stacking + RTSP commands in your app*/ + u32 user_flags; /* @@ -454,7 +457,7 @@ GF_Err gf_rtsp_set_buffer_size(GF_RTSPSession *sess, u32 BufferSize); /*! resets state machine, invalidate SessionID -NOTE: RFC2326 requires that the session is reseted when all RTP streams +\note RFC2326 requires that the session is reseted when all RTP streams are closed. As this lib doesn't maintain the number of valid streams you MUST call reset when all your streams are shutdown (either requested through TEARDOWN or signaled through RTCP BYE packets for RTP, or any other signaling means @@ -715,7 +718,7 @@ void gf_rtp_enable_nat_keepalive(GF_RTPChannel *ch, u32 nat_timeout); /*! initializes the RTP channel. \param ch the target RTP channel \param UDPBufferSize UDP stack buffer size if configurable by OS/ISP - ignored otherwise -NOTE: on WinCE devices, this is not configurable on an app bases but for the whole OS +\note On WinCE devices, this is not configurable on an app bases but for the whole OS you must update the device registry with: \code [HKEY_LOCAL_MACHINE\Comm\Afd] @@ -826,7 +829,8 @@ GF_Err gf_rtp_decode_rtcp(GF_RTPChannel *ch, u8 *pck, u32 pck_size, Bool *has_sr /*! computes and send Receiver report. If the channel is a TCP channel, you must specify -the callback function. NOTE: many RTP implementation do NOT process RTCP info received on TCP... +the callback function. +\note Many RTP implementation do NOT process RTCP info received on TCP... the lib will decide whether the report shall be sent or not, therefore you should call this function at regular times \param ch the target RTP channel @@ -925,7 +929,7 @@ void gf_rtp_get_ports(GF_RTPChannel *ch, u16 *rtp_port, u16 *rtcp_port); SDP LIBRARY EXPORTS - Note: SDP is mainly a text protocol with + SDP is mainly a text protocol with well defined containers. The following structures are used to write / read SDP informations, and the library also provides consistency checking @@ -1053,10 +1057,10 @@ typedef struct u32 PortNumber; /*number of ports described. If >= 2, the next media(s) in the SDP will be configured to use the next tuple (for RTP). If 0 or 1, ignored - Note: this is used for scalable media: PortNumber indicates the port of the base + \note This is used for scalable media: PortNumber indicates the port of the base media and NumPorts the ports||total number of the upper layers*/ u32 NumPorts; - /*currently ony "RTP/AVP" and "udp" defined*/ + /*currently only "RTP/AVP" and "udp" defined*/ char *Profile; /*list of GF_SDPConnection's. A media can have several connection in case of scalable content*/ @@ -1069,7 +1073,7 @@ typedef struct GF_List *FMTP; /*for RTP this is PayloadType, but can be opaque (string) depending on the app. - Formated as XX WW QQ FF + Formatted as XX WW QQ FF When reading the SDP, the payloads defined in RTPMap are removed from this list When writing the SDP for RTP, you should only specify static payload types here, as dynamic ones are stored in RTPMaps and automatically written*/ @@ -1153,7 +1157,7 @@ typedef struct GF_SDPInfo *gf_sdp_info_new(); /*! destrucs an SDP info Memory Consideration: the destructors free all non-NULL string. You should therefore - be carefull while (de-)assigning the strings. The function gf_sdp_info_parse() performs a complete + be careful while (de-)assigning the strings. The function gf_sdp_info_parse() performs a complete reset of the GF_SDPInfo \param sdp the target SDP to destroy @@ -1397,13 +1401,15 @@ enum GF_RTP_PAYT_AC3, /*use H264-SVC transport*/ GF_RTP_PAYT_H264_SVC, - /*use HEVC/H265 transport - no RFC yet, only draft*/ + /*use HEVC/H265 transport (RFC 7798)*/ GF_RTP_PAYT_HEVC, GF_RTP_PAYT_LHVC, #if GPAC_ENABLE_3GPP_DIMS_RTP /*use 3GPP DIMS format*/ GF_RTP_PAYT_3GPP_DIMS, #endif + /*use VVC transport (no RFC yet)*/ + GF_RTP_PAYT_VVC, }; @@ -1464,7 +1470,7 @@ void gf_rtp_builder_del(GP_RTPPacketizer *builder); \param avgSize average size of an AU. This is not always known (real-time encoding). In this case you should specify a rough compute indicating how many packets could be stored per RTP packet. for ex AAC stereo at 44100 k / 64kbps , one AU ~= 380 bytes -so 3 AUs for 1500 MTU is ok - BE CAREFULL: MultiSL adds some SL info on top of the 12 +so 3 AUs for 1500 MTU is ok - BE CAREFUL: MultiSL adds some SL info on top of the 12 byte RTP header so you should specify a smaller size The packetizer will ALWAYS make sure there's no pb storing the packets so specifying more will result in a slight overhead in the SL mapping but the gain to singleSL diff --git a/include/gpac/internal/avilib.h b/include/gpac/internal/avilib.h index accc4a8..5d31166 100644 --- a/include/gpac/internal/avilib.h +++ b/include/gpac/internal/avilib.h @@ -308,6 +308,10 @@ typedef struct #define IBM_FORMAT_MULAW (0x0101) #define IBM_FORMAT_ALAW (0x0102) #define IBM_FORMAT_ADPCM (0x0103) +#define WAVE_FORMAT_MP3 (0x0055) +#define WAVE_FORMAT_AAC_ADTS (0x706d) +#define WAVE_FORMAT_AAC (0x00FF) +#define WAVE_FORMAT_AC3 (0x2000) avi_t* AVI_open_output_file(char * filename, u64 opendml_threshold); void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor); diff --git a/include/gpac/internal/bifs_dev.h b/include/gpac/internal/bifs_dev.h index 5860a5f..2adcfa5 100644 --- a/include/gpac/internal/bifs_dev.h +++ b/include/gpac/internal/bifs_dev.h @@ -44,8 +44,8 @@ typedef struct { GF_Node *node; /*in case node is not defined yet*/ u32 node_id; - /*the rest is not needed at the current time, we only support simple sugnaling for FDP, BDP and IFS2D - which are using pre-defs masks*/ + /*the rest is not needed at the current time, we only support simple signaling for FDP, BDP and IFS2D + which are using predefined masks*/ } BIFSElementaryMask; typedef struct @@ -83,6 +83,7 @@ typedef struct /*per_stream config support*/ typedef struct { + //node is registered with NULL as parent GF_Node *node; SFCommandBuffer *cb; } CommandBufferItem; @@ -142,7 +143,7 @@ GF_Err gf_bifs_dec_field(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node /*decodes a route*/ GF_Err gf_bifs_dec_route(GF_BifsDecoder * codec, GF_BitStream *bs, Bool is_insert); /*get name*/ -void gf_bifs_dec_name(GF_BitStream *bs, char *name); +void gf_bifs_dec_name(GF_BitStream *bs, char *name, u32 size); BIFSStreamInfo *gf_bifs_dec_get_stream(GF_BifsDecoder * codec, u16 ESID); /*decodes a BIFS command frame*/ diff --git a/include/gpac/internal/compositor_dev.h b/include/gpac/internal/compositor_dev.h index 23d3a44..d56f9de 100644 --- a/include/gpac/internal/compositor_dev.h +++ b/include/gpac/internal/compositor_dev.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2018 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Scene Rendering sub-project @@ -150,6 +150,12 @@ typedef struct #define DOUBLECLICK_TIME_MS 250 +enum +{ + TILE_DEBUG_NONE=0, + TILE_DEBUG_PARTIAL, + TILE_DEBUG_FULL +}; enum { @@ -205,6 +211,9 @@ struct __tag_compositor u32 drv; GF_Err last_error; + //filter mode, we can be a source for our built-in URLs + char *src; + /*audio renderer*/ struct _audio_render *audio_renderer; /*video out*/ @@ -242,7 +251,7 @@ struct __tag_compositor GF_List *textures; Bool texture_inserted; - /*all textures to be destroyed (needed for openGL context ...)*/ + /*all textures to be destroyed (needed for OpenGL context ...)*/ GF_List *textures_gc; /*event queue*/ @@ -270,6 +279,8 @@ struct __tag_compositor Bool bench_mode; //0: no frame pending, 1: frame pending, needs clock increase, 2: frames are pending but one frame has been decoded, do not increase clock u32 force_bench_frame; + //number of audio frames sent in call to send_frame + u32 audio_frames_sent; u32 frame_time[GF_SR_FPS_COMPUTE_SIZE]; u32 frame_dur[GF_SR_FPS_COMPUTE_SIZE]; @@ -290,7 +301,7 @@ struct __tag_compositor Bool amc, async; u32 asr, ach, alayout, afmt, asize, avol, apan, abuf; Double max_aspeed, max_vspeed; - u32 buf, rbuf, mbuf, ntpsync; + u32 buffer, rbuffer, mbuffer, ntpsync; u32 ogl, mode2d; @@ -358,6 +369,8 @@ struct __tag_compositor /*count number of initialized sensors*/ u32 interaction_sensors; + //in player mode, exit if set + //in non player mode, check for eos u32 check_eos_state; u32 last_check_pass; @@ -427,7 +440,7 @@ struct __tag_compositor /*to copy!*/ u32 nbviews, stereo, camlay; - Bool rview; + Bool rview, dbgpack; Fixed dispdist; char *mvshader; @@ -582,7 +595,7 @@ struct __tag_compositor If not set video is written through glDrawPixels with bitmap (slow scaling), or converted to po2 texture*/ Bool epow2; - /*use openGL for outline rather than vectorial ones*/ + /*use OpenGL for outline rather than vectorial ones*/ Bool linegl; /*disable RECT extensions (except for Bitmap...)*/ Bool rext; @@ -643,8 +656,8 @@ struct __tag_compositor u8 *screen_buffer, *line_buffer; u32 screen_buffer_alloc_size; - u32 tvtn, tvtt; - Bool tvtd, tvtf; + u32 tvtn, tvtt, tvtd; + Bool tvtf; u32 vrhud_mode; Fixed fov; @@ -1124,7 +1137,7 @@ struct _traversing_state /*layer traversal state: set to the first traversed layer3D when picking - set to the current layer3D traversed when rendering 3D to an offscreen bitmap. This alows other + set to the current layer3D traversed when rendering 3D to an offscreen bitmap. This allows other nodes (typically bindables) seting the layer dirty flags to force a redraw */ GF_Node *layer3d; @@ -1176,6 +1189,7 @@ typedef struct _audiointerface Bool forced_layout; //updated at each frame, used if frame fetch returns NULL Bool is_buffering; + Bool is_eos; } GF_AudioInterface; typedef struct __audiomix GF_AudioMixer; @@ -1198,14 +1212,15 @@ Bool gf_mixer_reconfig(GF_AudioMixer *am); /*retrieves mixer cfg*/ void gf_mixer_get_config(GF_AudioMixer *am, u32 *outSR, u32 *outCH, u32 *outFMT, u64 *outChCfg); /*called by audio renderer in case the hardware used a different setup than requested*/ -void gf_mixer_set_config(GF_AudioMixer *am, u32 outSR, u32 outCH, u32 outFMT, u64 ch_cfg); +GF_Err gf_mixer_set_config(GF_AudioMixer *am, u32 outSR, u32 outCH, u32 outFMT, u64 ch_cfg); Bool gf_mixer_is_src_present(GF_AudioMixer *am, GF_AudioInterface *ifce); u32 gf_mixer_get_src_count(GF_AudioMixer *am); -void gf_mixer_force_chanel_out(GF_AudioMixer *am, u32 num_channels); +GF_Err gf_mixer_force_channel_out(GF_AudioMixer *am, u32 num_channels); u32 gf_mixer_get_block_align(GF_AudioMixer *am); Bool gf_mixer_must_reconfig(GF_AudioMixer *am); Bool gf_mixer_empty(GF_AudioMixer *am); Bool gf_mixer_buffering(GF_AudioMixer *am); +Bool gf_mixer_is_eos(GF_AudioMixer *am); //#define ENABLE_AOUT @@ -1245,8 +1260,8 @@ typedef struct _audio_render u32 audio_delay, volume, pan, mute; - //set when output is not realtime - Bool non_rt_output; + //set when output is not realtime - set to 2 will indicate end of session + u32 non_rt_output; Fixed yaw, pitch, roll; @@ -1495,7 +1510,9 @@ enum /*span is in the current text selection*/ GF_TEXT_SPAN_RIGHT_TO_LEFT = 1<<3, /*span is in the current text selection*/ - GF_TEXT_SPAN_SELECTED = 1<<4 + GF_TEXT_SPAN_SELECTED = 1<<4, + /*span is strikeout*/ + GF_TEXT_SPAN_STRIKEOUT = 1<<5 }; typedef struct __text_span @@ -1633,7 +1650,7 @@ GF_SceneNamespace *gf_scene_ns_new(GF_Scene *scene, GF_ObjectManager *owner, con /*destroy service*/ void gf_scene_ns_del(GF_SceneNamespace *ns, GF_Scene *scene); -void gf_scene_ns_connect_object(GF_Scene *scene, GF_ObjectManager *odm, char *serviceURL, char *parent_url); +void gf_scene_ns_connect_object(GF_Scene *scene, GF_ObjectManager *odm, char *serviceURL, char *parent_url, GF_SceneNamespace *parent_ns); @@ -1656,7 +1673,7 @@ struct _gf_scene both external resources (urls) and ODs sent in MPEG-4 systems*/ GF_List *resources; - /*list of GF_MediaObject - these are the links betwwen scene nodes (URL, xlink:href) and media resources. + /*list of GF_MediaObject - these are the links between scene nodes (URL, xlink:href) and media resources. We need this link because of MPEG-4 Systems, where an OD (media resource) can be removed or replaced by the server without the scene being modified*/ GF_List *scene_objects; @@ -1780,10 +1797,10 @@ Bool gf_scene_is_root(GF_Scene *scene); void gf_scene_remove_object(GF_Scene *scene, GF_ObjectManager *odm, u32 for_shutdown); /*browse all (media) channels and send buffering info to the app*/ -void gf_scene_buffering_info(GF_Scene *scene); +void gf_scene_buffering_info(GF_Scene *scene, Bool rebuffer_done); void gf_scene_attach_to_compositor(GF_Scene *scene); struct _mediaobj *gf_scene_get_media_object(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines); -struct _mediaobj *gf_scene_get_media_object_ex(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines, struct _mediaobj *sync_ref, Bool force_new_if_not_attached, GF_Node *node_ptr); +struct _mediaobj *gf_scene_get_media_object_ex(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines, struct _mediaobj *sync_ref, Bool force_new_if_not_attached, GF_Node *node_ptr, GF_Scene *original_parent_scene); void gf_scene_setup_object(GF_Scene *scene, GF_ObjectManager *odm); /*updates scene duration based on sub objects*/ void gf_scene_set_duration(GF_Scene *scene); @@ -1817,7 +1834,7 @@ void gf_scene_force_size_to_video(GF_Scene *scene, GF_MediaObject *mo); //If @check_buffering is 1, returns 1 if no clock is buffering, 0 otheriwse Bool gf_scene_check_clocks(GF_SceneNamespace *ns, GF_Scene *scene, Bool check_buffering); -void gf_scene_notify_event(GF_Scene *scene, u32 event_type, GF_Node *n, void *dom_evt, GF_Err code, Bool no_queueing); +void gf_scene_notify_event(GF_Scene *scene, u32 event_type, GF_Node *n, void *dom_evt, GF_Err code, Bool no_queuing); void gf_scene_mpeg4_inline_restart(GF_Scene *scene); void gf_scene_mpeg4_inline_check_restart(GF_Scene *scene); @@ -1852,65 +1869,45 @@ void gf_inline_restart(GF_Scene *scene); Bool gf_mo_is_same_url(GF_MediaObject *obj, MFURL *an_url, Bool *keep_fragment, u32 obj_hint_type); void gf_mo_update_caps(GF_MediaObject *mo); +void gf_mo_update_caps_ex(GF_MediaObject *mo, Bool check_unchanged); const char *gf_scene_get_fragment_uri(GF_Node *node); void gf_scene_set_fragment_uri(GF_Node *node, const char *uri); -#if FILTER_FIXME - - -/*URI relocators are used for containers like zip or ISO FF with file items. The relocator -is in charge of translating the URI, potentially extracting the associated resource and sending -back the new (local or not) URI. Only the interface is defined, URI translators are free to derive from them - -relocate a URI - if NULL is returned, this relocator is not concerned with the URI -otherwise returns the translated URI -*/ - -#define GF_TERM_URI_RELOCATOR \ - Bool (*relocate_uri)(void *__self, const char *parent_uri, const char *uri, char *out_relocated_uri, char *out_localized_uri); \ - -typedef struct __gf_uri_relocator GF_URIRelocator; - -struct __gf_uri_relocator -{ - GF_TERM_URI_RELOCATOR -}; - +/*GF_NET_ASSOCIATED_CONTENT_TIMING*/ typedef struct { - GF_TERM_URI_RELOCATOR - GF_Terminal *term; - char *szAbsRelocatedPath; -} GF_TermLocales; - -#define MAX_SHORTCUTS 200 - -typedef struct -{ - u8 code; - u8 mods; - u8 action; -} GF_Shortcut; + u32 timeline_id; + u32 media_timescale; + u64 media_timestamp; + //for now only used in MPEG-2, so media_pts is in 90khz scale + u64 media_pts; + Bool force_reload; + Bool is_paused; + Bool is_discontinuity; + u64 ntp; +} GF_AssociatedContentTiming; typedef struct { - void *udta; - /*called when an event should be filtered - */ - Bool (*on_event)(void *udta, GF_Event *evt, Bool consumed_by_compositor); -} GF_TermEventFilter; - -GF_Err gf_term_add_event_filter(GF_Terminal *terminal, GF_TermEventFilter *ef); -GF_Err gf_term_remove_event_filter(GF_Terminal *terminal, GF_TermEventFilter *ef); + //negative values mean "timeline is ready no need for timing message" + s32 timeline_id; + const char *external_URL; + Bool is_announce, is_splicing; + Bool reload_external; + Bool enable_if_defined; + Bool disable_if_defined; + GF_Fraction activation_countdown; + //start and end times of splicing if any + Double splice_start_time, splice_end_time; + Bool splice_time_pts; +} GF_AssociatedContentLocation; void gf_scene_register_associated_media(GF_Scene *scene, GF_AssociatedContentLocation *addon_info); void gf_scene_notify_associated_media_timeline(GF_Scene *scene, GF_AssociatedContentTiming *addon_time); -#endif - /*clock*/ struct _object_clock @@ -2032,6 +2029,10 @@ enum /*flag indicates the odm is a target passthrough*/ GF_ODM_PASSTHROUGH = (1<<15), + /*flag indicates the clock is shared between tiles and a play should not trigger a rebuffer*/ + GF_ODM_TILED_SHARED_CLOCK = (1<<16), + /*flag indicates TEMI info is associated with PID*/ + GF_ODM_HAS_TEMI = (1<<17), }; enum @@ -2084,6 +2085,9 @@ struct _od_manager u32 ID; u32 pid_id; //esid for clock solving + //MPEG-4 OD descriptor + GF_ObjectDescriptor *OD; + //parent service ID as defined from input u32 ServiceID; Bool hybrid_layered_coded; @@ -2094,7 +2098,7 @@ struct _od_manager Bool clock_inherited; //0 or 1, except for IOD where we may have several BIFS/OD streams u32 nb_buffering, nb_rebuffer; - u32 buffer_max_us, buffer_min_us, buffer_playout_us; + u32 buffer_max_ms, buffer_min_ms, buffer_playout_ms; Bool blocking_media; //internal hash for source allowing to distinguish input PIDs sources @@ -2128,7 +2132,8 @@ struct _od_manager u32 timeshift_depth; u32 action_type; - s32 delay; + //delay in PID timescale + s64 timestamp_offset; Fixed set_speed; Bool disable_buffer_at_next_play; @@ -2139,7 +2144,7 @@ struct _od_manager #ifndef GPAC_DISABLE_VRML /*the one and only media control currently attached to this object*/ struct _media_control *media_ctrl; - /*the list of media control controling the object*/ + /*the list of media control controlling the object*/ GF_List *mc_stack; /*the media sensor(s) attached to this object*/ GF_List *ms_stack; @@ -2149,8 +2154,6 @@ struct _od_manager GF_AddonMedia *addon; //set for objects splicing the main content, indicates the media type (usually in @codec but no codec created for splicing) u32 splice_addon_mtype; - //set to true if this is a scalable addon for an existing object - Bool scalable_addon; //for a regular ODM, this indicates that the current scalable_odm associated struct _od_manager *upper_layer_odm; @@ -2175,7 +2178,7 @@ void gf_odm_del(GF_ObjectManager *ODMan); /*setup OD*/ void gf_odm_setup_object(GF_ObjectManager *odm, GF_SceneNamespace *parent_ns, GF_FilterPid *for_pid); -void gf_odm_setup_remote_object(GF_ObjectManager *odm, GF_SceneNamespace *parent_ns, char *remote_url); +void gf_odm_setup_remote_object(GF_ObjectManager *odm, GF_SceneNamespace *parent_ns, char *remote_url, Bool for_addon); /*disctonnect OD and removes it if desired (otherwise only STOP is propagated)*/ void gf_odm_disconnect(GF_ObjectManager *odman, u32 do_remove); @@ -2226,6 +2229,8 @@ void gf_odm_reset_media_control(GF_ObjectManager *odm, Bool signal_reset); void gf_odm_check_clock_mediatime(GF_ObjectManager *odm); +void gf_odm_addon_setup(GF_ObjectManager *odm); + /*! * Media Object types @@ -2255,6 +2260,17 @@ enum /*! All Media Objects inserted through URLs and not MPEG-4 OD Framework use this ODID*/ #define GF_MEDIA_EXTERNAL_ID 1050 +enum +{ + //no connection error, no frames seen in input pipeline + MO_CONNECT_OK=0, + //no connection error, frames seen in input pipeline but no frame yet available for object + MO_CONNECT_BUFFERING, + //explicit source setup failure + MO_CONNECT_FAILED, + //timeout of input pipeline (no frames seen after compositor->timeout ms) + MO_CONNECT_TIMEOUT +}; /*GF_MediaObject: link between real object manager and scene. although there is a one-to-one mapping between a MediaObject and an ObjectManager, we have to keep them separated in order to handle OD remove commands which destroy @@ -2320,6 +2336,7 @@ struct _mediaobj u64 channel_config; Bool planar_audio; u32 srd_x, srd_y, srd_w, srd_h, srd_full_w, srd_full_h; + u32 flip, rotate; u32 quality_degradation_hint; u32 nb_views; @@ -2327,7 +2344,8 @@ struct _mediaobj u32 view_min_x, view_max_x, view_min_y, view_max_y; GF_FilterFrameInterface *frame_ifce; - Bool connect_failure; + Float c_x, c_y, c_w, c_h; + u32 connect_state; }; GF_MediaObject *gf_mo_new(); @@ -2335,7 +2353,7 @@ GF_MediaObject *gf_mo_new(); /*media access events */ void gf_odm_service_media_event(GF_ObjectManager *odm, GF_EventType event_type); -void gf_odm_service_media_event_with_download(GF_ObjectManager *odm, GF_EventType event_type, u64 loaded_size, u64 total_size, u32 bytes_per_sec); +void gf_odm_service_media_event_with_download(GF_ObjectManager *odm, GF_EventType event_type, u64 loaded_size, u64 total_size, u32 bytes_per_sec, u32 buffer_level_plus_one, u32 min_buffer_time); /*checks the URL and returns the ODID (MPEG-4 od://) or GF_MEDIA_EXTERNAL_ID for all regular URLs*/ u32 gf_mo_get_od_id(MFURL *url); @@ -2353,8 +2371,8 @@ void gf_scene_message_ex(GF_Scene *scene, const char *service, const char *messa //returns media time in sec for the addon - timestamp_based is set to 1 if no timeline has been found (eg sync is based on direct timestamp comp) Double gf_scene_adjust_time_for_addon(GF_AddonMedia *addon, Double clock_time, u8 *timestamp_based); -s64 gf_scene_adjust_timestamp_for_addon(GF_AddonMedia *addon, u64 orig_ts); -void gf_scene_select_scalable_addon(GF_Scene *scene, GF_ObjectManager *odm); +s64 gf_scene_adjust_timestamp_for_addon(GF_AddonMedia *addon, u64 orig_ts_ms); + /*check if the associated addon has to be restarted, based on the timestamp of the main media (used for scalable addons only). Returns 1 if the addon has been restarted*/ Bool gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts); @@ -2423,8 +2441,8 @@ void gf_scene_set_service_id(GF_Scene *scene, u32 service_id); /*post extended user mouse interaction to terminal X and Y are point coordinates in the display expressed in 2D coord system top-left (0,0), Y increasing towards bottom - @xxx_but_down: specifiy whether the mouse button is down(2) or up (1), 0 if unchanged - @wheel: specifiy current wheel inc (0: unchanged , +1 for one wheel delta forward, -1 for one wheel delta backward) + @xxx_but_down: specify whether the mouse button is down(2) or up (1), 0 if unchanged + @wheel: specify current wheel inc (0: unchanged , +1 for one wheel delta forward, -1 for one wheel delta backward) */ /*NOT NEEDED WHEN THE TERMINAL IS HANDLING THE DISPLAY WINDOW (cf user.h)*/ void gf_sc_input_sensor_mouse_input(GF_Compositor *compositor, GF_EventMouse *event); @@ -2516,7 +2534,7 @@ typedef struct _media_control /*stream object list (segments)*/ GF_List *seg; - /*current active segment index (ie, controling the PLAY range of the media)*/ + /*current active segment index (ie, controlling the PLAY range of the media)*/ u32 current_seg; } MediaControlStack; void InitMediaControl(GF_Scene *scene, GF_Node *node); diff --git a/include/gpac/internal/ietf_dev.h b/include/gpac/internal/ietf_dev.h index 0a4e808..d8642a6 100644 --- a/include/gpac/internal/ietf_dev.h +++ b/include/gpac/internal/ietf_dev.h @@ -446,6 +446,10 @@ GF_Err gp_rtp_builder_do_latm(GP_RTPPacketizer *builder, u8 *data, u32 data_size GF_Err gp_rtp_builder_do_ac3(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize); GF_Err gp_rtp_builder_do_hevc(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize); GF_Err gp_rtp_builder_do_mp2t(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize); +GF_Err gp_rtp_builder_do_vvc(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize); + +#define RTP_VVC_AGG_NAL 0x1C //28 +#define RTP_VVC_FRAG_NAL 0x1D //29 /*! RTP depacketization tool*/ struct __tag_rtp_depacketizer diff --git a/include/gpac/internal/isomedia_dev.h b/include/gpac/internal/isomedia_dev.h index 3a18910..b39a58f 100644 --- a/include/gpac/internal/isomedia_dev.h +++ b/include/gpac/internal/isomedia_dev.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2012 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / ISO Media File Format sub-project @@ -86,6 +86,7 @@ enum GF_ISOM_BOX_TYPE_UDTA = GF_4CC( 'u', 'd', 't', 'a' ), GF_ISOM_BOX_TYPE_VMHD = GF_4CC( 'v', 'm', 'h', 'd' ), GF_ISOM_BOX_TYPE_FTYP = GF_4CC( 'f', 't', 'y', 'p' ), + GF_ISOM_BOX_TYPE_OTYP = GF_4CC( 'o', 't', 'y', 'p' ), GF_ISOM_BOX_TYPE_PADB = GF_4CC( 'p', 'a', 'd', 'b' ), GF_ISOM_BOX_TYPE_PDIN = GF_4CC( 'p', 'd', 'i', 'n' ), GF_ISOM_BOX_TYPE_SDTP = GF_4CC( 's', 'd', 't', 'p' ), @@ -98,6 +99,7 @@ enum GF_ISOM_BOX_TYPE_MFRA = GF_4CC( 'm', 'f', 'r', 'a' ), GF_ISOM_BOX_TYPE_MFRO = GF_4CC( 'm', 'f', 'r', 'o' ), GF_ISOM_BOX_TYPE_TFRA = GF_4CC( 't', 'f', 'r', 'a' ), + GF_ISOM_BOX_TYPE_CSGP = GF_4CC( 'c', 's', 'g', 'p'), GF_ISOM_BOX_TYPE_TENC = GF_4CC( 't', 'e', 'n', 'c' ), @@ -191,6 +193,12 @@ enum GF_ISOM_BOX_TYPE_LHVC = GF_4CC( 'l', 'h', 'v', 'C' ), + GF_ISOM_BOX_TYPE_VVC1 = GF_4CC( 'v', 'v', 'c', '1' ), + GF_ISOM_BOX_TYPE_VVI1 = GF_4CC( 'v', 'v', 'i', '1' ), + GF_ISOM_BOX_TYPE_VVCC = GF_4CC( 'v', 'v', 'c', 'C' ), + GF_ISOM_BOX_TYPE_VVS1 = GF_4CC( 'v', 'v', 's', '1' ), + GF_ISOM_BOX_TYPE_VVNC = GF_4CC( 'v', 'v', 'n', 'C' ), + GF_ISOM_BOX_TYPE_AV1C = GF_4CC('a', 'v', '1', 'C'), GF_ISOM_BOX_TYPE_AV01 = GF_4CC('a', 'v', '0', '1'), @@ -336,28 +344,6 @@ enum /* Apple extensions */ GF_ISOM_BOX_TYPE_ILST = GF_4CC( 'i', 'l', 's', 't' ), - GF_ISOM_BOX_TYPE_0xA9NAM = GF_4CC( 0xA9, 'n', 'a', 'm' ), - GF_ISOM_BOX_TYPE_0xA9CMT = GF_4CC( 0xA9, 'c', 'm', 't' ), - GF_ISOM_BOX_TYPE_0xA9DAY = GF_4CC( 0xA9, 'd', 'a', 'y' ), - GF_ISOM_BOX_TYPE_0xA9ART = GF_4CC( 0xA9, 'A', 'R', 'T' ), - GF_ISOM_BOX_TYPE_0xA9TRK = GF_4CC( 0xA9, 't', 'r', 'k' ), - GF_ISOM_BOX_TYPE_0xA9ALB = GF_4CC( 0xA9, 'a', 'l', 'b' ), - GF_ISOM_BOX_TYPE_0xA9COM = GF_4CC( 0xA9, 'c', 'o', 'm' ), - GF_ISOM_BOX_TYPE_0xA9WRT = GF_4CC( 0xA9, 'w', 'r', 't' ), - GF_ISOM_BOX_TYPE_0xA9TOO = GF_4CC( 0xA9, 't', 'o', 'o' ), - GF_ISOM_BOX_TYPE_0xA9CPY = GF_4CC( 0xA9, 'c', 'p', 'y' ), - GF_ISOM_BOX_TYPE_0xA9DES = GF_4CC( 0xA9, 'd', 'e', 's' ), - GF_ISOM_BOX_TYPE_0xA9GEN = GF_4CC( 0xA9, 'g', 'e', 'n' ), - GF_ISOM_BOX_TYPE_0xA9GRP = GF_4CC( 0xA9, 'g', 'r', 'p' ), - GF_ISOM_BOX_TYPE_0xA9ENC = GF_4CC( 0xA9, 'e', 'n', 'c' ), - GF_ISOM_BOX_TYPE_aART = GF_4CC( 'a', 'A', 'R', 'T' ), - GF_ISOM_BOX_TYPE_PGAP = GF_4CC( 'p', 'g', 'a', 'p' ), - GF_ISOM_BOX_TYPE_GNRE = GF_4CC( 'g', 'n', 'r', 'e' ), - GF_ISOM_BOX_TYPE_DISK = GF_4CC( 'd', 'i', 's', 'k' ), - GF_ISOM_BOX_TYPE_TRKN = GF_4CC( 't', 'r', 'k', 'n' ), - GF_ISOM_BOX_TYPE_TMPO = GF_4CC( 't', 'm', 'p', 'o' ), - GF_ISOM_BOX_TYPE_CPIL = GF_4CC( 'c', 'p', 'i', 'l' ), - GF_ISOM_BOX_TYPE_COVR = GF_4CC( 'c', 'o', 'v', 'r' ), GF_ISOM_BOX_TYPE_iTunesSpecificInfo = GF_4CC( '-', '-', '-', '-' ), GF_ISOM_BOX_TYPE_DATA = GF_4CC( 'd', 'a', 't', 'a' ), @@ -385,7 +371,14 @@ enum GF_ISOM_BOX_TYPE_EC3 = GF_4CC( 'e', 'c', '-', '3' ), GF_ISOM_BOX_TYPE_DEC3 = GF_4CC( 'd', 'e', 'c', '3' ), GF_ISOM_BOX_TYPE_DVCC = GF_4CC( 'd', 'v', 'c', 'C' ), + GF_ISOM_BOX_TYPE_DVVC = GF_4CC( 'd', 'v', 'v', 'C' ), + GF_ISOM_BOX_TYPE_DVH1 = GF_4CC( 'd', 'v', 'h', '1' ), GF_ISOM_BOX_TYPE_DVHE = GF_4CC( 'd', 'v', 'h', 'e' ), + GF_ISOM_BOX_TYPE_DVA1 = GF_4CC( 'd', 'v', 'a', '1' ), + GF_ISOM_BOX_TYPE_DVAV = GF_4CC( 'd', 'v', 'a', 'v' ), + GF_ISOM_BOX_TYPE_DAV1 = GF_4CC( 'd', 'a', 'v', '1' ), + GF_ISOM_BOX_TYPE_MLPA = GF_4CC( 'm', 'l', 'p', 'a' ), + GF_ISOM_BOX_TYPE_DMLP = GF_4CC( 'd', 'm', 'l', 'p' ), GF_ISOM_BOX_TYPE_SUBS = GF_4CC( 's', 'u', 'b', 's' ), @@ -406,6 +399,7 @@ enum GF_ISOM_BOX_TYPE_STXT = GF_4CC( 's', 't', 'x', 't' ), GF_ISOM_BOX_TYPE_TXTC = GF_4CC( 't', 'x', 't', 'C' ), + GF_ISOM_BOX_TYPE_MIME = GF_4CC( 'm', 'i', 'm', 'e' ), GF_ISOM_BOX_TYPE_PRFT = GF_4CC( 'p', 'r', 'f', 't' ), @@ -415,6 +409,7 @@ enum GF_ISOM_BOX_TYPE_PIXI = GF_4CC( 'p', 'i', 'x', 'i' ), GF_ISOM_BOX_TYPE_RLOC = GF_4CC( 'r', 'l', 'o', 'c' ), GF_ISOM_BOX_TYPE_IROT = GF_4CC( 'i', 'r', 'o', 't' ), + GF_ISOM_BOX_TYPE_IMIR = GF_4CC( 'i', 'm', 'i', 'r' ), GF_ISOM_BOX_TYPE_IPCO = GF_4CC( 'i', 'p', 'c', 'o' ), GF_ISOM_BOX_TYPE_IPRP = GF_4CC( 'i', 'p', 'r', 'p' ), GF_ISOM_BOX_TYPE_IPMA = GF_4CC( 'i', 'p', 'm', 'a' ), @@ -424,11 +419,17 @@ enum GF_ISOM_BOX_TYPE_AUXI = GF_4CC( 'a', 'u', 'x', 'i' ), GF_ISOM_BOX_TYPE_OINF = GF_4CC( 'o', 'i', 'n', 'f' ), GF_ISOM_BOX_TYPE_TOLS = GF_4CC( 't', 'o', 'l', 's' ), + GF_ISOM_BOX_TYPE_IENC = GF_4CC( 'i', 'e', 'n', 'c' ), + GF_ISOM_BOX_TYPE_IAUX = GF_4CC('i', 'a', 'u', 'x'), /* MIAF Boxes */ GF_ISOM_BOX_TYPE_CLLI = GF_4CC('c', 'l', 'l', 'i'), GF_ISOM_BOX_TYPE_MDCV = GF_4CC('m', 'd', 'c', 'v'), + /* AVIF Boxes */ + GF_ISOM_BOX_TYPE_A1LX = GF_4CC('a', '1', 'l', 'x'), + GF_ISOM_BOX_TYPE_A1OP = GF_4CC('a', '1', 'o', 'p'), + GF_ISOM_BOX_TYPE_ALTR = GF_4CC( 'a', 'l', 't', 'r' ), /*ALL INTERNAL BOXES - NEVER WRITTEN TO FILE!!*/ @@ -496,6 +497,7 @@ enum GF_ISOM_BOX_TYPE_MHM1 = GF_4CC('m','h','m','1'), GF_ISOM_BOX_TYPE_MHM2 = GF_4CC('m','h','m','2'), GF_ISOM_BOX_TYPE_MHAC = GF_4CC('m','h','a','C'), + GF_ISOM_BOX_TYPE_MHAP = GF_4CC('m','h','a','P'), GF_ISOM_BOX_TYPE_IPCM = GF_4CC('i','p','c','m'), GF_ISOM_BOX_TYPE_FPCM = GF_4CC('f','p','c','m'), @@ -512,16 +514,36 @@ enum GF_QT_SUBTYPE_RAW_AUD = GF_4CC('Q','T','R','A'), GF_QT_SUBTYPE_RAW_VID = GF_4CC('Q','T','R','V'), + GF_ISOM_BOX_TYPE_XTRA = GF_4CC( 'X', 't', 'r', 'a' ), + + GF_ISOM_BOX_TYPE_ST3D = GF_4CC( 's', 't', '3', 'd' ), + GF_ISOM_BOX_TYPE_SV3D = GF_4CC( 's', 'v', '3', 'd' ), + GF_ISOM_BOX_TYPE_SVHD = GF_4CC( 's', 'v', 'h', 'd' ), + GF_ISOM_BOX_TYPE_PROJ = GF_4CC( 'p', 'r', 'o', 'j' ), + GF_ISOM_BOX_TYPE_PRHD = GF_4CC( 'p', 'r', 'h', 'd' ), + GF_ISOM_BOX_TYPE_CBMP = GF_4CC( 'c', 'b', 'm', 'p' ), + GF_ISOM_BOX_TYPE_EQUI = GF_4CC( 'e', 'q', 'u', 'i' ), + GF_ISOM_BOX_TYPE_MSHP = GF_4CC( 'm', 's', 'h', 'p' ), + GF_ISOM_BOX_TYPE_MESH = GF_4CC( 'm', 'e', 's', 'h' ), + + GF_ISOM_BOX_TYPE_AVCE = GF_4CC( 'a', 'v', 'c', 'E' ), + GF_ISOM_BOX_TYPE_HVCE = GF_4CC( 'h', 'v', 'c', 'E' ), + + //opaque data container + GF_ISOM_BOX_TYPE_GDAT = GF_4CC( 'g', 'd', 'a', 't' ), }; enum { - GF_ISOM_SAMPLE_ENTRY_UNKN = 0, + //can be safely type-casted to sample entry + GF_ISOM_SAMPLE_ENTRY_GENERIC = 0, + //can be safely type-casted to Video sample entry GF_ISOM_SAMPLE_ENTRY_VIDEO = GF_4CC('v','i','d','e'), + //can be safely type-casted to Audio sample entry GF_ISOM_SAMPLE_ENTRY_AUDIO = GF_4CC('a','u','d','i'), - GF_ISOM_SAMPLE_ENTRY_MP4S = GF_4CC('m','p','4','s') - + //can be safely type-casted to mpeg systems sample entry + GF_ISOM_SAMPLE_ENTRY_MP4S = GF_4CC('m','p','4','s'), }; @@ -542,6 +564,7 @@ enum //internal flags (up to 16) //if flag is set, position checking of child boxes is ignored #define GF_ISOM_ORDER_FREEZE 1 +#define GF_ISOM_BOX_COMPRESSED 2 /*the default size is 64, cause we need to handle large boxes... @@ -597,6 +620,21 @@ typedef struct }\ __ptr->size -= bytes; \ +#define ISOM_DECREASE_SIZE_GOTO_EXIT(__ptr, bytes) if (__ptr->size < (bytes) ) {\ + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[isom] not enough bytes in box %s: %d left, reading %d (file %s, line %d)\n", gf_4cc_to_str(__ptr->type), (u32) __ptr->size, (bytes), __FILE__, __LINE__ )); \ + e = GF_ISOM_INVALID_FILE; \ + goto exit;\ + }\ + __ptr->size -= bytes; \ + + +#define ISOM_DECREASE_SIZE_NO_ERR(__ptr, bytes) if (__ptr->size < (bytes) ) {\ + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[isom] not enough bytes in box %s: %d left, reading %d (file %s, line %d), skipping box\n", gf_4cc_to_str(__ptr->type), (u32) __ptr->size, (bytes), __FILE__, __LINE__ )); \ + return GF_OK; \ + }\ + __ptr->size -= bytes; \ + + /*constructor*/ GF_Box *gf_isom_box_new(u32 boxType); //some boxes may have different syntax based on container. Use this constructor for this case @@ -610,8 +648,8 @@ GF_Err gf_isom_box_size(GF_Box *ptr); GF_Err gf_isom_clone_box(GF_Box *src, GF_Box **dst); GF_Err gf_isom_box_parse(GF_Box **outBox, GF_BitStream *bs); -GF_Err gf_isom_box_array_read(GF_Box *s, GF_BitStream *bs, GF_Err (*check_child_box)(GF_Box *par, GF_Box *b)); -GF_Err gf_isom_box_array_read_ex(GF_Box *parent, GF_BitStream *bs, GF_Err (*check_child_box)(GF_Box *par, GF_Box *b), u32 parent_type); +GF_Err gf_isom_box_array_read(GF_Box *s, GF_BitStream *bs); +GF_Err gf_isom_box_array_read_ex(GF_Box *parent, GF_BitStream *bs, u32 parent_type); GF_Err gf_isom_box_parse_ex(GF_Box **outBox, GF_BitStream *bs, u32 parent_type, Bool is_root_box); @@ -622,6 +660,7 @@ GF_Err gf_isom_box_write_header(GF_Box *ptr, GF_BitStream *bs); //writes box header then version+flags GF_Err gf_isom_full_box_write(GF_Box *s, GF_BitStream *bs); +void gf_isom_box_array_reset(GF_List *boxlist); void gf_isom_box_array_del(GF_List *child_boxes); GF_Err gf_isom_box_array_write(GF_Box *parent, GF_List *list, GF_BitStream *bs); GF_Err gf_isom_box_array_size(GF_Box *parent, GF_List *list); @@ -636,6 +675,26 @@ void gf_isom_box_array_reset_parent(GF_List **child_boxes, GF_List *boxlist); void gf_isom_box_freeze_order(GF_Box *box); +#define BOX_FIELD_ASSIGN(_field, _box_cast) \ + if (is_rem) {\ + ptr->_field = NULL;\ + return GF_OK;\ + } else {\ + if (ptr->_field) ERROR_ON_DUPLICATED_BOX(a, ptr)\ + ptr->_field = (_box_cast *)a;\ + } + +#define BOX_FIELD_LIST_ASSIGN(_field) \ + if (is_rem) {\ + gf_list_del_item(ptr->_field, a);\ + } else {\ + if (!ptr->_field) ptr->_field = gf_list_new();\ + GF_Err _e = gf_list_add(ptr->_field, a);\ + if (_e) return _e;\ + } + + +void gf_isom_box_remove_from_parent(GF_Box *parent_box, GF_Box *box); typedef struct { @@ -686,6 +745,9 @@ typedef struct u8 *data; u32 dataSize; u32 original_4cc; + u32 sai_type, sai_aux_info; + u64 sai_offset; + struct _gf_saio_box *saio_box; } GF_UnknownBox; typedef struct @@ -860,6 +922,7 @@ typedef struct u64 magic; u32 index; + u32 nb_base_refs; #ifndef GPAC_DISABLE_ISOM_WRITE u64 first_dts_chunk; @@ -870,11 +933,17 @@ typedef struct #endif #ifndef GPAC_DISABLE_ISOM_FRAGMENTS + //dts value when at refererence fragment start (first frag ever or first after a table reset), usually current segment start u64 dts_at_seg_start; + //number of samples at refererence fragment start (first frag ever or first after a table reset), usually current segment start u32 sample_count_at_seg_start; Bool first_traf_merged; Bool present_in_scalable_segment; u32 current_traf_stsd_idx; + + u64 last_tfxd_value; + struct __traf_mss_timeref_box *tfrf; + u64 dts_at_next_frag_start; #endif } GF_TrackBox; @@ -1090,8 +1159,8 @@ typedef struct u32 r_currentEntryIndex; u32 r_FirstSampleInEntry; - //stats for read - s32 max_ts_delta; + s32 max_cts_delta; + u32 sample_num_max_cts_delta; } GF_CompositionOffsetBox; @@ -1268,9 +1337,9 @@ typedef struct u32 cleanApertureWidthD; u32 cleanApertureHeightN; u32 cleanApertureHeightD; - u32 horizOffN; + s32 horizOffN; u32 horizOffD; - u32 vertOffN; + s32 vertOffN; u32 vertOffD; } GF_CleanApertureBox; @@ -1352,9 +1421,6 @@ void gf_isom_video_sample_entry_write(GF_VisualSampleEntryBox *ent, GF_BitStream void gf_isom_video_sample_entry_size(GF_VisualSampleEntryBox *ent); #endif -void gf_isom_sample_entry_predestroy(GF_SampleEntryBox *ptr); - - GF_Box *gf_isom_box_find_child(GF_List *parent_child_list, u32 code); void gf_isom_box_del_parent(GF_List **parent_child_list, GF_Box*b); GF_Box *gf_isom_box_new_parent(GF_List **parent_child_list, u32 code); @@ -1372,6 +1438,19 @@ typedef struct GF_HEVCConfig *config; } GF_HEVCConfigurationBox; +typedef struct +{ + GF_ISOM_FULL_BOX + GF_VVCConfig *config; +} GF_VVCConfigurationBox; + +typedef struct +{ + GF_ISOM_FULL_BOX + u8 nal_unit_size; +} GF_VVCNaluConfigurationBox; + + typedef struct { GF_ISOM_BOX @@ -1456,6 +1535,8 @@ typedef struct /*hevc extension*/ GF_HEVCConfigurationBox *hevc_config; GF_HEVCConfigurationBox *lhvc_config; + /*vvc extension*/ + GF_VVCConfigurationBox *vvc_config; /*av1 extension*/ GF_AV1ConfigurationBox *av1_config; /*vp8-9 extension*/ @@ -1534,6 +1615,16 @@ typedef struct GF_AC3Config cfg; } GF_AC3ConfigBox; + + +typedef struct +{ + GF_ISOM_BOX + u32 format_info; + u16 peak_data_rate; +} GF_TrueHDConfigBox; + + typedef struct { GF_ISOM_FULL_BOX @@ -1541,6 +1632,42 @@ typedef struct u32 dataSize; } GF_FLACConfigBox; +typedef struct +{ + GF_ISOM_FULL_BOX + u8 stereo_type; +} GF_Stereo3DBox; + +typedef struct +{ + GF_ISOM_FULL_BOX + char *string; +} GF_SphericalVideoInfoBox; + + +typedef struct +{ + GF_ISOM_FULL_BOX + s32 yaw; + s32 pitch; + s32 roll; +} GF_ProjectionHeaderBox; + + +typedef struct +{ + GF_ISOM_FULL_BOX + //cube map + u32 layout; + s32 padding; + //EQR + u32 bounds_top, bounds_bottom, bounds_left, bounds_right; + //mesh + u32 crc; + s32 encoding_4cc; + +} GF_ProjectionTypeBox; + typedef struct { GF_ISOM_BOX @@ -1574,6 +1701,14 @@ typedef struct } GF_MHAConfigBox; +typedef struct +{ + GF_ISOM_BOX + u8 num_profiles; + u8 *compat_profiles; +} GF_MHACompatibleProfilesBox; + + typedef struct { GF_ISOM_FULL_BOX @@ -1594,6 +1729,9 @@ typedef struct //for AC3/EC3 audio GF_AC3ConfigBox *cfg_ac3; + //for AC3/EC3 audio + GF_TrueHDConfigBox *cfg_mlp; + //for Opus GF_OpusSpecificBox *cfg_opus; @@ -1877,7 +2015,7 @@ typedef struct u32 cached_prev_size; } GF_SampleAuxiliaryInfoSizeBox; -typedef struct +typedef struct _gf_saio_box { GF_ISOM_FULL_BOX @@ -1893,6 +2031,8 @@ typedef struct u32 total_size; u8 *cached_data; + + GF_UnknownBox *sai_data; } GF_SampleAuxiliaryInfoOffsetBox; typedef struct @@ -1935,6 +2075,7 @@ typedef struct GF_List *sub_samples; GF_List *sampleGroups; + GF_List *compactSampleGroups; GF_List *sampleGroupsDescription; u32 nb_sgpd_in_stbl; u32 nb_stbl_boxes; @@ -1942,7 +2083,7 @@ typedef struct GF_List *sai_sizes; GF_List *sai_offsets; - u32 MaxSamplePerChunk, MaxChunkSize; + u32 MaxSamplePerChunk, MaxChunkSize, MaxChunkDur; u16 groupID; u16 trackPriority; u32 currentEntryIndex; @@ -1950,9 +2091,10 @@ typedef struct Bool no_sync_found; u32 r_last_chunk_num, r_last_sample_num, r_last_offset_in_chunk; + u8 patch_piff_psec; } GF_SampleTableBox; -GF_Err stbl_AppendTrafMap(GF_SampleTableBox *stbl, Bool is_seg_start, u64 seg_start_offset, u64 frag_start_offset, u8 *moof_template, u32 moof_template_size, u64 sidx_start, u64 sidx_end); +GF_Err stbl_AppendTrafMap(GF_SampleTableBox *stbl, Bool is_seg_start, u64 seg_start_offset, u64 frag_start_offset, u8 *moof_template, u32 moof_template_size, u64 sidx_start, u64 sidx_end, u32 nb_pack_samples); typedef struct __tag_media_info_box { @@ -2253,6 +2395,8 @@ typedef struct char *full_path; // if not 0, full_path is actually the data to write. u32 data_len; + + u32 tk_id, sample_num, ref_it_id; } GF_ItemInfoEntryBox; typedef struct @@ -2280,6 +2424,9 @@ typedef struct { GF_ISOM_BOX u32 data_format; + //if the sample entry is a generic sample entry (data_format==GNRX), this is the underlying 4CC + //otherwise this is 0 + u32 gnr_type; } GF_OriginalFormatBox; typedef struct @@ -2374,6 +2521,9 @@ typedef struct __tag_meta_box GF_IPMPControlBox *IPMP_control; GF_ItemPropertiesBox *item_props; GF_ItemReferenceBox *item_refs; + GF_GroupListBox *groups_list; + + u8 use_item_sample_sharing, use_item_item_sharing; } GF_MetaBox; typedef struct @@ -2455,6 +2605,10 @@ typedef struct //temp storage of prft box GF_ISOTrackID reference_track_ID; u64 ntp, timestamp; + + //emsg to inject before moof, not part of the moof hierarchy ! + + GF_List *emsgs; } GF_MovieFragmentBox; @@ -2503,6 +2657,7 @@ typedef struct GF_List *sub_samples; GF_List *sampleGroups; + GF_List *compactSampleGroups; GF_List *sampleGroupsDescription; GF_List *sai_sizes; @@ -2511,6 +2666,7 @@ typedef struct //can be senc or PIFF psec struct __sample_encryption_box *sample_encryption; struct __traf_mss_timeext_box *tfxd; /*similar to PRFT but for Smooth Streaming*/ + struct __traf_mss_timeref_box *tfrf; /*when data caching is on*/ u32 DataCache; @@ -2528,6 +2684,9 @@ typedef struct u8 force_new_trun; u8 IFrameSwitching; u8 use_sdtp; + u8 truns_first; + u8 truns_v1; + u8 large_tfdt; } GF_TrackFragmentBox; GF_TrackFragmentBox *gf_isom_get_traf(GF_ISOFile *mov, GF_ISOTrackID TrackID); @@ -2884,8 +3043,8 @@ typedef struct typedef struct { GF_ISOM_FULL_BOX - u8 baseLocation[256]; - u8 basePurlLocation[256]; + u8 baseLocation[257]; + u8 basePurlLocation[257]; } GF_BaseLocationBox; typedef struct @@ -3083,7 +3242,7 @@ typedef struct __adobe_bootstrap_info_box GF_List *quality_entry_table; char *drm_data; char *meta_data; - //entries in these two lists are NOT registered with the box child_boxes because of the inbetween 8 bits !! + //entries in these two lists are NOT registered with the box child_boxes because of the in-between 8 bits !! u8 segment_run_table_count; GF_List *segment_run_table_entries; u8 fragment_run_table_count; @@ -3146,6 +3305,23 @@ typedef struct } GF_SampleGroupBox; +typedef struct +{ + u32 length; + u32 sample_count; + u32 *sample_group_description_indices; +} GF_CompactSampleGroupPattern; + +typedef struct +{ + GF_ISOM_FULL_BOX + u32 grouping_type; + u32 grouping_type_parameter; + + u32 pattern_count; + GF_CompactSampleGroupPattern *patterns; +} GF_CompactSampleGroupBox; + typedef struct { GF_ISOM_FULL_BOX @@ -3273,7 +3449,31 @@ typedef struct u8 dimension_identifier[16]; } LHEVC_DependentLayer; +typedef struct +{ + u8 subpic_id_len_minus1; + u16 subpic_id_bit_pos; + u8 start_code_emul_flag; + u8 pps_sps_subpic_id_flag; + u8 xps_id; +} GF_VVCSubpicIDRewritingInfo; +/*SubpictureOrder - 'spor' type*/ +typedef struct +{ + Bool subpic_id_info_flag; + u16 num_subpic_ref_idx; + u16 *subp_track_ref_idx; + GF_VVCSubpicIDRewritingInfo spinfo; +} GF_SubpictureOrderEntry; + +/*SubpictureLayoutMap - 'sulm' type*/ +typedef struct +{ + u32 groupID_info_4cc; + u32 nb_entries; + u16 *groupIDs; +} GF_SubpictureLayoutMapEntry; /* CENC stuff @@ -3284,10 +3484,8 @@ typedef struct { u8 crypt_byte_block, skip_byte_block; u8 IsProtected; - u8 Per_Sample_IV_size; - u8 constant_IV_size; - bin128 KID; - bin128 constant_IV; + u8 *key_info; + u32 key_info_size; } GF_CENCSampleEncryptionGroupEntry; typedef struct @@ -3299,6 +3497,7 @@ typedef struct bin128 *KIDs; u32 private_data_size; u8 *private_data; + u8 moof_defined; } GF_ProtectionSystemHeaderBox; typedef struct __cenc_tenc_box @@ -3307,10 +3506,9 @@ typedef struct __cenc_tenc_box u8 crypt_byte_block, skip_byte_block; u8 isProtected; - u8 Per_Sample_IV_Size; - bin128 KID; - u8 constant_IV_size; - bin128 constant_IV; + + //single key + u8 key_info[37]; } GF_TrackEncryptionBox; typedef struct __piff_tenc_box @@ -3320,8 +3518,7 @@ typedef struct __piff_tenc_box u32 flags; u32 AlgorithmID; - u8 IV_size; - bin128 KID; + u8 key_info[20]; } GF_PIFFTrackEncryptionBox; typedef struct @@ -3342,7 +3539,8 @@ typedef struct __sample_encryption_box /*u8 version; field in included in base box version */ u32 flags; - Bool is_piff; + //0: regular senc, 1: PIFF PSEC, 2: MS senc with version 1 (not compatible with ISOBMFF senc v1) + u32 piff_type; GF_List *samp_aux_info; /*GF_CENCSampleAuxInfo*/ u64 bs_offset; @@ -3373,20 +3571,48 @@ typedef struct __traf_mss_timeext_box u64 fragment_duration_in_track_timescale; } GF_MSSTimeExtBox; +typedef struct +{ + u64 absolute_time_in_track_timescale; + u64 fragment_duration_in_track_timescale; +} GF_MSSTimeEntry; + +typedef struct __traf_mss_timeref_box +{ + GF_ISOM_UUID_BOX + /*u8 version; field in included in base box version */ + u32 flags; + + u32 frags_count; + GF_MSSTimeEntry *frags; + +} GF_MSSTimeRefBox; + + + GF_SampleEncryptionBox *gf_isom_create_piff_psec_box(u8 version, u32 flags, u32 AlgorithmID, u8 IV_size, bin128 KID); GF_SampleEncryptionBox * gf_isom_create_samp_enc_box(u8 version, u32 flags); -void gf_isom_cenc_get_default_info_ex(GF_TrackBox *trak, u32 sampleDescriptionIndex, u32 *container_type, Bool *default_IsEncrypted, u8 *default_IV_size, bin128 *default_KID, u8 *constant_IV_size, bin128 *constant_IV, u8 *crypt_byte_block, u8 *skip_byte_block); +void gf_isom_cenc_get_default_info_internal(GF_TrackBox *trak, u32 sampleDescriptionIndex, u32 *container_type, Bool *default_IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size); +GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, #ifndef GPAC_DISABLE_ISOM_FRAGMENTS -GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *IV_size, bin128 *KID, u8 *crypt_byte_block, u8 *skip_byte_block, u8 *constant_IV_size, bin128 *constant_IV); -GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *ptr); + GF_TrackFragmentBox *traf, #else -GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, void *traf, uGF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *IV_size, bin128 *KID, - u8 *crypt_byte_block, u8 *skip_byte_block, u8 *constant_IV_size, bin128 *constant_IV); -GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *ptr); + void *traf, #endif + GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size); + + +GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + GF_TrackFragmentBox *traf, +#else + void *traf, +#endif + GF_SampleEncryptionBox *ptr); + /* Boxes for Adobe's protection scheme @@ -3471,6 +3697,11 @@ typedef struct { u8 angle; } GF_ImageRotationBox; +typedef struct { + GF_ISOM_BOX + u8 axis; +} GF_ImageMirrorBox; + typedef struct { u8 essential; @@ -3488,6 +3719,17 @@ typedef struct __item_association_box { GF_List *entries; } GF_ItemPropertyAssociationBox; +typedef struct { + GF_ISOM_BOX + u8 large_size; + u32 layer_size[3]; +} GF_AV1LayeredImageIndexingPropertyBox; + +typedef struct { + GF_ISOM_BOX + u8 op_index; +} GF_AV1OperatingPointSelectorPropertyBox; + typedef struct { GF_ISOM_FULL_BOX @@ -3496,6 +3738,20 @@ typedef struct { u8 *data; } GF_AuxiliaryTypePropertyBox; +typedef struct { + GF_ISOM_FULL_BOX + u8 skip_byte_block, crypt_byte_block; + u8 *key_info; + u32 key_info_size; +} GF_ItemEncryptionPropertyBox; + + +typedef struct { + GF_ISOM_FULL_BOX + u32 aux_info_type; + u32 aux_info_parameter; +} GF_AuxiliaryInfoPropertyBox; + typedef struct { GF_ISOM_FULL_BOX @@ -3604,6 +3860,25 @@ typedef struct } FDItemInformationBox; + +typedef struct +{ + char *name; + u32 flags; + u16 prop_type; + + u32 prop_size; + u8 *prop_value; //most of the time, utf16 with trailing \0\0 +} GF_XtraTag; + +typedef struct +{ + GF_ISOM_BOX + + GF_List *tags; +} GF_XtraBox; + + /* Data Map (media storage) stuff */ @@ -3655,6 +3930,7 @@ typedef struct #ifndef GPAC_DISABLE_ISOM_WRITE char *temp_file; #endif + GF_Blob *blob; } GF_FileDataMap; /*file mapping handler. used if supported, only on read mode for complete files (not in file download)*/ @@ -3720,6 +3996,7 @@ enum GF_ISOM_FRAG_READ_DEBUG = 0x02, }; + /*this is our movie object*/ struct __tag_isom { /*the last fatal error*/ @@ -3749,6 +4026,8 @@ struct __tag_isom { u8 convert_streaming_text; u8 is_jp2; u8 force_co64; + u8 disable_odf_translate; + u8 disable_brand_rewrite; u64 next_flush_chunk_time; Bool keep_utc; /*main boxes for fast access*/ @@ -3758,6 +4037,9 @@ struct __tag_isom { GF_MediaDataBox *mdat; /*file brand (since v2, NULL means mp4 v1)*/ GF_FileTypeBox *brand; + /*original file type box if any*/ + GF_Box *otyp; + /*progressive download info*/ GF_ProgressiveDownloadBox *pdin; /*meta box if any*/ @@ -3766,16 +4048,15 @@ struct __tag_isom { s64 read_byte_offset; u64 bytes_removed; - Bool disable_odf_translate; - GF_ISOCompressMode compress_mode; - Bool force_compress; + u32 compress_flags; void (*progress_cbk)(void *udta, u64 nb_done, u64 nb_total); void *progress_cbk_udta; + u32 FragmentsFlags; #ifndef GPAC_DISABLE_ISOM_FRAGMENTS - u32 FragmentsFlags, NextMoofNumber; + u32 NextMoofNumber; /*active fragment*/ GF_MovieFragmentBox *moof; /*in WRITE mode, this is the current MDAT where data is written*/ @@ -3786,6 +4067,8 @@ struct __tag_isom { GF_List *moof_list; Bool use_segments, moof_first, append_segment, styp_written, force_moof_base_offset; + GF_List *emsgs; + /*used when building single-indexed self initializing media segments*/ GF_SegmentIndexBox *root_sidx; u64 root_sidx_offset; @@ -3801,6 +4084,7 @@ struct __tag_isom { u32 single_moof_state; Bool sample_groups_in_traf; + Bool force_sidx_v1; /* optional mfra box used in write mode */ GF_MovieFragmentRandomAccessBox *mfra; @@ -3818,6 +4102,7 @@ struct __tag_isom { GF_SegmentIndexBox *main_sidx; u64 main_sidx_end_pos; + Bool has_pssh_moof; #endif GF_ProducerReferenceTimeBox *last_producer_ref_time; @@ -3840,6 +4125,10 @@ struct __tag_isom { u32 block_buffer_size; u32 nb_box_init_seg; + + Bool no_inplace_rewrite; + u32 padding; + u64 original_moov_offset, original_meta_offset, first_data_toplevel_offset, first_data_toplevel_size; }; /*time function*/ @@ -3858,6 +4147,9 @@ u32 gf_isom_get_tracknum_from_id(GF_MovieBox *moov, GF_ISOTrackID trackID); GF_ISOFile *gf_isom_open_file(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir); /*close and delete a movie*/ void gf_isom_delete_movie(GF_ISOFile *mov); +void gf_isom_meta_restore_items_ref(GF_ISOFile *file, GF_MetaBox *meta); + +GF_MetaBox *gf_isom_get_meta(GF_ISOFile *file, Bool root_meta, u32 track_num); /*StreamDescription reconstruction Functions*/ GF_Err GetESD(GF_MovieBox *moov, GF_ISOTrackID trackID, u32 StreamDescIndex, GF_ESD **outESD); @@ -3927,6 +4219,9 @@ GF_Err gf_isom_rewrite_text_sample(GF_ISOSample *samp, u32 sampleDescriptionInde GF_UserDataMap *udta_getEntry(GF_UserDataBox *ptr, u32 box_type, bin128 *uuid); + +GF_Err gf_isom_set_sample_group_description_internal(GF_ISOFile *movie, u32 track, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *data, u32 data_size, Bool check_access); + #ifndef GPAC_DISABLE_ISOM_WRITE GF_Err FlushCaptureMode(GF_ISOFile *movie); @@ -3971,7 +4266,7 @@ GF_Err stbl_SampleSizeAppend(GF_SampleSizeBox *stsz, u32 data_size); /*writing of the final chunk info in edit mode*/ GF_Err stbl_SetChunkAndOffset(GF_SampleTableBox *stbl, u32 sampleNumber, u32 StreamDescIndex, GF_SampleToChunkBox *the_stsc, GF_Box **the_stco, u64 data_offset, Bool forceNewChunk, u32 nb_samp); /*EDIT LIST functions*/ -GF_EdtsEntry *CreateEditEntry(u64 EditDuration, u64 MediaTime, u8 EditMode); +GF_EdtsEntry *CreateEditEntry(u64 EditDuration, u64 MediaTime, u32 MediaRate, u8 EditMode); GF_Err stbl_SetRedundant(GF_SampleTableBox *stbl, u32 sampleNumber); GF_Err stbl_AddRedundant(GF_SampleTableBox *stbl, u32 sampleNumber); @@ -3992,11 +4287,12 @@ GF_Err stbl_RemoveSampleGroup(GF_SampleTableBox *stbl, u32 SampleNumber); GF_Err gf_isom_close_fragments(GF_ISOFile *movie); #endif -GF_Err gf_isom_flush_sidx(GF_ISOFile *movie, u32 sidx_max_size, Bool exact_range); +GF_Err gf_isom_flush_sidx(GF_ISOFile *movie, u32 sidx_max_size, Bool force_v1); #endif /*GPAC_DISABLE_ISOM_WRITE*/ Bool gf_isom_is_identical_sgpd(void *ptr1, void *ptr2, u32 grouping_type); +void sgpd_del_entry(u32 grouping_type, void *entry); GF_DefaultSampleGroupDescriptionEntry * gf_isom_get_sample_group_info_entry(GF_ISOFile *the_file, GF_TrackBox *trak, u32 grouping_type, u32 sample_description_index, u32 *default_index, GF_SampleGroupDescriptionBox **out_sgdp); @@ -4008,22 +4304,22 @@ Bool CheckHintFormat(GF_TrackBox *trak, u32 HintType); u32 GetHintFormat(GF_TrackBox *trak); /*locate a box by its type or UUID*/ -GF_ItemListBox *gf_ismo_locate_box(GF_List *list, u32 boxType, bin128 UUID); - -GF_Err moov_on_child_box(GF_Box *ptr, GF_Box *a); -GF_Err trak_on_child_box(GF_Box *ptr, GF_Box *a); -GF_Err mvex_on_child_box(GF_Box *ptr, GF_Box *a); -GF_Err stsd_on_child_box(GF_Box *ptr, GF_Box *a); -GF_Err hnti_on_child_box(GF_Box *hnti, GF_Box *a); -GF_Err udta_on_child_box(GF_Box *ptr, GF_Box *a); -GF_Err edts_on_child_box(GF_Box *s, GF_Box *a); +GF_ItemListBox *gf_isom_locate_box(GF_List *list, u32 boxType, bin128 UUID); + +GF_Err moov_on_child_box(GF_Box *ptr, GF_Box *a, Bool is_rem); +GF_Err trak_on_child_box(GF_Box *ptr, GF_Box *a, Bool is_rem); +GF_Err mvex_on_child_box(GF_Box *ptr, GF_Box *a, Bool is_rem); +GF_Err stsd_on_child_box(GF_Box *ptr, GF_Box *a, Bool is_rem); +GF_Err hnti_on_child_box(GF_Box *hnti, GF_Box *a, Bool is_rem); +GF_Err udta_on_child_box(GF_Box *ptr, GF_Box *a, Bool is_rem); +GF_Err edts_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem); GF_Err stdp_box_read(GF_Box *s, GF_BitStream *bs); -GF_Err stbl_on_child_box(GF_Box *ptr, GF_Box *a); +GF_Err stbl_on_child_box(GF_Box *ptr, GF_Box *a, Bool is_rem); GF_Err sdtp_box_read(GF_Box *s, GF_BitStream *bs); -GF_Err dinf_on_child_box(GF_Box *s, GF_Box *a); -GF_Err minf_on_child_box(GF_Box *s, GF_Box *a); -GF_Err mdia_on_child_box(GF_Box *s, GF_Box *a); -GF_Err traf_on_child_box(GF_Box *s, GF_Box *a); +GF_Err dinf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem); +GF_Err minf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem); +GF_Err mdia_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem); +GF_Err traf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem); /*rewrites avcC based on the given esd - this destroys the esd*/ GF_Err AVC_HEVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd); @@ -4040,14 +4336,40 @@ Bool gf_isom_cenc_has_saiz_saio_track(GF_SampleTableBox *stbl, u32 scheme_type); #ifndef GPAC_DISABLE_ISOM_FRAGMENTS Bool gf_isom_cenc_has_saiz_saio_traf(GF_TrackFragmentBox *traf, u32 scheme_type); -void gf_isom_cenc_set_saiz_saio(GF_SampleEncryptionBox *senc, GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 len, Bool saio_32bits); +void gf_isom_cenc_set_saiz_saio(GF_SampleEncryptionBox *senc, GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 len, Bool saio_32bits, Bool use_mkey); #endif -GF_Err gf_isom_cenc_merge_saiz_saio(GF_SampleEncryptionBox *senc, GF_SampleTableBox *stbl, u64 offset, u32 len); +GF_Err gf_isom_cenc_merge_saiz_saio(GF_SampleEncryptionBox *senc, GF_SampleTableBox *stbl, u32 sample_number, u64 offset, u32 len); void gf_isom_parse_trif_info(const u8 *data, u32 size, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h); Bool gf_isom_is_encrypted_entry(u32 entryType); +//too export in constants +Bool gf_cenc_validate_key_info(const u8 *key_info, u32 key_info_size); + +GF_Err gf_isom_add_sample_aux_info_internal(GF_TrackBox *trak, void *_traf, u32 sampleNumber, u32 aux_type, u32 aux_info, u8 *data, u32 size); + + +/*! CENC auxiliary info*/ +typedef struct __cenc_sample_aux_info +{ + u8 *cenc_data; + u32 cenc_data_size; + /*! flag set if sample is clear - it MUST NOT be written to file*/ + u8 isNotProtected; + + /*! key info, for dump only (not valid otherwise)*/ + const u8 *key_info; + u32 key_info_size; +} GF_CENCSampleAuxInfo; + + +/*! destroys a CENC sample auxiliary structure +\param samp_aux_info the target auxiliary buffer +*/ +void gf_isom_cenc_samp_aux_info_del(GF_CENCSampleAuxInfo *samp_aux_info); + + #ifndef GPAC_DISABLE_ISOM_HINTING /* @@ -4342,10 +4664,10 @@ GF_Err gf_isom_box_array_dump(GF_List *list, FILE * trace); void gf_isom_registry_disable(u32 boxCode, Bool disable); /*Apple extensions*/ -GF_MetaBox *gf_isom_apple_get_meta_extensions(GF_ISOFile *mov); +GF_Box *gf_isom_get_meta_extensions(GF_ISOFile *mov, Bool for_xtra); #ifndef GPAC_DISABLE_ISOM_WRITE -GF_MetaBox *gf_isom_apple_create_meta_extensions(GF_ISOFile *mov); +GF_Box *gf_isom_create_meta_extensions(GF_ISOFile *mov, Bool for_xtra); #endif /*GPAC_DISABLE_ISOM_WRITE*/ @@ -4360,7 +4682,7 @@ GF_Box *boxstring_new_with_data(u32 type, const char *string, GF_List **parent); GF_Err gf_isom_read_null_terminated_string(GF_Box *s, GF_BitStream *bs, u64 size, char **out_str); -GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_MovieFragmentBox *moof, u64 moof_offset, s32 compresed_diff, u64 *cumulated_offset, Bool is_first_merge); +GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_MovieFragmentBox *moof, u64 moof_offset, s32 compresed_diff, u64 *cumulated_offset); #endif //GPAC_DISABLE_ISOM diff --git a/include/gpac/internal/m3u8.h b/include/gpac/internal/m3u8.h index c24a513..93d5a52 100644 --- a/include/gpac/internal/m3u8.h +++ b/include/gpac/internal/m3u8.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Pierre Souchay - Jean Le Feuvre - Romain Bouqueau - * Copyright (c) Telecom ParisTech 2010-2012, Romain Bouqueau + * Copyright (c) Telecom ParisTech 2010-2021 * All rights reserved * * This file is part of GPAC @@ -45,6 +45,7 @@ struct s_playList { int current_media_seq; int media_seq_min; int media_seq_max; + int discontinuity; double target_duration; double computed_duration; Bool is_ended; @@ -54,7 +55,7 @@ typedef struct s_playList Playlist; typedef enum e_playlistElementType { TYPE_PLAYLIST, TYPE_MEDIA, TYPE_UNKNOWN } PlaylistElementType; -typedef enum e_playlistElementDRMMethod { DRM_NONE, DRM_AES_128 } PlaylistElementDRMMethod; +typedef enum e_playlistElementDRMMethod { DRM_NONE, DRM_AES_128, DRM_CENC } PlaylistElementDRMMethod; typedef enum _e_MediaType { MEDIA_TYPE_UNKNOWN = 0, @@ -71,7 +72,7 @@ struct s_playlistElement { MediaType media_type; double duration_info; u64 byte_range_start, byte_range_end; - int bandwidth, width, height; + int bandwidth, width, height, low_lat_chunk, independent_chunk; char *title; char *codecs; char *language; @@ -80,8 +81,9 @@ struct s_playlistElement { char *url; char *init_segment_url; u64 init_byte_range_start, init_byte_range_end; + //informative UTC start time u64 utc_start_time; - + u32 discontinuity; PlaylistElementDRMMethod drm_method; char *key_uri; bin128 key_iv; @@ -108,7 +110,7 @@ struct s_masterPlaylist { GF_List *streams; /*Stream*/ int current_stream; Bool playlist_needs_refresh; - Bool independent_segments; + Bool independent_segments, low_latency; }; typedef struct s_masterPlaylist MasterPlaylist; @@ -129,9 +131,10 @@ GF_Err gf_m3u8_parse_master_playlist(const char *file, MasterPlaylist **playlist \param baseURL base URL of the playlist \param in_program in which the playlist is parsed \param sub_playlist existing subplaylist element in the playlist in which the playlist is parsed +\param is_master set to true to indicate if this is the root playlist \param GF_OK if playlist valid */ -GF_Err gf_m3u8_parse_sub_playlist(const char *file, MasterPlaylist **playlist, const char *baseURL, Stream *in_program, PlaylistElement *sub_playlist); +GF_Err gf_m3u8_parse_sub_playlist(const char *file, MasterPlaylist **playlist, const char *baseURL, Stream *in_program, PlaylistElement *sub_playlist, Bool is_master); /** * Deletes the given MasterPlaylist and all of its sub elements diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index 9ac2a96..f722dd9 100644 --- a/include/gpac/internal/media_dev.h +++ b/include/gpac/internal/media_dev.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2012 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Media Tools sub-project @@ -43,6 +43,15 @@ void gf_media_get_sample_average_infos(GF_ISOFile *file, u32 Track, u32 *avgSize GF_Err gf_import_message(GF_MediaImporter *import, GF_Err e, char *format, ...); #endif /*GPAC_DISABLE_MEDIA_IMPORT*/ + +typedef struct +{ + Bool override; + u16 colour_primaries, transfer_characteristics, matrix_coefficients; + Bool full_range; +} COLR; + + #ifndef GPAC_DISABLE_AV_PARSERS u32 gf_latm_get_value(GF_BitStream *bs); @@ -63,10 +72,11 @@ u32 gf_media_nalu_next_start_code(const u8 *data, u32 data_len, u32 *sc_size); u32 gf_media_nalu_emulation_bytes_remove_count(const u8 *buffer, u32 nal_size); u32 gf_media_nalu_remove_emulation_bytes(const u8 *buffer_src, u8 *buffer_dst, u32 nal_size); -u32 gf_bs_get_ue(GF_BitStream *bs); -s32 gf_bs_get_se(GF_BitStream *bs); -void gf_bs_set_ue(GF_BitStream *bs, u32 num); -void gf_bs_set_se(GF_BitStream *bs, s32 num); +u32 gf_bs_read_ue(GF_BitStream *bs); +s32 gf_bs_read_se(GF_BitStream *bs); +void gf_bs_write_ue(GF_BitStream *bs, u32 num); +void gf_bs_write_se(GF_BitStream *bs, s32 num); + enum { @@ -205,7 +215,7 @@ typedef struct AVC_SPS *sps; AVC_PPS *pps; - SVC_NALUHeader NalHeader; + SVC_NALUHeader svc_nalhdr; } AVCSliceInfo; @@ -263,29 +273,72 @@ typedef struct /*return sps ID or -1 if error*/ -s32 gf_media_avc_read_sps(const u8 *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos); -s32 gf_media_avc_read_sps_bs(GF_BitStream *bs, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos); +s32 gf_avc_read_sps(const u8 *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos); +s32 gf_avc_read_sps_bs(GF_BitStream *bs, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos); /*return pps ID or -1 if error*/ -s32 gf_media_avc_read_pps(const u8 *pps_data, u32 pps_size, AVCState *avc); -s32 gf_media_avc_read_pps_bs(GF_BitStream *bs, AVCState *avc); +s32 gf_avc_read_pps(const u8 *pps_data, u32 pps_size, AVCState *avc); +s32 gf_avc_read_pps_bs(GF_BitStream *bs, AVCState *avc); /*is slice containing intra MB only*/ -Bool gf_media_avc_slice_is_intra(AVCState *avc); +Bool gf_avc_slice_is_intra(AVCState *avc); /*parses NALU, updates avc state and returns: 1 if NALU part of new frame 0 if NALU part of prev frame -1 if bitstream error */ -s32 gf_media_avc_parse_nalu(GF_BitStream *bs, AVCState *avc); +s32 gf_avc_parse_nalu(GF_BitStream *bs, AVCState *avc); /*remove SEI messages not allowed in MP4*/ /*nota: 'buffer' remains unmodified but cannot be set const*/ -u32 gf_media_avc_reformat_sei(u8 *buffer, u32 nal_size, Bool isobmf_rewrite, AVCState *avc); +u32 gf_avc_reformat_sei(u8 *buffer, u32 nal_size, Bool isobmf_rewrite, AVCState *avc); #ifndef GPAC_DISABLE_ISOM -GF_Err gf_media_avc_change_par(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d); -GF_Err gf_media_hevc_change_par(GF_HEVCConfig *hvcc, s32 ar_n, s32 ar_d); + +GF_Err gf_media_get_color_info(GF_ISOFile *file, u32 track, u32 sampleDescriptionIndex, u32 *colour_type, u16 *colour_primaries, u16 *transfer_characteristics, u16 *matrix_coefficients, Bool *full_range_flag); + +/*! VUI modification parameters*/ +typedef struct +{ + /*! if true, the structure members will be updated to the actual values written or present in bitstream. If still -1, info was not written in bitstream*/ + Bool update; + /*! pixel aspect ratio num + a value of 0 in ar_num or ar_den removes PAR + a value of -1 in ar_num or ar_den keeps PAR from bitstream + positive values change PAR + */ + s32 ar_num; + /*! pixel aspect ratio den*/ + s32 ar_den; + + //if set all video info is removed + Bool remove_video_info; + //new fullrange, -1 to use info from bitstream + s32 fullrange; + //new vidformat flag, -1 to use info from bitstream + s32 video_format; + //new color primaries flag, -1 to use info from bitstream + s32 color_prim; + //new color transfer characteristics flag, -1 to use info from bitstream + s32 color_tfc; + //new color matrix flag, -1 to use info from bitstream + s32 color_matrix; +} GF_VUIInfo; + +GF_Err gf_avc_change_vui(GF_AVCConfig *avcc, GF_VUIInfo *vui_info); + +//shortucts for the above for API compatibility +GF_Err gf_avc_change_par(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d); +GF_Err gf_avc_change_color(GF_AVCConfig *avcc, s32 fullrange, s32 vidformat, s32 colorprim, s32 transfer, s32 colmatrix); + +GF_Err gf_hevc_change_vui(GF_HEVCConfig *hvcc, GF_VUIInfo *vui); +//shortcut for the above for API compatibility +GF_Err gf_hevc_change_par(GF_HEVCConfig *hvcc, s32 ar_n, s32 ar_d); +GF_Err gf_hevc_change_color(GF_HEVCConfig *hvcc, s32 fullrange, s32 vidformat, s32 colorprim, s32 transfer, s32 colmatrix); #endif +GF_Err gf_vvc_change_vui(GF_VVCConfig *cfg, GF_VUIInfo *vui); +//shortcut for the above for API compatibility +GF_Err gf_vvc_change_par(GF_VVCConfig *cfg, s32 ar_n, s32 ar_d); +GF_Err gf_vvc_change_color(GF_VVCConfig *cfg, s32 fullrange, s32 vidformat, s32 colorprim, s32 transfer, s32 colmatrix); typedef struct @@ -411,7 +464,7 @@ typedef struct RepFormat typedef struct { u16 avg_bit_rate, max_bit_rate, avg_pic_rate; - u8 constand_pic_rate_idc; + u8 constant_pic_rate_idc; } HEVC_RateInfo; @@ -430,6 +483,7 @@ typedef struct HEVC_ProfileTierLevel ptl; HEVC_SublayerPTL sub_ptl[8]; + //this is not parsed yet (in VPS VUI) HEVC_RateInfo rates[8]; @@ -515,9 +569,9 @@ typedef struct _hevc_state s32 last_parsed_sps_id; s32 last_parsed_pps_id; - // Dolby Vision - Bool dv_rpu; - Bool dv_el; + u8 clli_data[4]; + u8 mdcv_data[24]; + u8 clli_valid, mdcv_valid; } HEVCState; typedef struct hevc_combine{ @@ -532,35 +586,263 @@ enum GF_HEVC_SLICE_TYPE_P = 1, GF_HEVC_SLICE_TYPE_I = 2, }; -s32 gf_media_hevc_read_vps(u8 *data, u32 size, HEVCState *hevc); -s32 gf_media_hevc_read_vps_bs(GF_BitStream *bs, HEVCState *hevc); -s32 gf_media_hevc_read_sps(u8 *data, u32 size, HEVCState *hevc); -s32 gf_media_hevc_read_sps_bs(GF_BitStream *bs, HEVCState *hevc); -s32 gf_media_hevc_read_pps(u8 *data, u32 size, HEVCState *hevc); -s32 gf_media_hevc_read_pps_bs(GF_BitStream *bs, HEVCState *hevc); -s32 gf_media_hevc_parse_nalu(u8 *data, u32 size, HEVCState *hevc, u8 *nal_unit_type, u8 *temporal_id, u8 *layer_id); -Bool gf_media_hevc_slice_is_intra(HEVCState *hevc); -Bool gf_media_hevc_slice_is_IDR(HEVCState *hevc); +s32 gf_hevc_read_vps(u8 *data, u32 size, HEVCState *hevc); +s32 gf_hevc_read_vps_bs(GF_BitStream *bs, HEVCState *hevc); +s32 gf_hevc_read_sps(u8 *data, u32 size, HEVCState *hevc); +s32 gf_hevc_read_sps_bs(GF_BitStream *bs, HEVCState *hevc); +s32 gf_hevc_read_pps(u8 *data, u32 size, HEVCState *hevc); +s32 gf_hevc_read_pps_bs(GF_BitStream *bs, HEVCState *hevc); +s32 gf_hevc_parse_nalu(u8 *data, u32 size, HEVCState *hevc, u8 *nal_unit_type, u8 *temporal_id, u8 *layer_id); +Bool gf_hevc_slice_is_intra(HEVCState *hevc); +Bool gf_hevc_slice_is_IDR(HEVCState *hevc); //parses VPS and rewrites data buffer after removing VPS extension -s32 gf_media_hevc_read_vps_ex(u8 *data, u32 *size, HEVCState *hevc, Bool remove_extensions); +s32 gf_hevc_read_vps_ex(u8 *data, u32 *size, HEVCState *hevc, Bool remove_extensions); -void gf_media_hevc_parse_ps(GF_HEVCConfig* hevccfg, HEVCState* hevc, u32 nal_type); -s32 gf_media_hevc_parse_nalu_bs(GF_BitStream *bs, HEVCState *hevc, u8 *nal_unit_type, u8 *temporal_id, u8 *layer_id); +void gf_hevc_parse_ps(GF_HEVCConfig* hevccfg, HEVCState* hevc, u32 nal_type); +s32 gf_hevc_parse_nalu_bs(GF_BitStream *bs, HEVCState *hevc, u8 *nal_unit_type, u8 *temporal_id, u8 *layer_id); GF_Err gf_hevc_get_sps_info_with_state(HEVCState *hevc_state, u8 *sps_data, u32 sps_size, u32 *sps_id, u32 *width, u32 *height, s32 *par_n, s32 *par_d); /*parses HEVC SEI and fill state accordingly*/ -void gf_media_hevc_parse_sei(char* buffer, u32 nal_size, HEVCState *hevc); +void gf_hevc_parse_sei(char* buffer, u32 nal_size, HEVCState *hevc); + + + +enum +{ + GF_VVC_SLICE_TYPE_B = 0, + GF_VVC_SLICE_TYPE_P = 1, + GF_VVC_SLICE_TYPE_I = 2, + GF_VVC_SLICE_TYPE_UNKNOWN = 10, +}; + +#define VVC_MAX_REF_PICS 29 + +#define VVC_RPL_ST 0 +#define VVC_RPL_LT 1 +#define VVC_RPL_IL 2 + +typedef struct +{ + u32 num_ref_entries; + u32 nb_short_term_pictures, nb_long_term_pictures, nb_inter_layer_pictures; + + u8 ref_pic_type[VVC_MAX_REF_PICS]; +// u32 ref_pic_id[VVC_MAX_REF_PICS]; +// s32 poc[VVC_MAX_REF_PICS]; +// u32 nb_active_pics; +// u8 delta_poc_msb_present[VVC_MAX_REF_PICS]; +// s32 delta_poc_msb_cycle_lt[VVC_MAX_REF_PICS]; + u8 ltrp_in_header_flag; +// u32 inter_layer_ref_pic_id[VVC_MAX_REF_PICS]; +} VVC_RefPicList; + +#define MAX_TILE_COLS 30 +#define MAX_TILE_ROWS 33 + +typedef struct +{ + s32 id; + u32 vps_id; + u8 state; + + //all flags needed for further PPS , picture header or slice header parsing + u8 max_sublayers, chroma_format_idc, log2_ctu_size, sps_ptl_dpb_hrd_params_present_flag; + u8 gdr_enabled, ref_pic_resampling, res_change_in_clvs, explicit_scaling_list_enabled_flag; + u8 virtual_boundaries_enabled_flag, virtual_boundaries_present_flag, joint_cbcr_enabled_flag; + u8 dep_quant_enabled_flag, sign_data_hiding_enabled_flag, transform_skip_enabled_flag; + u8 ph_num_extra_bits, sh_num_extra_bits, partition_constraints_override_enabled_flag; + u8 alf_enabled_flag, ccalf_enabled_flag, lmcs_enabled_flag, long_term_ref_pics_flag, inter_layer_prediction_enabled_flag; + u8 weighted_pred_flag, weighted_bipred_flag, temporal_mvp_enabled_flag, mmvd_fullpel_only_enabled_flag, bdof_control_present_in_ph_flag; + u8 dmvr_control_present_in_ph_flag, prof_control_present_in_ph_flag, sao_enabled_flag, idr_rpl_present_flag; + u8 entry_point_offsets_present_flag, entropy_coding_sync_enabled_flag; + + u8 conf_window; + u32 cw_left, cw_right, cw_top, cw_bottom; + + //subpic info, not fully implemented yet + u8 subpic_info_present, independent_subpic_flags, subpic_same_size, subpicid_mapping_explicit, subpicid_mapping_present; + u32 nb_subpics; //up to 600 + u32 subpicid_len; + Bool has_timing_info; + u32 num_units_in_tick, time_scale; + u32 width, height; + + u32 bitdepth; + + //POC compute + u8 log2_max_poc_lsb, poc_msb_cycle_flag; + u32 poc_msb_cycle_len; + + //reference picture lists + u32 num_ref_pic_lists[2]; + VVC_RefPicList rps[2][64]; + + //VUI + u8 aspect_ratio_info_present_flag; + u8 sar_idc; + u16 sar_width, sar_height; + + u8 overscan_info_present_flag; + u8 video_signal_type_present_flag; + u8 video_format; + u8 video_full_range_flag; -GF_Err gf_media_parse_ivf_file_header(GF_BitStream *bs, u32 *width, u32*height, u32 *codec_fourcc, u32 *frame_rate, u32 *time_scale, u32 *num_frames); + u8 colour_description_present_flag; + u8 colour_primaries; + u8 transfer_characteristics; + u8 matrix_coefficients; + + //SPS range extensions, not yet parsed + u8 ts_residual_coding_rice_present_in_sh_flag, reverse_last_sig_coeff_enabled_flag; +} VVC_SPS; + +typedef struct +{ + s32 id; + u32 sps_id; + u8 state; + //all flags needed for further picture header or slice header parsing + u8 mixed_nal_types, output_flag_present_flag, no_pic_partition_flag, subpic_id_mapping_present_flag, rect_slice_flag; + u8 alf_info_in_ph_flag, rpl_info_in_ph_flag, cu_qp_delta_enabled_flag, cu_chroma_qp_offset_list_enabled_flag, weighted_pred_flag; + u8 weighted_bipred_flag, wp_info_in_ph_flag, qp_delta_info_in_ph_flag, sao_info_in_ph_flag, dbf_info_in_ph_flag; + u8 deblocking_filter_disabled_flag, deblocking_filter_override_enabled_flag, chroma_tool_offsets_present_flag; + u8 slice_chroma_qp_offsets_present_flag, picture_header_extension_present_flag, rpl1_idx_present_flag; + u8 cabac_init_present_flag, slice_header_extension_present_flag, single_slice_per_subpic_flag; + + u32 num_ref_idx_default_active[2]; + u32 num_tiles_in_pic, num_tile_rows, num_tile_cols, slice_address_len, num_slices_in_pic; + + u32 width, height; + u8 conf_window; + u32 cw_left, cw_right, cw_top, cw_bottom; + + //tile info + u32 tile_rows_height_ctb[MAX_TILE_ROWS]; + u32 tile_cols_width_ctb[MAX_TILE_COLS]; + u32 pic_width_in_ctbsY, pic_height_in_ctbsY; +} VVC_PPS; + +#define VVC_MAX_LAYERS 4 +#define VVC_MAX_NUM_LAYER_SETS 1024 + + +typedef struct +{ + u8 profile_present_flag, level_present_flag; + u8 sublayer_level_idc; + +} VVC_SublayerPTL; + +typedef struct +{ + u8 pt_present; + u8 ptl_max_tid; + + u8 general_profile_idc, general_tier_flag, general_level_idc, frame_only_constraint, multilayer_enabled; + VVC_SublayerPTL sub_ptl[8]; + + u8 num_sub_profiles; + u32 sub_profile_idc[255]; + + u8 gci_present; + //holds 81 bits, the last byte contains the remainder (low bit set, not high) + u8 gci[12]; +} VVC_ProfileTierLevel; + +typedef struct +{ + s32 id; + u8 state; + + HEVC_RateInfo rates[8]; + u32 max_layers, max_sub_layers; + Bool all_layers_independent, each_layer_is_ols; + u32 max_layer_id; //, num_layer_sets; + + u16 num_ptl; //max 256 + VVC_ProfileTierLevel ptl[256]; +} VVC_VPS; + +typedef struct +{ + u8 nal_unit_type; + u32 frame_num, poc_lsb, slice_type; + + u8 poc_msb_cycle_present_flag; + s32 poc; + u32 poc_msb, poc_msb_cycle, poc_msb_prev, poc_lsb_prev, frame_num_prev; + + VVC_SPS *sps; + VVC_PPS *pps; + + u8 picture_header_in_slice_header_flag, inter_slice_allowed_flag, intra_slice_allowed_flag; + u8 irap_or_gdr_pic; + u8 non_ref_pic; + u8 gdr_pic; + u32 gdr_recovery_count; + u8 recovery_point_valid, lmcs_enabled_flag, explicit_scaling_list_enabled_flag, temporal_mvp_enabled_flag; + + u8 prev_layer_id_plus1; + u8 compute_poc_defer; + + //picture header RPL state + VVC_RefPicList ph_rpl[2]; + s32 ph_rpl_idx[2]; + + //slive RPL state + VVC_RefPicList rpl[2]; + s32 rpl_idx[2]; + + //slice header size in bytes + u32 payload_start_offset; +} VVCSliceInfo; + +/*TODO once we add HLS parsing (FDIS) */ +typedef struct _vvc_state +{ + s8 sps_active_idx; /*currently active sps; must be initalized to -1 in order to discard not yet decodable SEIs*/ + + //-1 or the value of the vps/sps/pps ID of the nal just parsed + s32 last_parsed_vps_id; + s32 last_parsed_sps_id; + s32 last_parsed_pps_id; + s32 last_parsed_aps_id; + + VVC_SPS sps[16]; + VVC_PPS pps[64]; + VVC_VPS vps[16]; + + VVCSliceInfo s_info; + + //0: minimal parsing, used by most tools. Slice header and picture header are skipped + //1: full parsing, error check: used to retrieve end of slice header + //2: full parsing, no error check (used by dumpers) + u32 parse_mode; + + + u8 clli_data[4]; + u8 mdcv_data[24]; + u8 clli_valid, mdcv_valid; +} VVCState; + +s32 gf_vvc_parse_nalu_bs(GF_BitStream *bs, VVCState *vvc, u8 *nal_unit_type, u8 *temporal_id, u8 *layer_id); +void gf_vvc_parse_sei(char* buffer, u32 nal_size, VVCState *vvc); +Bool gf_vvc_slice_is_ref(VVCState *vvc); +s32 gf_vvc_parse_nalu(u8 *data, u32 size, VVCState *vvc, u8 *nal_unit_type, u8 *temporal_id, u8 *layer_id); + +void gf_vvc_parse_ps(GF_VVCConfig* hevccfg, VVCState* vvc, u32 nal_type); + + +GF_Err gf_media_parse_ivf_file_header(GF_BitStream *bs, u32 *width, u32*height, u32 *codec_fourcc, u32 *timebase_num, u32 *timebase_den, u32 *num_frames); #define VP9_MAX_FRAMES_IN_SUPERFRAME 16 -GF_Err gf_media_vp9_parse_sample(GF_BitStream *bs, GF_VPConfig *vp9_cfg, Bool *key_frame, u32 *FrameWidth, u32 *FrameHeight, u32 *renderWidth, u32 *renderHeight); -GF_Err gf_media_vp9_parse_superframe(GF_BitStream *bs, u64 ivf_frame_size, u32 *num_frames_in_superframe, u32 frame_sizes[VP9_MAX_FRAMES_IN_SUPERFRAME], u32 *superframe_index_size); +GF_Err gf_vp9_parse_sample(GF_BitStream *bs, GF_VPConfig *vp9_cfg, Bool *key_frame, u32 *FrameWidth, u32 *FrameHeight, u32 *renderWidth, u32 *renderHeight); +GF_Err gf_vp9_parse_superframe(GF_BitStream *bs, u64 ivf_frame_size, u32 *num_frames_in_superframe, u32 frame_sizes[VP9_MAX_FRAMES_IN_SUPERFRAME], u32 *superframe_index_size); @@ -616,7 +898,7 @@ typedef struct Bool mem_mode; /*bitstream object for mem mode - this bitstream is NOT destroyed by gf_av1_reset_state(state, GF_TRUE) */ GF_BitStream *bs; - Bool bs_overread, unframed; + Bool unframed; u8 *frame_obus; u32 frame_obus_alloc; @@ -626,6 +908,7 @@ typedef struct Bool decoder_model_info_present_flag; u16 OperatingPointIdc; u32 width, height, UpscaledWidth; + u32 sequence_width, sequence_height; u32 tb_num, tb_den; Bool use_128x128_superblock; @@ -679,21 +962,40 @@ typedef struct AV1GMParams SavedGmParams[AV1_NUM_REF_FRAMES]; u8 RefFrameType[AV1_NUM_REF_FRAMES]; + u32 RefUpscaledWidth[AV1_NUM_REF_FRAMES]; + u32 RefFrameHeight[AV1_NUM_REF_FRAMES]; + /*frame parsing state*/ AV1StateFrame frame_state; + + /*layer sizes for AVIF a1lx*/ + u32 layer_size[4]; + + + u8 clli_data[4]; + u8 mdcv_data[24]; + u8 clli_valid, mdcv_valid; + } AV1State; GF_Err aom_av1_parse_temporal_unit_from_section5(GF_BitStream *bs, AV1State *state); GF_Err aom_av1_parse_temporal_unit_from_annexb(GF_BitStream *bs, AV1State *state); GF_Err aom_av1_parse_temporal_unit_from_ivf(GF_BitStream *bs, AV1State *state); +/*may return GF_BUFFER_TOO_SMALL if not enough bytes*/ GF_Err gf_media_parse_ivf_frame_header(GF_BitStream *bs, u64 *frame_size, u64 *pts); Bool gf_media_probe_ivf(GF_BitStream *bs); Bool gf_media_aom_probe_annexb(GF_BitStream *bs); -/*parses one OBU*/ -GF_Err gf_media_aom_av1_parse_obu(GF_BitStream *bs, ObuType *obu_type, u64 *obu_size, u32 *obu_hdr_size, AV1State *state); +/*parses one OBU +\param bs bitstream object +\param obu_type OBU type +\param obu_size As an input the size of the input OBU (needed when obu_size is not coded). As an output the coded obu_size value. +\param obu_hdr_size OBU header size +\param state the frame parser +*/ +GF_Err gf_av1_parse_obu(GF_BitStream *bs, ObuType *obu_type, u64 *obu_size, u32 *obu_hdr_size, AV1State *state); Bool av1_is_obu_header(ObuType obu_type); diff --git a/include/gpac/internal/mesh.h b/include/gpac/internal/mesh.h index 15ab04b..ce4e699 100644 --- a/include/gpac/internal/mesh.h +++ b/include/gpac/internal/mesh.h @@ -201,6 +201,7 @@ void mesh_new_unit_bbox(GF_Mesh *mesh); /*insert base primitives - low res indicates less subdivision steps for circles (cone, cylinder, ellipse, sphere)*/ void mesh_new_rectangle(GF_Mesh *mesh, SFVec2f size, SFVec2f *orig, Bool flip); +void mesh_new_rectangle_ex(GF_Mesh *mesh, SFVec2f size, SFVec2f *orig, u32 flip, u32 rotate); void mesh_new_ellipse(GF_Mesh *mesh, Fixed a_dia, Fixed b_dia, Bool low_res); void mesh_new_box(GF_Mesh *mesh, SFVec3f size); void mesh_new_cylinder(GF_Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool top, Bool low_res); diff --git a/include/gpac/internal/odf_parse_common.h b/include/gpac/internal/odf_parse_common.h index 473c621..4b0b514 100644 --- a/include/gpac/internal/odf_parse_common.h +++ b/include/gpac/internal/odf_parse_common.h @@ -39,10 +39,10 @@ #define GET_DOUBLE(field) { Float v; ret = 1; sscanf(val, "%f", &v); field = (Double) v;} #define GET_STRING(field) { \ ret = 1;\ - field = gf_strdup(val); \ + (field) = gf_strdup(val); \ if (field) { \ - if (val[0] == '"') strcpy(field, val+1); \ - if (field[strlen(field)-1] == '"') field[strlen(field)-1] = 0;\ + if (val[0] == '"') strcpy((field), val+1); \ + if ((field)[strlen(field)-1] == '"') (field)[strlen(field)-1] = 0;\ }\ } diff --git a/include/gpac/internal/scenegraph_dev.h b/include/gpac/internal/scenegraph_dev.h index 1d80707..d8f2a10 100644 --- a/include/gpac/internal/scenegraph_dev.h +++ b/include/gpac/internal/scenegraph_dev.h @@ -280,6 +280,7 @@ struct __tag_scene_graph u32 (*get_element_class)(GF_Node *n); u32 (*get_document_class)(GF_SceneGraph *n); + struct __gf_filter_session *attached_session; #endif }; @@ -305,8 +306,10 @@ GF_Node *gf_sg_new_base_node(); struct _route { u8 is_setup; - /*set to true for proto IS fields*/ + /*set to 1 for proto IS fields*/ u8 IS_route; + /*set to 1 for JS route to fun*/ + u8 script_route; u32 ID; char *name; @@ -496,7 +499,7 @@ typedef struct _proto_instance /*Prototype interface for coding and field addressing*/ GF_Proto *proto_interface; - /*proto implementation at run-time (aka the state of the nodes may differ accross + /*proto implementation at run-time (aka the state of the nodes may differ across different instances of the proto)*/ GF_List *fields; @@ -677,7 +680,7 @@ struct _smil_timing_rti SMIL_Interval *current_interval; SMIL_Interval *next_interval; - /* Evaluation of animations is postponed untill tree traversal, so that inherit values can be computed + /* Evaluation of animations is postponed until tree traversal, so that inherit values can be computed Other timed elements (audio, video, animation) are evaluated directly and do not require scene tree traversal.*/ Bool postpone; @@ -942,7 +945,7 @@ GF_Err gf_dom_listener_del(GF_Node *listener, GF_DOMEventTarget *target); GF_DOMHandler *gf_dom_listener_build_ex(GF_Node *node, u32 event_type, u32 event_parameter, GF_Node *handler, GF_Node **out_listener); void gf_dom_event_dump_listeners(GF_Node *n, FILE *f); -void gf_dom_event_remove_all_listeners(GF_DOMEventTarget *event_target); +void gf_dom_event_remove_all_listeners(GF_DOMEventTarget *event_target, GF_SceneGraph *sg); void gf_dom_event_target_del(GF_DOMEventTarget *target); GF_Err gf_dom_event_remove_listener_from_parent(GF_DOMEventTarget *event_target, GF_Node *listener); diff --git a/include/gpac/internal/swf_dev.h b/include/gpac/internal/swf_dev.h index b5ff36b..5b7dc4a 100644 --- a/include/gpac/internal/swf_dev.h +++ b/include/gpac/internal/swf_dev.h @@ -133,7 +133,7 @@ struct SWFReader GF_Err (*define_text)(SWFReader *read, SWFText *text); GF_Err (*define_edit_text)(SWFReader *read, SWFEditText *text); /*@button is NULL to signal end of button declaration, non-null otherwise. "action" callback will be - called inbetween*/ + called in between*/ GF_Err (*define_button)(SWFReader *read, SWF_Button *button); GF_Err (*setup_image)(SWFReader *read, u32 ID, char *fileName); diff --git a/include/gpac/isomedia.h b/include/gpac/isomedia.h index 76aa8e2..cb4b5bb 100644 --- a/include/gpac/isomedia.h +++ b/include/gpac/isomedia.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / ISO Media File Format sub-project @@ -142,8 +142,16 @@ enum GF_ISOM_REF_LYRA = GF_4CC( 'l', 'y', 'r', 'a' ), /*! File Delivery Item Information Extension */ GF_ISOM_REF_FDEL = GF_4CC( 'f', 'd', 'e', 'l' ), +#ifdef GF_ENABLE_CTRN /*! Track fragment inherit */ GF_ISOM_REF_TRIN = GF_4CC( 't', 'r', 'i', 'n' ), +#endif + + /*! Item auxiliary reference */ + GF_ISOM_REF_AUXR = GF_4CC( 'a', 'u', 'x', 'r' ), + + /*! ref type for the VVC subpicture tracks*/ + GF_ISOM_REF_SUBPIC = GF_4CC( 's', 'u', 'b', 'p' ), }; /*! Track Edit list type*/ @@ -226,6 +234,12 @@ enum GF_ISOM_SUBTYPE_LHE1 = GF_4CC( 'l', 'h', 'e', '1' ), GF_ISOM_SUBTYPE_HVT1 = GF_4CC( 'h', 'v', 't', '1' ), + /*VVC media types*/ + GF_ISOM_SUBTYPE_VVC1 = GF_4CC( 'v', 'v', 'c', '1' ), + GF_ISOM_SUBTYPE_VVI1 = GF_4CC( 'v', 'v', 'i', '1' ), + GF_ISOM_SUBTYPE_VVS1 = GF_4CC( 'v', 'v', 's', '1' ), + GF_ISOM_SUBTYPE_VVCN = GF_4CC( 'v', 'v', 'c', 'N' ), + /*AV1 media type*/ GF_ISOM_SUBTYPE_AV01 = GF_4CC('a', 'v', '0', '1'), @@ -240,6 +254,10 @@ enum /* Dolby Vision */ GF_ISOM_SUBTYPE_DVHE = GF_4CC('d', 'v', 'h', 'e'), + GF_ISOM_SUBTYPE_DVH1 = GF_4CC('d', 'v', 'h', '1'), + GF_ISOM_SUBTYPE_DVA1 = GF_4CC('d', 'v', 'a', '1'), + GF_ISOM_SUBTYPE_DVAV = GF_4CC('d', 'v', 'a', 'v'), + GF_ISOM_SUBTYPE_DAV1 = GF_4CC('d', 'a', 'v', '1'), /*3GPP(2) extension subtypes*/ GF_ISOM_SUBTYPE_3GP_H263 = GF_4CC( 's', '2', '6', '3' ), @@ -255,6 +273,8 @@ enum GF_ISOM_SUBTYPE_AC3 = GF_4CC( 'a', 'c', '-', '3' ), GF_ISOM_SUBTYPE_EC3 = GF_4CC( 'e', 'c', '-', '3' ), GF_ISOM_SUBTYPE_MP3 = GF_4CC( '.', 'm', 'p', '3' ), + GF_ISOM_SUBTYPE_MLPA = GF_4CC( 'm', 'l', 'p', 'a' ), + GF_ISOM_SUBTYPE_MP4A = GF_4CC( 'm', 'p', '4', 'a' ), GF_ISOM_SUBTYPE_MP4S = GF_4CC( 'm', 'p', '4', 's' ), @@ -300,6 +320,7 @@ enum GF_ISOM_SUBTYPE_RICC = GF_4CC( 'r', 'I', 'C', 'C' ), /* QT audio codecs */ + //this one is also used for 24bit RGB GF_QT_SUBTYPE_RAW = GF_4CC('r','a','w',' '), GF_QT_SUBTYPE_TWOS = GF_4CC('t','w','o','s'), GF_QT_SUBTYPE_SOWT = GF_4CC('s','o','w','t'), @@ -325,11 +346,27 @@ enum GF_QT_SUBTYPE_APCS = GF_4CC( 'a', 'p', 'c', 's' ), GF_QT_SUBTYPE_AP4X = GF_4CC( 'a', 'p', '4', 'x' ), GF_QT_SUBTYPE_AP4H = GF_4CC( 'a', 'p', '4', 'h' ), - GF_QT_SUBTYPE_YUV422 = GF_4CC('y','u','v','2'), -// GF_QT_SUBTYPE_YUV422 = GF_4CC('2','v','u','Y'), - GF_QT_SUBTYPE_YUV444 = GF_4CC('v','3','0','8'), - GF_QT_SUBTYPE_YUV422_10 = GF_4CC('v','2','1','0'), - GF_QT_SUBTYPE_YUV444_10 = GF_4CC('v','4','1','0'), + GF_QT_SUBTYPE_YUYV = GF_4CC('y','u','v','2'), + GF_QT_SUBTYPE_UYVY = GF_4CC('2','v','u','y'), + GF_QT_SUBTYPE_YUV444 = GF_4CC('v','3','0','8'), + GF_QT_SUBTYPE_YUVA444 = GF_4CC('v','4','0','8'), + GF_QT_SUBTYPE_YUV422_10 = GF_4CC('v','2','1','0'), + GF_QT_SUBTYPE_YUV444_10 = GF_4CC('v','4','1','0'), + GF_QT_SUBTYPE_YUV422_16 = GF_4CC('v','2','1','6'), + GF_QT_SUBTYPE_YUV420 = GF_4CC('j','4','2','0'), + GF_QT_SUBTYPE_I420 = GF_4CC('I','4','2','0'), + GF_QT_SUBTYPE_IYUV = GF_4CC('I','Y','U','V'), + GF_QT_SUBTYPE_YV12 = GF_4CC('y','v','1','2'), + GF_QT_SUBTYPE_YVYU = GF_4CC('Y','V','Y','U'), + GF_QT_SUBTYPE_RGBA = GF_4CC('R','G','B','A'), + GF_QT_SUBTYPE_ABGR = GF_4CC('A','B','G','R'), + + GF_ISOM_SUBTYPE_FFV1 = GF_4CC( 'F', 'F', 'V', '1' ), + + GF_ISOM_ITEM_TYPE_AUXI = GF_4CC('a', 'u', 'x', 'i'), + + GF_QT_SUBTYPE_TMCD = GF_4CC( 't', 'm', 'c', 'd' ), + }; @@ -388,11 +425,14 @@ enum /*file complying to the generic ISO Media File (base specification ISO/IEC 14496-12) + support for version 1*/ GF_ISOM_BRAND_ISO4 = GF_4CC( 'i', 's', 'o', '4' ), /* Image File Format */ + GF_ISOM_BRAND_HEIF = GF_4CC('h', 'e', 'i', 'f'), GF_ISOM_BRAND_MIF1 = GF_4CC('m', 'i', 'f', '1'), GF_ISOM_BRAND_HEIC = GF_4CC('h', 'e', 'i', 'c'), GF_ISOM_BRAND_HEIM = GF_4CC('h', 'e', 'i', 'm'), GF_ISOM_BRAND_AVIF = GF_4CC('a', 'v', 'i', 'f'), GF_ISOM_BRAND_AVCI = GF_4CC('a', 'v', 'c', 'i'), + GF_ISOM_BRAND_VVIC = GF_4CC('v', 'v', 'i', 'c'), + /*other iso media brands */ GF_ISOM_BRAND_ISO1 = GF_4CC( 'i', 's', 'o', '1' ), GF_ISOM_BRAND_ISO3 = GF_4CC( 'i', 's', 'o', '3' ), @@ -444,6 +484,10 @@ enum /* Subsegment Index Segment used to index MPEG-2 TS based Media Segments */ GF_ISOM_BRAND_SSSS = GF_4CC('s','s','s','s'), + /* CMAF brand */ + GF_ISOM_BRAND_CMFC = GF_4CC('c','m','f','c'), + /* CMAF brand with neg ctts */ + GF_ISOM_BRAND_CMF2 = GF_4CC('c','m','f','2'), /* from ismacryp.c */ /* OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A) */ @@ -451,6 +495,10 @@ enum /* OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C) */ GF_ISOM_BRAND_OPF2 = GF_4CC('o','p','f','2'), + /* compressed brand*/ + GF_ISOM_BRAND_COMP = GF_4CC( 'c', 'o', 'm', 'p' ), + GF_ISOM_BRAND_ISOC = GF_4CC( 'i', 's', 'o', 'C' ), + }; /*! sample roll information type*/ @@ -530,9 +578,8 @@ typedef struct \return the newly allocated ISO sample*/ GF_ISOSample *gf_isom_sample_new(); -/*! delete a sample. NOTE:the buffer content will be destroyed by default. -if you wish to keep the buffer, set dataLength to 0 in the sample -before deleting it +/*! delete a sample. +\note The buffer content will be destroyed by default. If you wish to keep the buffer, set dataLength to 0 in the sample before deleting it the pointer is set to NULL after deletion \param samp pointer to the target ISO sample */ @@ -565,6 +612,10 @@ typedef enum GF_ISOM_WRITE_EDIT, /*! Opens an existing file and keep fragment information*/ GF_ISOM_OPEN_KEEP_FRAGMENTS, + /*! Opens an existing file in READ ONLY mode but enables most of the file edit functions except fragmentation + Samples may be added to the file in this mode, they will be stored in memory + */ + GF_ISOM_OPEN_READ_EDIT, } GF_ISOOpenMode; /*! indicates if target file is an IsoMedia file @@ -592,8 +643,7 @@ u32 gf_isom_probe_data(const u8*inBuf, u32 inSize); If fileName is NULL data will be written in memory ; write with gf_isom_write() ; use gf_isom_get_bs() to get the data ; use gf_isom_delete() to delete the internal data. \param fileName name of the file to open, , gmem:// or gfio:// resource. The special name "_gpac_isobmff_redirect" is used to indicate that segment shall be written to a memory buffer passed to callback function set through \ref gf_isom_set_write_callback. \param OpenMode file opening mode -\param tmp_dir for the 2 edit modes only, specifies a location for temp file. If NULL, the library will use the default -OS temporary file management schemes. +\param tmp_dir for the 2 edit modes only, specifies a location for temp file. If NULL, the library will use the default libgpac temporary file management schemes. \return the created ISO file if no error */ GF_ISOFile *gf_isom_open(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir); @@ -611,7 +661,7 @@ void gf_isom_delete(GF_ISOFile *isom_file); /*! gets the last fatal error that occured in the file ANY FUNCTION OF THIS API WON'T BE PROCESSED IF THE FILE HAS AN ERROR -Note: some function may return an error while the movie has no error +\note Some function may return an error while the movie has no error the last error is a FatalError, and is not always set if a bad param is specified... \param isom_file the target ISO file @@ -678,7 +728,7 @@ Bool gf_isom_moov_first(GF_ISOFile *isom_file); /*! when reading a file, indicates that file data is missing the indicated bytes \param isom_file the target ISO file -\param byte_offset number of bytes not present at the begining of the file +\param byte_offset number of bytes not present at the beginning of the file \return error if any */ GF_Err gf_isom_set_byte_offset(GF_ISOFile *isom_file, s64 byte_offset); @@ -764,6 +814,16 @@ u64 gf_isom_get_original_duration(GF_ISOFile *isom_file); */ GF_Err gf_isom_get_creation_time(GF_ISOFile *isom_file, u64 *creationTime, u64 *modificationTime); + +/*! gets the creation info of the movie +\param isom_file the target ISO file +\param trackNumber the target track +\param creationTime set to the creation time of the movie +\param modificationTime set to the modification time of the movie +\return error if any +*/ +GF_Err gf_isom_get_track_creation_time(GF_ISOFile *isom_file, u32 trackNumber, u64 *creationTime, u64 *modificationTime); + /*! gets the ID of a track \param isom_file the target ISO file \param trackNumber the target track @@ -837,11 +897,11 @@ u32 gf_isom_get_sample_description_count(GF_ISOFile *isom_file, u32 trackNumber) \return the sample description index, or 0 if error or if empty*/ u32 gf_isom_get_sample_description_index(GF_ISOFile *isom_file, u32 trackNumber, u64 for_time); -/*! checks if a sample stream descritpion is self-contained (samples located in the file) +/*! checks if a sample stream description is self-contained (samples located in the file) \param isom_file the target ISO file \param trackNumber the target track \param sampleDescriptionIndex the target sample description index (1-based) -\return GF_TRUE if samples refering to the given stream description are present in the file, GF_FALSE otherwise*/ +\return GF_TRUE if samples referring to the given stream description are present in the file, GF_FALSE otherwise*/ Bool gf_isom_is_self_contained(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); /*! gets the media duration (without edit) based on sample table @@ -943,7 +1003,7 @@ u64 gf_isom_get_media_data_size(GF_ISOFile *isom_file, u32 trackNumber); /*! sets sample padding bytes when reading a sample It may be desired to fetch samples with a bigger allocated buffer than their real size, in case the decoder reads more data than available. This sets the amount of extra bytes to allocate when reading samples from this track -NOTE: the dataLength of the sample does NOT include padding +\note The dataLength of the sample does NOT include padding \param isom_file the target ISO file \param trackNumber the target track \param padding_bytes the amount of bytes to add at the end of a sample data buffer @@ -981,7 +1041,7 @@ GF_ISOSample *gf_isom_get_sample_ex(GF_ISOFile *isom_file, u32 trackNumber, u32 \param sampleNumber the desired sample number (1-based index) \param sampleDescriptionIndex set to the sample description index corresponding to this sample (optional, can be NULL) \param data_offset set to the sample start offset in file (optional, can be NULL) -\note: when both sampleDescriptionIndex and data_offset are NULL, only DTS, CTS_Offset and RAP indications are retrieved (faster) +\note When both sampleDescriptionIndex and data_offset are NULL, only DTS, CTS_Offset and RAP indications are retrieved (faster) \return the ISO sample without data or NULL if not found or end of stream or incomplete file. Use \ref gf_isom_last_error to check the error code */ GF_ISOSample *gf_isom_get_sample_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset); @@ -992,7 +1052,7 @@ GF_ISOSample *gf_isom_get_sample_info(GF_ISOFile *isom_file, u32 trackNumber, u3 \param sampleNumber the desired sample number (1-based index) \param sampleDescriptionIndex set to the sample description index corresponding to this sample (optional, can be NULL) \param data_offset set to the sample start offset in file (optional, can be NULL) -\note: when both sampleDescriptionIndex and data_offset are NULL, only DTS, CTS_Offset and RAP indications are retrieved (faster) +\note When both sampleDescriptionIndex and data_offset are NULL, only DTS, CTS_Offset and RAP indications are retrieved (faster) \param static_sample a caller-allocated ISO sample to use as the returned sample \return the ISO sample without data or NULL if not found or end of stream or incomplete file. Use \ref gf_isom_last_error to check the error code \note If the function returns NULL, the static_sample and its associated data if any are NOT destroyed @@ -1068,7 +1128,7 @@ GF_Err gf_isom_get_sample_flags(GF_ISOFile *isom_file, u32 trackNumber, u32 samp /*! gets a sample given a desired decoding time and set the sampleDescriptionIndex of this sample -WARNING: the sample may not be sync even though the sync was requested (depends on the media and the editList) +\warning The sample may not be sync even though the sync was requested (depends on the media and the editList) the SampleNum is optional. If non-NULL, will contain the sampleNumber \param isom_file the target ISO file @@ -1092,6 +1152,16 @@ GF_Err gf_isom_get_sample_for_media_time(GF_ISOFile *isom_file, u32 trackNumber, */ u32 gf_isom_get_sample_from_dts(GF_ISOFile *isom_file, u32 trackNumber, u64 dts); + +/*! enumerates the type and references IDs of a track +\param isom_file the target ISO file +\param trackNumber the target track +\param idx 0-based index of reference to query +\param referenceType set to the four character code of the reference entry +\param referenceCount set to the number of track ID references for the reference entry +\return list of track IDs, NULL if no references - do NOT modify !*/ +const GF_ISOTrackID *gf_isom_enum_track_references(GF_ISOFile *isom_file, u32 trackNumber, u32 idx, u32 *referenceType, u32 *referenceCount); + /*! get the number of track references of a track for a given ReferenceType \param isom_file the target ISO file \param trackNumber the target track @@ -1132,9 +1202,9 @@ u32 gf_isom_has_track_reference(GF_ISOFile *isom_file, u32 trackNumber, u32 refe if no sample is playing, an empty sample is returned with no data and a DTS set to MovieTime when searching in sync modes if no sample is playing, the closest sample in the edit time-line is returned when searching in regular modes -WARNING: the sample may not be sync even though the sync was requested (depends on the media and the editList) +\warning The sample may not be sync even though the sync was requested (depends on the media and the editList) -Note: this function will handle re-timestamping the sample according to the mapping of the media time-line +\note This function will handle re-timestamping the sample according to the mapping of the media time-line on the track time-line. The sample TSs (DTS / CTS offset) are expressed in MEDIA TIME SCALE (to match the media stream TS resolution as indicated in media header / SLConfig) @@ -1416,6 +1486,64 @@ GF_Err gf_isom_get_pixel_aspect_ratio(GF_ISOFile *isom_file, u32 trackNumber, u3 \return error if any*/ GF_Err gf_isom_get_color_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *colour_type, u16 *colour_primaries, u16 *transfer_characteristics, u16 *matrix_coefficients, Bool *full_range_flag); + +/*! gets clean aperture (crop window, see ISO/IEC 14496-12) for a sample description +\param isom_file the target ISO file +\param trackNumber the target track number +\param sampleDescriptionIndex the target sample description index +\param cleanApertureWidthN set to nominator of clean aperture horizontal size, may be NULL +\param cleanApertureWidthD set to denominator of clean aperture horizontal size, may be NULL +\param cleanApertureHeightN set to nominator of clean aperture vertical size, may be NULL +\param cleanApertureHeightD set to denominator of clean aperture vertical size, may be NULL +\param horizOffN set to nominator of horizontal offset of clean aperture center minus (width-1)/2 (eg 0 sets center to center of video), may be NULL +\param horizOffD set to denominator of horizontal offset of clean aperture center minus (width-1)/2 (eg 0 sets center to center of video), may be NULL +\param vertOffN set to nominator of vertical offset of clean aperture center minus (height-1)/2 (eg 0 sets center to center of video), may be NULL +\param vertOffD set to denominator of vertical offset of clean aperture center minus (height-1)/2 (eg 0 sets center to center of video), may be NULL +\return error if any +*/ +GF_Err gf_isom_get_clean_aperture(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *cleanApertureWidthN, u32 *cleanApertureWidthD, u32 *cleanApertureHeightN, u32 *cleanApertureHeightD, s32 *horizOffN, u32 *horizOffD, s32 *vertOffN, u32 *vertOffD); + +/*! content light level info*/ +typedef struct { + /*! max content ligth level*/ + u16 max_content_light_level; + /*! max picture average ligth level*/ + u16 max_pic_average_light_level; +} GF_ContentLightLevelInfo; + +/*! mastering display colour volume info*/ +typedef struct { + /*! display primaries*/ + struct { + u16 x; + u16 y; + } display_primaries[3]; + /*! X white point*/ + u16 white_point_x; + /*! Y white point*/ + u16 white_point_y; + u32 max_display_mastering_luminance; + /*! min display mastering luminance*/ + u32 min_display_mastering_luminance; +} GF_MasteringDisplayColourVolumeInfo; + +/*! gets master display colour info if any +\param isom_file the target ISO file +\param trackNumber the target track number +\param sampleDescriptionIndex the target sample description index +\return the mdcv info, or NULL if none or not a valid video track +*/ +const GF_MasteringDisplayColourVolumeInfo *gf_isom_get_mastering_display_colour_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); + +/*! gets content light level info if any +\param isom_file the target ISO file +\param trackNumber the target track number +\param sampleDescriptionIndex the target sample description index +\return the clli info, or NULL if none or not a valid video track +*/ +const GF_ContentLightLevelInfo *gf_isom_get_content_light_level_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); + + /*! gets the media language code of a track \param isom_file the target ISO file \param trackNumber the target track @@ -1446,6 +1574,14 @@ GF_Err gf_isom_get_track_kind(GF_ISOFile *isom_file, u32 trackNumber, u32 index, */ u64 gf_isom_get_track_magic(GF_ISOFile *isom_file, u32 trackNumber); +/*! gets track group ID of a given track group type for this track +\param isom_file the target ISO file +\param trackNumber the target track +\param track_group_type the target track group type +\return the track group ID, 0 if not found +*/ +u32 gf_isom_get_track_group(GF_ISOFile *isom_file, u32 trackNumber, u32 track_group_type); + /*! checks if file is a single AV file with max one audio, one video, one text and basic od/bifs \param isom_file the target ISO file \return GF_TRUE if file is single AV, GF_FALSE otherwise @@ -1533,7 +1669,6 @@ GF_Err gf_isom_get_current_top_box_offset(GF_ISOFile *isom_file, u64 *current_to */ GF_Err gf_isom_purge_samples(GF_ISOFile *isom_file, u32 trackNumber, u32 nb_samples); - #ifndef GPAC_DISABLE_ISOM_DUMP /*! dumps file structures into XML trace file @@ -1548,6 +1683,40 @@ GF_Err gf_isom_dump(GF_ISOFile *isom_file, FILE *trace, Bool skip_init, Bool ski #endif /*GPAC_DISABLE_ISOM_DUMP*/ +/*! gets number of chunks in track +\param isom_file the target ISO file +\param trackNumber the desired track to purge +\return number of chunks in track +*/ +u32 gf_isom_get_chunk_count(GF_ISOFile *isom_file, u32 trackNumber); + +/*! gets info for a given chunk in track +\param isom_file the target ISO file +\param trackNumber the desired track to purge +\param chunkNumber the 1-based index of the desired chunk +\param chunk_offset set to the chunk offset in bytes from start of file +\param first_sample_num set to the sample number of the first sample in the chunk +\param sample_per_chunk set to number of samples per chunk +\param sample_desc_idx set to sample desc index of samples of this chunk +\param cache_1 updated by function at each call. May be NULL (slower). Must be set to 0 if not querying consecutive chunks +\param cache_2 updated by function at each call. May be NULL (slower). Must be set to 0 if not querying consecutive chunks +\return error if any +*/ +GF_Err gf_isom_get_chunk_info(GF_ISOFile *isom_file, u32 trackNumber, u32 chunkNumber, u64 *chunk_offset, u32 *first_sample_num, u32 *sample_per_chunk, u32 *sample_desc_idx, u32 *cache_1, u32 *cache_2); + + +/*! gets the file offset of the first usable byte of the first mdat box in the file +\param isom_file the target ISO file +\return byte offset +*/ +u64 gf_isom_get_first_mdat_start(GF_ISOFile *isom_file); + +/*! gets the size of all skip, free and wide boxes present in the file and bytes skipped during parsing (assumes a single file was opened) +\param isom_file the target ISO file +\return size +*/ +u64 gf_isom_get_unused_box_bytes(GF_ISOFile *isom_file); + /*! @} */ @@ -1600,6 +1769,12 @@ GF_Err gf_isom_freeze_order(GF_ISOFile *isom_file); */ void gf_isom_keep_utc_times(GF_ISOFile *isom_file, Bool keep_utc); +/*! Checks if UTC keeping is enabled +\param isom_file the target ISO file +\return GF_TRUE if UTC keeping is enabled +*/ +Bool gf_isom_has_keep_utc_times(GF_ISOFile *isom_file); + /*! sets the timescale of the movie. This rescales times expressed in movie timescale in edit lists and mvex boxes \param isom_file the target ISO file \param timeScale the target timescale @@ -1636,7 +1811,7 @@ u32 gf_isom_new_track(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u32 MediaTyp u32 gf_isom_new_track_from_template(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u32 MediaType, u32 TimeScale, u8 *tk_box, u32 tk_box_size, Bool udta_only); /*! removes a track - internal cross dependencies will be updated. -WARNING: any OD streams with references to this track through ODUpdate, ESDUpdate, ESDRemove commands +\warning Any OD streams with references to this track through ODUpdate, ESDUpdate, ESDRemove commands will be rewritten \param isom_file the target ISO file \param trackNumber the target track to remove file @@ -1656,13 +1831,27 @@ GF_Err gf_isom_set_track_enabled(GF_ISOFile *isom_file, u32 trackNumber, Bool en typedef enum { /*! set flags, erasing previous value*/ - GF_ISOM_TKFLAGS_SET = 0, + GF_ISOM_TKFLAGS_SET = 1, /*! add flags*/ GF_ISOM_TKFLAGS_REM, /*! remove flags*/ GF_ISOM_TKFLAGS_ADD, } GF_ISOMTrackFlagOp; + +/*! Track header flags*/ +enum +{ + /*! track is enabled */ + GF_ISOM_TK_ENABLED = 1, + /*! track is in regular presentation*/ + GF_ISOM_TK_IN_MOVIE = 1<<1, + /*! track is in preview*/ + GF_ISOM_TK_IN_PREVIEW = 1<<2, + /*! track size is an aspect ratio indicator only*/ + GF_ISOM_TK_SIZE_IS_AR = 1<<3 +}; + /*! toggles track flags on or off \param isom_file the target ISO file \param trackNumber the target track @@ -1672,20 +1861,31 @@ typedef enum */ GF_Err gf_isom_set_track_flags(GF_ISOFile *isom_file, u32 trackNumber, u32 flags, GF_ISOMTrackFlagOp op); -/*! sets creationTime and modificationTime of the movie to the specified date +/*! sets creationTime and modificationTime of the movie to the specified dates (no validty check) +\param isom_file the target ISO file +\param create_time the new creation time +\param modif_time the new modification time +\return error if any +*/ +GF_Err gf_isom_set_creation_time(GF_ISOFile *isom_file, u64 create_time, u64 modif_time); + +/*! sets creationTime and modificationTime of the track to the specified dates \param isom_file the target ISO file -\param time the new time +\param trackNumber the target track +\param create_time the new creation time +\param modif_time the new modification time \return error if any */ -GF_Err gf_isom_set_creation_time(GF_ISOFile *isom_file, u64 time); +GF_Err gf_isom_set_track_creation_time(GF_ISOFile *isom_file, u32 trackNumber, u64 create_time, u64 modif_time); -/*! sets creationTime and modificationTime of the track to the specified date +/*! sets creationTime and modificationTime of the track media header to the specified dates \param isom_file the target ISO file \param trackNumber the target track -\param time the new time +\param create_time the new creation time +\param modif_time the new modification time \return error if any */ -GF_Err gf_isom_set_track_creation_time(GF_ISOFile *isom_file,u32 trackNumber, u64 time); +GF_Err gf_isom_set_media_creation_time(GF_ISOFile *isom_file, u32 trackNumber, u64 create_time, u64 modif_time); /*! changes the ID of a track - all track references present in the file are updated \param isom_file the target ISO file @@ -1787,7 +1987,7 @@ GF_Err gf_isom_patch_last_sample_duration(GF_ISOFile *isom_file, u32 trackNumber \param isom_file the target ISO file \param trackNumber the target track \param referenceType the four character code of the reference -\param ReferencedTrackID the ID of the track refered to +\param ReferencedTrackID the ID of the track referred to \return error if any */ GF_Err gf_isom_set_track_reference(GF_ISOFile *isom_file, u32 trackNumber, u32 referenceType, GF_ISOTrackID ReferencedTrackID); @@ -1799,6 +1999,21 @@ GF_Err gf_isom_set_track_reference(GF_ISOFile *isom_file, u32 trackNumber, u32 r */ GF_Err gf_isom_remove_track_references(GF_ISOFile *isom_file, u32 trackNumber); +/*! removes any track reference poiting to a non-existing track +\param isom_file the target ISO file +\param trackNumber the target track +\return error if any +*/ +GF_Err gf_isom_purge_track_reference(GF_ISOFile *isom_file, u32 trackNumber); + +/*! removes all track references of a given type +\param isom_file the target ISO file +\param trackNumber the target track +\param ref_type the reference type to remove +\return error if any +*/ +GF_Err gf_isom_remove_track_reference(GF_ISOFile *isom_file, u32 trackNumber, u32 ref_type); + /*! sets track handler name. \param isom_file the target ISO file \param trackNumber the target track @@ -1850,16 +2065,35 @@ GF_Err gf_isom_update_sample_reference(GF_ISOFile *isom_file, u32 trackNumber, u */ GF_Err gf_isom_remove_sample(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber); + /*! changes media time scale \param isom_file the target ISO file \param trackNumber the target track \param new_timescale the new timescale to set \param new_tsinc if not 0, changes sample duration and composition offsets to new_tsinc/new_timescale. If non-constant sample dur is used, uses the samllest sample dur in the track. Otherwise, only changes the timescale -\param force_rescale if set to GF_TRUE, only the media timescale is changed but media times are not updated. Ignored if new_tsinc is not 0. +\param force_rescale_type type fo rescaling, Ignored if new_tsinc is not 0: + - if set to 0, rescale timings. + - if set to 1, only the media timescale is changed but media times are not updated. + - if set to 2, media timescale is updated if new_timescale is set, and all sample durations are set to new_tsinc \return GF_EOS if no action taken (same config), or error if any */ -GF_Err gf_isom_set_media_timescale(GF_ISOFile *isom_file, u32 trackNumber, u32 new_timescale, u32 new_tsinc, Bool force_rescale); +GF_Err gf_isom_set_media_timescale(GF_ISOFile *isom_file, u32 trackNumber, u32 new_timescale, u32 new_tsinc, u32 force_rescale_type); + + + +/*! adds sample auxiliary data + +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleNumber the sample number. Must be equal or larger to last auxiliary +\param aux_type auxiliary sample data type, shall not be 0 +\param aux_info auxiliary sample data specific info type, may be 0 +\param data data to add +\param size size of data to add +\return error if any +*/ +GF_Err gf_isom_add_sample_aux_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 aux_type, u32 aux_info, u8 *data, u32 size); /*! sets the save file name of the (edited) movie. If the movie is edited, the default fileName is the open name suffixed with an internally defined extension "%p_isotmp")" @@ -1897,26 +2131,35 @@ GF_Err gf_isom_force_64bit_chunk_offset(GF_ISOFile *isom_file, Bool set_on); typedef enum { /*! no compression is used*/ - GF_ISO_COMP_NONE=0, + GF_ISOM_COMP_NONE=0, /*! only moov box is compressed*/ - GF_ISO_COMP_MOOV, + GF_ISOM_COMP_MOOV, /*! only moof boxes are compressed*/ - GF_ISO_COMP_MOOF, + GF_ISOM_COMP_MOOF, /*! only moof and sidx boxes are compressed*/ - GF_ISO_COMP_MOOF_SIDX, + GF_ISOM_COMP_MOOF_SIDX, /*! only moof, sidx and ssix boxes are compressed*/ - GF_ISO_COMP_MOOF_SSIX, + GF_ISOM_COMP_MOOF_SSIX, /*! all (moov, moof, sidx and ssix) boxes are compressed*/ - GF_ISO_COMP_ALL, + GF_ISOM_COMP_ALL, } GF_ISOCompressMode; +enum +{ + /*! forces compressed box even if compress size is larger than uncompressed size*/ + GF_ISOM_COMP_FORCE_ALL = 0x01, + /*! wraps ftyp in otyp*/ + GF_ISOM_COMP_WRAP_FTYPE = 0x02, +}; + + /*! sets compression mode of file \param isom_file the target ISO file \param compress_mode the desired compress mode -\param force_compress forces compressed box even if compress size is larger than uncompressed size +\param compress_flags compress mode flags \return error if any */ -GF_Err gf_isom_enable_compression(GF_ISOFile *isom_file, GF_ISOCompressMode compress_mode, Bool force_compress); +GF_Err gf_isom_enable_compression(GF_ISOFile *isom_file, GF_ISOCompressMode compress_mode, u32 compress_flags); /*! sets the copyright in one language \param isom_file the target ISO file @@ -1945,7 +2188,7 @@ GF_Err gf_isom_add_track_kind(GF_ISOFile *isom_file, u32 trackNumber, const char GF_Err gf_isom_remove_track_kind(GF_ISOFile *isom_file, u32 trackNumber, const char *schemeURI, const char *value); /*! changes the handler type of the media -\warning this may completely breaks the parsing of the media track +\warning This may completely breaks the parsing of the media track \param isom_file the target ISO file \param trackNumber the target track \param new_type the new handler four character type @@ -1954,7 +2197,7 @@ GF_Err gf_isom_remove_track_kind(GF_ISOFile *isom_file, u32 trackNumber, const c GF_Err gf_isom_set_media_type(GF_ISOFile *isom_file, u32 trackNumber, u32 new_type); /*! changes the type of the sampleDescriptionBox -\warning this may completely breaks the parsing of the media track +\warning This may completely breaks the parsing of the media track \param isom_file the target ISO file \param trackNumber the target track \param sampleDescriptionIndex the target sample description index @@ -2002,10 +2245,29 @@ the media normal timing. EditTime and EditDuration are expressed in movie timesc \param EditDuration the duration of the edit in movie timecale \param MediaTime the corresponding media time of the start of the edit, in media timescale. -1 for empty edits \param EditMode the edit mode -\return error if any +\return error if any, GF_EOS if empty edit was inserted */ GF_Err gf_isom_set_edit(GF_ISOFile *isom_file, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode); + + +/*! updates or inserts a new edit in the track time line. Edits are used to modify +the media normal timing. EditTime and EditDuration are expressed in movie timescale +\note If a segment with EditTime already exists, it is erase +\note If there is a segment before this new one, its duration is adjust to match EditTime of the new segment +\warning The first segment always have an EditTime of 0. You should insert an empty or dwelled segment first + +\param isom_file the target ISO file +\param trackNumber the target track +\param EditTime the start of the edit in movie timescale +\param EditDuration the duration of the edit in movie timecale +\param MediaTime the corresponding media time of the start of the edit, in media timescale. -1 for empty edits +\param MediaRate a 16.16 rate (0x10000 means normal playback) +\return error if any +*/ +GF_Err gf_isom_set_edit_with_rate(GF_ISOFile *isom_file, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u32 MediaRate); + + /*! same as \ref gf_isom_set_edit except only modifies duration type and mediaType \param isom_file the target ISO file \param trackNumber the target track @@ -2078,6 +2340,13 @@ compaction is done automatically while writing based on the track's sample sizes */ GF_Err gf_isom_use_compact_size(GF_ISOFile *isom_file, u32 trackNumber, Bool CompactionOn); +/*! disabled brand rewrite for file, usually done for temporary import in an existing file +\param isom_file the target ISO file +\param do_disable if true, brand rewrite is disabled, otherwise enabled +\return error if any +*/ +GF_Err gf_isom_disable_brand_rewrite(GF_ISOFile *isom_file, Bool do_disable); + /*! sets the brand of the movie \note this automatically adds the major brand to the set of alternate brands if not present \param isom_file the target ISO file @@ -2102,6 +2371,13 @@ GF_Err gf_isom_modify_alternate_brand(GF_ISOFile *isom_file, u32 Brand, Bool Add */ GF_Err gf_isom_reset_alt_brands(GF_ISOFile *isom_file); +/*! removes all alternate brands except major brand +\param isom_file the target ISO file +\param leave_empty if GF_TRUE, does not create a default alternate brand matching the major brand +\return error if any +*/ +GF_Err gf_isom_reset_alt_brands_ex(GF_ISOFile *isom_file, Bool leave_empty); + /*! set sample dependency flags - see ISO/IEC 14496-12 and \ref gf_filter_pck_set_dependency_flags \param isom_file the target ISO file \param trackNumber the target track number @@ -2165,21 +2441,21 @@ GF_Err gf_isom_set_track_matrix(GF_ISOFile *isom_file, u32 trackNumber, s32 matr */ GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, s32 hSpacing, s32 vSpacing, Bool force_par); -/*! sets clean apperture (crop window, see ISO/IEC 14496-12) for a sample description +/*! sets clean aperture (crop window, see ISO/IEC 14496-12) for a sample description \param isom_file the target ISO file \param trackNumber the target track number \param sampleDescriptionIndex the target sample description index -\param cleanApertureWidthN nominator of clean apperture horizontal size -\param cleanApertureWidthD denominator of clean apperture horizontal size -\param cleanApertureHeightN nominator of clean apperture vertical size -\param cleanApertureHeightD denominator of clean apperture vertical size -\param horizOffN nominator of horizontal offset of clean apperture center minus (width-1)/2 (eg 0 sets center to center of video) -\param horizOffD denominator of horizontal offset of clean apperture center minus (width-1)/2 (eg 0 sets center to center of video) -\param vertOffN nominator of vertical offset of clean apperture center minus (height-1)/2 (eg 0 sets center to center of video) -\param vertOffD denominator of vertical offset of clean apperture center minus (height-1)/2 (eg 0 sets center to center of video) +\param cleanApertureWidthN nominator of clean aperture horizontal size +\param cleanApertureWidthD denominator of clean aperture horizontal size +\param cleanApertureHeightN nominator of clean aperture vertical size +\param cleanApertureHeightD denominator of clean aperture vertical size +\param horizOffN nominator of horizontal offset of clean aperture center minus (width-1)/2 (eg 0 sets center to center of video) +\param horizOffD denominator of horizontal offset of clean aperture center minus (width-1)/2 (eg 0 sets center to center of video) +\param vertOffN nominator of vertical offset of clean aperture center minus (height-1)/2 (eg 0 sets center to center of video) +\param vertOffD denominator of vertical offset of clean aperture center minus (height-1)/2 (eg 0 sets center to center of video) \return error if any */ -GF_Err gf_isom_set_clean_aperture(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 cleanApertureWidthN, u32 cleanApertureWidthD, u32 cleanApertureHeightN, u32 cleanApertureHeightD, u32 horizOffN, u32 horizOffD, u32 vertOffN, u32 vertOffD); +GF_Err gf_isom_set_clean_aperture(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 cleanApertureWidthN, u32 cleanApertureWidthD, u32 cleanApertureHeightN, u32 cleanApertureHeightD, s32 horizOffN, u32 horizOffD, s32 vertOffN, u32 vertOffD); /*! updates track aperture information for QT/ProRes \param isom_file the target ISO file @@ -2189,37 +2465,13 @@ GF_Err gf_isom_set_clean_aperture(GF_ISOFile *isom_file, u32 trackNumber, u32 sa */ GF_Err gf_isom_update_aperture_info(GF_ISOFile *isom_file, u32 trackNumber, Bool remove); -/*! content light level info*/ -typedef struct { - /*! max content ligth level*/ - u16 max_content_light_level; - /*! max picture average ligth level*/ - u16 max_pic_average_light_level; -} GF_ContentLightLevelInfo; - -/*! mastering display colour volume info*/ -typedef struct { - /*! display primaries*/ - struct { - u16 x; - u16 y; - } display_primaries[3]; - /*! X white point*/ - u16 white_point_x; - /*! Y white point*/ - u16 white_point_y; - u32 max_display_mastering_luminance; - /*! min display mastering luminance*/ - u32 min_display_mastering_luminance; -} GF_MasteringDisplayColourVolumeInfo; - /*! sets high dynamic range information for a sample description \param isom_file the target ISO file \param trackNumber the target track number \param sampleDescriptionIndex the target sample description index -\param mdcv the mastering display colour volume to set -\param clli the content light level to set +\param mdcv the mastering display colour volume to set, if NULL removes the info +\param clli the content light level to set, if NULL removes the info \return error if any */ GF_Err gf_isom_set_high_dynamic_range_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_MasteringDisplayColourVolumeInfo *mdcv, GF_ContentLightLevelInfo *clli); @@ -2228,10 +2480,10 @@ GF_Err gf_isom_set_high_dynamic_range_info(GF_ISOFile *isom_file, u32 trackNumbe \param isom_file the target ISO file \param trackNumber the target track number \param sampleDescriptionIndex the target sample description index -\param dv_profile the Dolby Vision profile +\param dvcc the Dolby Vision configuration \return error if any */ -GF_Err gf_isom_set_dolby_vision_profile(GF_ISOFile* isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 dv_profile); +GF_Err gf_isom_set_dolby_vision_profile(GF_ISOFile* isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_DOVIDecoderConfigurationRecord *dvcc); /*! sets image sequence coding constraints (mostly used for HEIF image files) @@ -2414,7 +2666,9 @@ typedef enum /*! set this flag to keep data reference entries while cloning track*/ GF_ISOM_CLONE_TRACK_KEEP_DREF = 1, /*! set this flag to avoid cloning track as a QT track while cloning track*/ - GF_ISOM_CLONE_TRACK_NO_QT = 1<<1 + GF_ISOM_CLONE_TRACK_NO_QT = 1<<1, + /*! drop track ID while importing*/ + GF_ISOM_CLONE_TRACK_DROP_ID = 1<<2 } GF_ISOTrackCloneFlags; /*! clones a track. This clones everything except media data and sample info (DTS, CTS, RAPs, etc...), and also clones sample descriptions @@ -2459,6 +2713,14 @@ GF_Err gf_isom_set_track_priority_in_group(GF_ISOFile *isom_file, u32 trackNumbe */ GF_Err gf_isom_hint_max_chunk_size(GF_ISOFile *isom_file, u32 trackNumber, u32 maxChunkSize); +/*! sets the maximum chunk duration for a track +\param isom_file the target ISO file +\param trackNumber the target track +\param maxChunkDur the maximum chunk duration in media timescale +\return error if any +*/ +GF_Err gf_isom_hint_max_chunk_duration(GF_ISOFile *isom_file, u32 trackNumber, u32 maxChunkDur); + /*! sets up interleaving for storage (shortcut for storeage mode + interleave_time) \param isom_file the target ISO file \param TimeInSec the desired interleaving time in seconds @@ -2466,6 +2728,13 @@ GF_Err gf_isom_hint_max_chunk_size(GF_ISOFile *isom_file, u32 trackNumber, u32 m */ GF_Err gf_isom_make_interleave(GF_ISOFile *isom_file, Double TimeInSec); +/*! sets up interleaving for storage (shortcut for storeage mode + interleave_time) +\param isom_file the target ISO file +\param fTimeInSec the desired interleaving time in seconds, as a fraction +\return error if any +*/ +GF_Err gf_isom_make_interleave_ex(GF_ISOFile *isom_file, GF_Fraction *fTimeInSec); + /*! sets progress callback when writing a file \param isom_file the target ISO file \param progress_cbk the progress callback function @@ -2487,6 +2756,35 @@ GF_Err gf_isom_set_write_callback(GF_ISOFile *isom_file, void *usr_data, u32 block_size); +/*! checks if file will use in-place rewriting or not +\param isom_file the target ISO file +\return GF_TRUE if in-place rewrite is used, GF_FALSE otherwise +*/ +Bool gf_isom_is_inplace_rewrite(GF_ISOFile *isom_file); + +/*! Disables inplace rewrite. Once in-place rewrite is disabled, the file can no longer be rewrittten in place. + + In-place rewriting allows editing the file structure (ftyp, moov and meta boxes) without modifying the media data size. + + In-place rewriting is disabled for any of the following: + - specifying a storage mode using \ref gf_isom_set_storage_mode + - removing or adding tracks or items + - removing, adding or updating samples + - using stdout, redirect file "_gpac_isobmff_redirect", memory file " gmem://" + +In-place rewriting is enabled by default on files open in edit mode. + +\param isom_file the target ISO file +*/ +void gf_isom_disable_inplace_rewrite(GF_ISOFile *isom_file); + +/*! sets amount of bytes to reserve after moov for future in-place editing. This may be ignored depending on the final write mode +\param isom_file the target ISO file +\param padding amount of bytes to reserve +\return error if any +*/ +GF_Err gf_isom_set_inplace_padding(GF_ISOFile *isom_file, u32 padding); + /*! @} */ #endif // GPAC_DISABLE_ISOM_WRITE @@ -2587,7 +2885,7 @@ the specific codec (equivalent to 0xFF value in MPEG profiles) \param ProfileLevel the profile and level value to set \return error if any */ -GF_Err gf_isom_set_pl_indication(GF_ISOFile *isom_file, u8 PL_Code, GF_ISOProfileLevelType ProfileLevel); +GF_Err gf_isom_set_pl_indication(GF_ISOFile *isom_file, GF_ISOProfileLevelType PL_Code, u8 ProfileLevel); #ifndef GPAC_DISABLE_ISOM_WRITE /*! sets the rootOD ID of the movie if you need it. By default, movies are created without root ODs @@ -2599,7 +2897,7 @@ GF_Err gf_isom_set_pl_indication(GF_ISOFile *isom_file, u8 PL_Code, GF_ISOProfil GF_Err gf_isom_set_root_od_id(GF_ISOFile *isom_file, u32 OD_ID); /*! sets the rootOD URL of the movie if you need it (only needed to create an empty file pointing -to external ressource) +to external resource) \note Use for MPEG-4 Systems only \param isom_file the target ISO file \param url_string the URL to assign to the root OD/IOD @@ -2758,6 +3056,8 @@ typedef struct u8 *extension_buf; /*optional, sample description specific size*/ u32 extension_buf_size; + /*optional, wraps sample description specific data into a box if given type*/ + u32 ext_box_wrap; } GF_GenericSampleDescription; /*! gets an unknown sample description @@ -3016,6 +3316,35 @@ GF_HEVCConfig *gf_isom_hevc_config_get(GF_ISOFile *isom_file, u32 trackNumber, u */ GF_HEVCConfig *gf_isom_lhvc_config_get(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); +/*! VVC family type*/ +typedef enum +{ + /*! not an VVC codec*/ + GF_ISOM_VVCTYPE_NONE=0, + /*! VVC only*/ + GF_ISOM_VVCTYPE_ONLY, + /*! VVC subpicture track*/ + GF_ISOM_VVCTYPE_SUBPIC, + /*! VVC non-VCL only*/ + GF_ISOM_VVCTYPE_NVCL, +} GF_ISOMVVCType; + +/*! gets the VVC family type for a sample description +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\return the type of VVC media +*/ +GF_ISOMVVCType gf_isom_get_vvc_type(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); + +/*! gets VVC config for a sample description +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\return the VVC config - user is responsible for deleting it +*/ +GF_VVCConfig *gf_isom_vvc_config_get(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); + /*! gets AV1 config for a sample description \param isom_file the target ISO file \param trackNumber the target track @@ -3126,7 +3455,7 @@ GF_Err gf_isom_svc_config_new(GF_ISOFile *isom_file, u32 trackNumber, GF_AVCConf */ GF_Err gf_isom_svc_config_update(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_AVCConfig *cfg, Bool is_additional); /*! deletes an SVC sample description -\warning associated samples if any are NOT deleted +\warning Associated samples if any are NOT deleted \param isom_file the target ISO file \param trackNumber the target track \param sampleDescriptionIndex the target sample description index to delete @@ -3156,7 +3485,7 @@ GF_Err gf_isom_mvc_config_new(GF_ISOFile *isom_file, u32 trackNumber, GF_AVCConf GF_Err gf_isom_mvc_config_update(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_AVCConfig *cfg, Bool is_additional); /*! deletes an MVC sample description -\warning associated samples if any are NOT deleted +\warning Associated samples if any are NOT deleted \param isom_file the target ISO file \param trackNumber the target track \param sampleDescriptionIndex the target sample description index to delete @@ -3243,7 +3572,7 @@ typedef enum { GF_Err gf_isom_lhvc_config_update(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_HEVCConfig *cfg, GF_ISOMLHEVCTrackType track_type); /*! sets nalu size length -\warning any previously added samples must be rewritten by the caller +\warning Any previously added samples must be rewritten by the caller \param isom_file the target ISO file \param trackNumber the target track \param sampleDescriptionIndex the target sample description index to update @@ -3252,6 +3581,36 @@ GF_Err gf_isom_lhvc_config_update(GF_ISOFile *isom_file, u32 trackNumber, u32 sa */ GF_Err gf_isom_set_nalu_length_field(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 nalu_size_length); + +/*! creates a new VVC sample description +\param isom_file the target ISO file +\param trackNumber the target track +\param cfg the VVC config for this sample description +\param URLname URL value of the data reference, NULL if no data reference (media in the file) +\param URNname URN value of the data reference, NULL if no data reference (media in the file) +\param outDescriptionIndex set to the index of the created sample description +\return error if any +*/ +GF_Err gf_isom_vvc_config_new(GF_ISOFile *isom_file, u32 trackNumber, GF_VVCConfig *cfg, const char *URLname, const char *URNname, u32 *outDescriptionIndex); + +/*! sets vvi1 entry type (inband SPS/PPS) instead of vvc1 (SPS/PPS in hvcC box) +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param keep_xps if set to GF_TRUE, keeps parameter set in the configuration record otherwise removes them +\return error if any +*/ +GF_Err gf_isom_vvc_set_inband_config(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, Bool keep_xps); + +/*! updates vvcC configuration +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param cfg new config to set +\return error if any +*/ +GF_Err gf_isom_vvc_config_update(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_VVCConfig *cfg); + /*! creates new VPx config \param isom_file the target ISO file \param trackNumber the target track @@ -3329,42 +3688,6 @@ GF_Err gf_isom_get_dims_description(GF_ISOFile *isom_file, u32 trackNumber, u32 GF_Err gf_isom_new_dims_description(GF_ISOFile *isom_file, u32 trackNumber, GF_DIMSDescription *desc, const char *URLname, const char *URNname, u32 *outDescriptionIndex); #endif /*GPAC_DISABLE_ISOM_WRITE*/ -/*! AC-3 config record extension for EAC-3 - see dolby specs*/ -struct __ec3_stream -{ - /*! AC3 fs code*/ - u8 fscod; - /*! AC3 bsid code*/ - u8 bsid; - /*! AC3 bs mode*/ - u8 bsmod; - /*! AC3 ac mode*/ - u8 acmod; - /*! LF on*/ - u8 lfon; - /*! asvc mode, only for EC3*/ - u8 asvc; - /*! deps, only for EC3*/ - u8 nb_dep_sub; - /*! channel loc, only for EC3*/ - u8 chan_loc; -}; - -/*! AC3 config record*/ -typedef struct -{ - /*! indicates if ec3*/ - u8 is_ec3; - /*! number of streams : - 1 for AC3 - max 8 for EC3, main stream is included - */ - u8 nb_streams; - /*! if AC3 this is the bitrate code, otherwise cumulated data rate of EC3 streams*/ - u16 brcode; - struct __ec3_stream streams[8]; -} GF_AC3Config; - /*! gets an AC3 sample description \param isom_file the target ISO file \param trackNumber the target track @@ -3373,15 +3696,6 @@ typedef struct */ GF_AC3Config *gf_isom_ac3_config_get(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); -/*! parses an AC3/EC3 sample description -\param dsi the encoded config -\param dsi_len the encoded config size -\param is_ec3 indicates that the encoded config is for an EC3 track -\param cfg the AC3/EC3 confgi to fill -\return Error if any -*/ -GF_Err gf_isom_ac3_config_parse(u8 *dsi, u32 dsi_len, Bool is_ec3, GF_AC3Config *cfg); - #ifndef GPAC_DISABLE_ISOM_WRITE /*! creates an AC3 sample description \param isom_file the target ISO file @@ -3395,6 +3709,30 @@ GF_Err gf_isom_ac3_config_parse(u8 *dsi, u32 dsi_len, Bool is_ec3, GF_AC3Config GF_Err gf_isom_ac3_config_new(GF_ISOFile *isom_file, u32 trackNumber, GF_AC3Config *cfg, const char *URLname, const char *URNname, u32 *outDescriptionIndex); #endif /*GPAC_DISABLE_ISOM_WRITE*/ +/*! gets TrueHD sample description info +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param format_info set to the format info - may be NULL +\param peak_data_rate set to the peak data rate info - may be NULL +\return error if any +*/ +GF_Err gf_isom_truehd_config_get(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *format_info, u32 *peak_data_rate); + +#ifndef GPAC_DISABLE_ISOM_WRITE +/*! creates a FLAC sample description +\param isom_file the target ISO file +\param trackNumber the target track +\param URLname URL value of the data reference, NULL if no data reference (media in the file) +\param URNname URN value of the data reference, NULL if no data reference (media in the file) +\param format_info TrueHD format info +\param peak_data_rate TrueHD peak data rate +\param outDescriptionIndex set to the index of the created sample description +\return error if any +*/ +GF_Err gf_isom_truehd_config_new(GF_ISOFile *isom_file, u32 trackNumber, char *URLname, char *URNname, u32 format_info, u32 peak_data_rate, u32 *outDescriptionIndex); +#endif + /*! gets a FLAC sample description \param isom_file the target ISO file \param trackNumber the target track @@ -3484,6 +3822,91 @@ GF_Err gf_isom_get_tmcd_config(GF_ISOFile *isom_file, u32 trackNumber, u32 sampl */ GF_Err gf_isom_get_pcm_config(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *flags, u32 *pcm_size); + + +#ifndef GPAC_DISABLE_ISOM_WRITE + +/*! creates a MPHA sample description +\param isom_file the target ISO file +\param trackNumber the target track +\param URLname URL value of the data reference, NULL if no data reference (media in the file) +\param URNname URN value of the data reference, NULL if no data reference (media in the file) +\param outDescriptionIndex set to the index of the created sample description +\param dsi the MPEGH audio config (payload of mhaC box): byte[0]=1 (config version) ,byte[1]=ProfileLevel, byte[2]=channel layout, byte[3],byte[4]: the size of what follows the rest being a mpegh3daConfig +\param dsi_size the size of the MPEGH audio config +\return error if any +*/ +GF_Err gf_isom_new_mpha_description(GF_ISOFile *isom_file, u32 trackNumber, const char *URLname, const char *URNname, u32 *outDescriptionIndex, u8 *dsi, u32 dsi_size); +#endif + +/*! gets compatible profile list for mpegh entry +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param nb_compatible_profiles set to the number of compatible profiles returned +\return array of compatible profiles, NULL if none found +*/ +const u8 *gf_isom_get_mpegh_compatible_profiles(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *nb_compatible_profiles); + + + +/*! structure holding youtube 360 video info +- cf https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md#stereoscopic-3d-video-box-st3d + */ +typedef struct +{ + /*! stereo type holding youtube 360 video info*/ + u32 stereo_type; + /*! 0: unknown (not present), 1: cube map, 2: EQR, 3: mesh*/ + u32 projection_type; + /*! metadata about 3D software creator*/ + const char *meta_data; + /*! indicate default pause is present*/ + Bool pose_present; + /*! default pause yaw as 16.16 fixed point*/ + u32 yaw; + /*! default pause pitch as 16.16 fixed point*/ + u32 pitch; + /*! default pause roll as 16.16 fixed point*/ + u32 roll; + + /*! cube map layout*/ + u32 layout; + /*! cube map padding*/ + u32 padding; + + /*! EQR top crop pos in frame, in pixels*/ + u32 top; + /*! EQR bottom crop pos in frame, in pixels*/ + u32 bottom; + /*! EQR left crop pos in frame, in pixels*/ + u32 left; + /*! EQR right crop pos in frame, in pixels*/ + u32 right; + +} GF_ISOM_Y3D_Info; + + +/*! gets youtube 3D/360 info +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param info filled with 3D info +\return error if any, GF_NOT_FOUND if no 3D/360 or setero info +*/ +GF_Err gf_isom_get_y3d_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info); + +#ifndef GPAC_DISABLE_ISOM_WRITE +/*! sets youtube 3D/360 info +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param info 3D info to set +\return error if any +*/ +GF_Err gf_isom_set_y3d_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info); +#endif + /*! @} */ @@ -3535,6 +3958,15 @@ u32 gf_isom_segment_get_track_fragment_count(GF_ISOFile *isom_file, u32 moof_ind */ u32 gf_isom_segment_get_track_fragment_decode_time(GF_ISOFile *isom_file, u32 moof_index, u32 traf_index, u64 *decode_time); +/*! get the movie fragment size, i.e. the size of moof, mdat and related boxes before moof/mdat + +\param isom_file the target ISO file +\param moof_index the target movie fragment (1-based index) +\param moof_size set to moof box size, may be NULL +\return the movie fragemnt size +*/ +u64 gf_isom_segment_get_fragment_size(GF_ISOFile *isom_file, u32 moof_index, u32 *moof_size); + /*! enables single moof mode. In single moof mode, file is parsed only one moof/mdat at a time in order to proceed to next moof, \ref gf_isom_reset_data_offset must be called to parse the next moof \param isom_file the target ISO file @@ -3584,6 +4016,13 @@ GF_Err gf_isom_refresh_fragmented(GF_ISOFile *isom_file, u64 *MissingBytes, cons */ u64 gf_isom_get_current_tfdt(GF_ISOFile *isom_file, u32 trackNumber); +/*! gets the estimated DTS of the first sample of the next segment for SmoothStreaming files (no tfdt, no tfxd) +\param isom_file the target ISO file +\param trackNumber the target track +\return the next track fragment decode time in media timescale +*/ +u64 gf_isom_get_smooth_next_tfdt(GF_ISOFile *isom_file, u32 trackNumber); + /*! checks if the movie is a smooth streaming recomputed initial movie \param isom_file the target ISO file \return GF_TRUE if the file init segment (moov) was generated from external meta-data (smooth streaming) @@ -3634,8 +4073,8 @@ typedef struct /*! mdat end offset*/ u64 mdat_end; /*segment start offset plus one: - 0 if regular fragment, 1 if dash sedment, offset indicates start of segment (styp or sidx) - if sidx, it is writtent in the moof_template + 0 if regular fragment, 1 if dash segment, offset indicates start of segment (styp or sidx) + if sidx, it is written in the moof_template */ u64 seg_start_plus_one; @@ -3677,7 +4116,7 @@ GF_Err gf_isom_reset_data_offset(GF_ISOFile *isom_file, u64 *top_box_start); /*! releases current movie segment. This closes the associated file IO object. \note seeking in the file is no longer possible when tables are rested -\warning the sample count is not reseted after the release of tables. use \ref gf_isom_reset_tables for this +\warning The sample count is not reseted after the release of tables. use \ref gf_isom_reset_tables for this \param isom_file the target ISO file \param reset_tables if set, sample information for all tracks setup as segment are destroyed, along with all PSSH boxes. This allows keeping the memory footprint low when playing segments. @@ -3768,7 +4207,7 @@ u32 gf_isom_get_next_moof_number(GF_ISOFile *isom_file); User Data Manipulation You can add specific typed data to either a track or the movie: the UserData - The type must be formated as a FourCC if you have a registered 4CC type + The type must be formatted as a FourCC if you have a registered 4CC type but the usual is to set a UUID (128 bit ID for box type) which never conflict with existing structures in the format To manipulate a UUID user data set the UserDataType to 0 and specify a valid UUID. @@ -3927,7 +4366,7 @@ GF_Err gf_isom_setup_track_fragment(GF_ISOFile *isom_file, GF_ISOTrackID TrackID Bool force_traf_flags); /*! changes the default parameters of an existing trak fragment -\warning should not be used if samples have already been added +\warning This should not be used if samples have already been added \param isom_file the target ISO file \param TrackID ID of the target track @@ -3960,9 +4399,10 @@ GF_Err gf_isom_finalize_for_fragment(GF_ISOFile *isom_file, u32 media_segment_ty /*! sets the duration of the movie in case of movie fragments \param isom_file the target ISO file \param duration the complete duration (movie and all fragments) in movie timescale +\param remove_mehd force removal of mehd box, only setting mvhd.duration to 0 \return error if any */ -GF_Err gf_isom_set_movie_duration(GF_ISOFile *isom_file, u64 duration); +GF_Err gf_isom_set_movie_duration(GF_ISOFile *isom_file, u64 duration, Bool remove_mehd); /*! fragment creatio option*/ typedef enum @@ -4125,6 +4565,14 @@ typedef enum This will enable data cache param: interleave ID*/ GF_ISOM_TRUN_SET_INTERLEAVE_ID, + /*! store truns before sample encryption and sample groups info + param: 1 to store before and follow CMAF (recommended?) order, 0, to store after*/ + GF_ISOM_TRAF_TRUNS_FIRST, + /*! forces trun v1 + param: on/off (0/1)*/ + GF_ISOM_TRAF_TRUN_V1, + /*force usage of 64 bits in tfdt and in per-segment sidx*/ + GF_ISOM_TRAF_USE_LARGE_TFDT } GF_ISOTrackFragmentOption; /*! sets a track fragment option. Options can be set at the beginning of each new fragment only, and for the @@ -4155,7 +4603,7 @@ GF_Err gf_isom_fragment_add_sample(GF_ISOFile *isom_file, GF_ISOTrackID TrackID, u32 Duration, u8 PaddingBits, u16 DegradationPriority, Bool redundantCoding); /*! appends data into last sample of track for video fragments/other media -\warning this shall not be used with OD tracks +\warning This shall not be used with OD tracks \param isom_file the target ISO file \param TrackID destination track \param data the data to append @@ -4169,14 +4617,14 @@ GF_Err gf_isom_fragment_append_data(GF_ISOFile *isom_file, GF_ISOTrackID TrackID /*! sets side information for common encryption for the last added sample \param isom_file the target ISO file \param trackID the ID of the target track -\param IV_size the size of the init vector (8 or 16 bytes) \param sai_b buffer containing the SAI information of the sample -\param sai_b_size size of the SAI buffer. If sai_b is NULL, this indicates the original sample size, and an SAI will be created describing the proper byte ranges if use_subsample is set +\param sai_b_size size of the SAI buffer. If sai_b is NULL or sai_b_size is 0, add a clear SAI data \param use_subsample indicates if the media uses CENC subsamples \param use_saio_32bit indicates if 32-bit saio shall be used +\param use_multikey indicates if multikey is in use (required to tag saiz/saio boxes) \return error if any */ -GF_Err gf_isom_fragment_set_cenc_sai(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u32 IV_size, u8 *sai_b, u32 sai_b_size, Bool use_subsample, Bool use_saio_32bit); +GF_Err gf_isom_fragment_set_cenc_sai(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u8 *sai_b, u32 sai_b_size, Bool use_subsample, Bool use_saio_32bit, Bool use_multikey); /*! clones PSSH data between two files \param dst_file the target ISO file \param src_file the source ISO file @@ -4218,6 +4666,21 @@ GF_Err gf_isom_fragment_set_sample_rap_group(GF_ISOFile *isom_file, GF_ISOTrackI GF_Err gf_isom_fragment_set_sample_flags(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u32 is_leading, u32 dependsOn, u32 dependedOn, u32 redundant); + +/*! adds sample auxiliary data + +\param isom_file the target ISO file +\param trackID the ID of the target track +\param sample_number_in_frag the sample number in the current fragment. Must be equal or larger to last auxiliary added +\param aux_type auxiliary sample data type, shall not be 0 +\param aux_info auxiliary sample data specific info type, may be 0 +\param data data to add +\param size size of data to add +\return error if any +*/ +GF_Err gf_isom_fragment_set_sample_aux_info(GF_ISOFile *isom_file, u32 trackID, u32 sample_number_in_frag, u32 aux_type, u32 aux_info, u8 *data, u32 size); + + /*! sets the number of the next moof to be produced \param isom_file the target ISO file \param value the number of the next moof @@ -4298,19 +4761,19 @@ GF_Err gf_isom_end_hint_sample(GF_ISOFile *isom_file, u32 trackNumber, u8 IsRand /*! adds a blank chunk of data in the sample that is skipped while streaming \param isom_file the target ISO file \param trackNumber the target hint track -\param AtBegin indicates if the blank chunk should be at the end or at the begining of the hint packet +\param AtBegin indicates if the blank chunk should be at the end or at the beginning of the hint packet \return error if any */ GF_Err gf_isom_hint_blank_data(GF_ISOFile *isom_file, u32 trackNumber, u8 AtBegin); /*! adds a chunk of data in the packet that is directly copied while streaming -NOTE: dataLength MUST BE <= 14 bytes, and you should only use this function +\note DataLength MUST BE <= 14 bytes, and you should only use this function to add small blocks of data (encrypted parts, specific headers, ...) \param isom_file the target ISO file \param trackNumber the target hint track \param data buffer to add to the RTP packet \param dataLength size of buffer to add to the RTP packet -\param AtBegin indicates if the blank chunk should be at the end or at the begining of the hint packet +\param AtBegin indicates if the blank chunk should be at the end or at the beginning of the hint packet \return error if any */ GF_Err gf_isom_hint_direct_data(GF_ISOFile *isom_file, u32 trackNumber, u8 *data, u32 dataLength, u8 AtBegin); @@ -4328,7 +4791,7 @@ GF_Err gf_isom_hint_direct_data(GF_ISOFile *isom_file, u32 trackNumber, u8 *data (useful to store en encrypted version of a packet only available while streaming) In this case, set SourceTrackID to the HintTrack ID and SampleNumber to 0 In this case, the DataOffset MUST BE NULL and length will indicate the extra_data size -\param AtBegin indicates if the blank chunk should be at the end or at the begining of the hint packet +\param AtBegin indicates if the blank chunk should be at the end or at the beginning of the hint packet \return error if any */ GF_Err gf_isom_hint_sample_data(GF_ISOFile *isom_file, u32 trackNumber, GF_ISOTrackID SourceTrackID, u32 SampleNumber, u16 DataLength, u32 offsetInSample, u8 *extra_data, u8 AtBegin); @@ -4342,7 +4805,7 @@ GF_Err gf_isom_hint_sample_data(GF_ISOFile *isom_file, u32 trackNumber, GF_ISOTr \param sampleDescriptionIndex the index of the stream description in the desired track \param DataLength the length of bytes to copy in the packet \param offsetInDescription the offset in bytes in the description at which to begin copying data. Since it is far from being obvious / interoperable what this offset is, we recommend not using this function and injecting the data instead using \ref gf_isom_hint_direct_data. -\param AtBegin indicates if the blank chunk should be at the end or at the begining of the hint packet +\param AtBegin indicates if the blank chunk should be at the end or at the beginning of the hint packet \return error if any */ GF_Err gf_isom_hint_sample_description_data(GF_ISOFile *isom_file, u32 trackNumber, GF_ISOTrackID SourceTrackID, u32 sampleDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin); @@ -4435,7 +4898,7 @@ GF_Err gf_isom_sdp_add_track_line(GF_ISOFile *isom_file, u32 trackNumber, const GF_Err gf_isom_sdp_clean_track(GF_ISOFile *isom_file, u32 trackNumber); /*! adds an SDP line to the SDP container at the movie level (presentation SDP info) -NOTE: the CRLF end of line for SDP is automatically inserted +\note The CRLF end of line for SDP is automatically inserted \param isom_file the target ISO file \param text the SDP text to add the target hint track \return error if any @@ -4465,16 +4928,16 @@ GF_Err gf_isom_dump_hint_sample(GF_ISOFile *isom_file, u32 trackNumber, u32 Samp /*! gets SDP info at the movie level \param isom_file the target ISO file -\param sdp set to the sdp text - do not modify -\param length set to the sdp length +\param sdp set to the sdp text, including a null-terminating character - do not modify +\param length set to the sdp length, not including the null-terminating character \return error if any */ GF_Err gf_isom_sdp_get(GF_ISOFile *isom_file, const char **sdp, u32 *length); /*! gets SDP info at the track level \param isom_file the target ISO file \param trackNumber the target track -\param sdp set to the sdp text - do not modify -\param length set to the sdp length +\param sdp set to the sdp text, including a null-terminating character - do not modify +\param length set to the sdp length, not including the null-terminating character \return error if any */ GF_Err gf_isom_sdp_track_get(GF_ISOFile *isom_file, u32 trackNumber, const char **sdp, u32 *length); @@ -4547,7 +5010,7 @@ GF_Err gf_isom_text_dump(GF_ISOFile *isom_file, u32 trackNumber, FILE *dump, GF_ \param isom_file the target ISO file \param trackNumber the target track \param sampleDescriptionIndex the sample description index -\param sidx_offset if 0, the sidx will NOT be written before the encoded TX3G. If not 0, the sidx will be written before the encoded TX3G, with the given offset. Offset sshould be at least 128 for most commmon usage of TX3G (RTP, MPEG-4 timed text, etc) +\param sidx_offset if 0, the sidx will NOT be written before the encoded TX3G. If not 0, the sidx will be written before the encoded TX3G, with the given offset. Offset sshould be at least 128 for most common usage of TX3G (RTP, MPEG-4 timed text, etc) \param tx3g set to a newly allocated buffer containing the encoded tx3g - to be freed by caller \param tx3g_size set to the size of the encoded config \return error if any @@ -4651,6 +5114,26 @@ GF_Err gf_isom_new_xml_subtitle_description(GF_ISOFile *isom_file, u32 trackNumb #endif // GPAC_DISABLE_ISOM_WRITE +/*! gets MIME parameters (type/subtype + codecs and profiles) associated with a sample descritpion +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\return MIME param if present, NULL otherwise +*/ +const char *gf_isom_subtitle_get_mime(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); + +#ifndef GPAC_DISABLE_ISOM_WRITE +/*! gets MIME parameters associated with a sample descritpion +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the target sample description index +\param full_mime MIME param (type/subtype + codecs and profiles) to set, if NULL removes MIME parameter info +\return error if any +*/ +GF_Err gf_isom_subtitle_set_mime(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, const char *full_mime); +#endif + + /*! gets XML metadata for a sample description \param isom_file the target ISO file \param trackNumber the target track @@ -4855,6 +5338,7 @@ GF_ISOSample *gf_isom_xml_subtitle_to_sample(GF_GenericSubtitleSample *subt_samp */ GF_Err gf_isom_xml_subtitle_sample_add_text(GF_GenericSubtitleSample *subt_samp, char *text_data, u32 text_len); + #endif /*GPAC_DISABLE_ISOM_WRITE*/ /*! @} */ @@ -4892,6 +5376,8 @@ enum GF_ISOM_CBCS_SCHEME = GF_4CC('c','b','c','s'), /*! PIFF Scheme Type in the SchemeTypeInfoBox */ GF_ISOM_PIFF_SCHEME = GF_4CC('p','i','f','f'), + /*! CENC sensitive encryption */ + GF_ISOM_SVE1_SCHEME = GF_4CC('s','v','e','1'), }; /*! checks if a track is encrypted or protected @@ -5029,28 +5515,6 @@ GF_Err gf_isom_get_ismacryp_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sam */ GF_Err gf_isom_get_original_format_type(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat); -/*! CENC subsample entry*/ -typedef struct -{ - /*! size of bytes in clear - 16 bit stored but we use 32*/ - u32 bytes_clear_data; - /*! size of bytes encrypted*/ - u32 bytes_encrypted_data; -} GF_CENCSubSampleEntry; - -/*! CENC auxiliary info*/ -typedef struct __cenc_sample_aux_info -{ - /*! IV size: 0, 8 or 16; it MUST NOT be written to file*/ - u8 IV_size; - /*! IV can be 0, 64 or 128 bits - if 64, bytes 0-7 are used and 8-15 are 0-padded*/ - bin128 IV; - /*! number of subsamples*/ - u16 subsample_count; - /*! subsamples*/ - GF_CENCSubSampleEntry *subsamples; -} GF_CENCSampleAuxInfo; - #ifndef GPAC_DISABLE_ISOM_WRITE /*! creates ISMACryp protection info for a sample description @@ -5112,30 +5576,36 @@ GF_Err gf_isom_set_oma_protection(GF_ISOFile *isom_file, u32 trackNumber, u32 sa */ GF_Err gf_isom_set_generic_protection(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 scheme_type, u32 scheme_version, char *scheme_uri, char *kms_URI); -/*! allocates storage for CENC side data in a senc or UUID box +/*! allocates storage for CENC side data in a senc box +\param isom_file the target ISO file +\param trackNumber the target track +\return error if any +*/ +GF_Err gf_isom_cenc_allocate_storage(GF_ISOFile *isom_file, u32 trackNumber); + +/*! allocates storage for CENC side data in a PIFF senc UUID box \param isom_file the target ISO file \param trackNumber the target track -\param container_type the code of the container (currently 'senc' for CENC or 'PSEC' for smooth) \param AlgorithmID algorith ID, usually 0 \param IV_size the size of the init vector \param KID the default Key ID \return error if any */ -GF_Err gf_isom_cenc_allocate_storage(GF_ISOFile *isom_file, u32 trackNumber, u32 container_type, u32 AlgorithmID, u8 IV_size, bin128 KID); +GF_Err gf_isom_piff_allocate_storage(GF_ISOFile *isom_file, u32 trackNumber, u32 AlgorithmID, u8 IV_size, bin128 KID); + /*! adds cenc SAI for the last sample added to a track \param isom_file the target ISO file \param trackNumber the target track \param container_type the code of the container (currently 'senc' for CENC or 'PSEC' for smooth) -\param IV_size the size of the init vector \param buf the SAI buffer -\param len the size of the SAI buffer. If buf is NULL but len is given, this adds an unencrypted entry. otherwise, buf && len represent the sai cenc info to add +\param len the size of the SAI buffer. If buf is NULL or len is 0, this adds an unencrypted entry (not written to file) \param use_subsamples if GF_TRUE, the media format uses CENC subsamples -\param clear_IV the IV used for clear samples (when buf is null) \param use_saio_32bit forces usage of 32-bit saio boxes +\param is_multi_key indicates if multi key is in use (required to tag saio and saiz boxes) \return error if any */ -GF_Err gf_isom_track_cenc_add_sample_info(GF_ISOFile *isom_file, u32 trackNumber, u32 container_type, u8 IV_size, u8 *buf, u32 len, Bool use_subsamples, u8 *clear_IV, Bool use_saio_32bit); +GF_Err gf_isom_track_cenc_add_sample_info(GF_ISOFile *isom_file, u32 trackNumber, u32 container_type, u8 *buf, u32 len, Bool use_subsamples, Bool use_saio_32bit, Bool is_multi_key); @@ -5146,18 +5616,35 @@ GF_Err gf_isom_track_cenc_add_sample_info(GF_ISOFile *isom_file, u32 trackNumber \param scheme_type 4CC of protection scheme (GF_ISOM_ISMACRYP_SCHEME = iAEC in ISMACryp 1.0) \param scheme_version version of protection scheme (1 in ISMACryp 1.0) \param default_IsEncrypted default isEncrypted flag -\param default_IV_size default IV size flag -\param default_KID default key ID used \param default_crypt_byte_block default crypt block size for pattern encryption \param default_skip_byte_block default skip block size for pattern encryption -\param default_constant_IV_size default constant IV size -\param default_constant_IV default constant IV +\param key_info key descriptor formatted as a multi-key info (cf GF_PROP_PID_CENC_KEY) +\param key_info_size key descriptor size \return error if any */ GF_Err gf_isom_set_cenc_protection(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 scheme_type, - u32 scheme_version, u32 default_IsEncrypted, u8 default_IV_size, bin128 default_KID, - u8 default_crypt_byte_block, u8 default_skip_byte_block, - u8 default_constant_IV_size, bin128 default_constant_IV); + u32 scheme_version, u32 default_IsEncrypted, u8 default_crypt_byte_block, u8 default_skip_byte_block, + u8 *key_info, u32 key_info_size); + + +/*! creates CENC protection for a multi-key sample description +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleDescriptionIndex the sample description index +\param scheme_type 4CC of protection scheme (GF_ISOM_ISMACRYP_SCHEME = iAEC in ISMACryp 1.0) +\param scheme_version version of protection scheme (1 in ISMACryp 1.0) +\param default_IsEncrypted default isEncrypted flag +\param default_crypt_byte_block default crypt block size for pattern encryption +\param default_skip_byte_block default skip block size for pattern encryption +\param key_info key info (cf CENC and GF_PROP_PID_CENC_KEY) +\param key_info_size key info size +\return error if any +*/ +GF_Err gf_isom_set_cenc_protection_mkey(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 scheme_type, + u32 scheme_version, u32 default_IsEncrypted, u8 default_crypt_byte_block, u8 default_skip_byte_block, + u8 *key_info, u32 key_info_size); + + /*! adds PSSH info for a file, can be called several time per system ID \param isom_file the target ISO file \param systemID the ID of the protection system @@ -5166,10 +5653,10 @@ GF_Err gf_isom_set_cenc_protection(GF_ISOFile *isom_file, u32 trackNumber, u32 s \param KID the list of key IDs \param data opaque data for the protection system \param len size of the opaque data -\param use_piff if GF_TRUE, use PIFF pssh UUID box when creating the pssh +\param pssh_mode 0: regular PSSH in moov, 1: PIFF PSSH in moov, 2: regular PSSH in meta \return error if any */ -GF_Err gf_cenc_set_pssh(GF_ISOFile *isom_file, bin128 systemID, u32 version, u32 KID_count, bin128 *KID, u8 *data, u32 len, Bool use_piff); +GF_Err gf_cenc_set_pssh(GF_ISOFile *isom_file, bin128 systemID, u32 version, u32 KID_count, bin128 *KID, u8 *data, u32 len, u32 pssh_mode); /*! removes CENC senc box info \param isom_file the target ISO file @@ -5236,29 +5723,13 @@ Bool gf_isom_is_cenc_media(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDes \param outOriginalFormat set to orginal unprotected media format \param outSchemeType set to 4CC of protection scheme (GF_ISOM_ISMACRYP_SCHEME = iAEC in ISMACryp 1.0) \param outSchemeVersion set to version of protection scheme (1 in ISMACryp 1.0) -\param outIVLength set to the IV size in bytes \return error if any */ -GF_Err gf_isom_get_cenc_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion, u32 *outIVLength); +GF_Err gf_isom_get_cenc_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion); -/*! destroys a CENC sample auxiliary structure -\param samp_aux_info the target auxiliary buffer -*/ -void gf_isom_cenc_samp_aux_info_del(GF_CENCSampleAuxInfo *samp_aux_info); - -/*! gets CENC auxiliary info of a sample -\param isom_file the target ISO file -\param trackNumber the target track -\param sampleNumber the target sample -\param sampleDescIndex the target sample description index -\param sai set to the auxiliary info - shall be freeed by caller -\param container_type set to type of box which contains the sample auxiliary information. Now we have two type: GF_ISOM_BOX_UUID_PSEC and GF_ISOM_BOX_TYPE_SENC -\return error if any -*/ -GF_Err gf_isom_cenc_get_sample_aux_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 sampleDescIndex, GF_CENCSampleAuxInfo **sai, u32 *container_type); /*! gets CENC auxiliary info of a sample as a buffer -\note the serialized buffer format is IV on IV_size bytes, then subsample count if any an [clear_bytes(u16), crypt_bytes(u32)] subsamples +\note the serialized buffer format is exactly a CencSampleAuxiliaryDataFormat \param isom_file the target ISO file \param trackNumber the target track @@ -5269,7 +5740,7 @@ GF_Err gf_isom_cenc_get_sample_aux_info(GF_ISOFile *isom_file, u32 trackNumber, \param outSize set to the size of the serialized buffer. If an existing buffer was passed, the passed value shall be the allocated buffer size (the returned value is still the buffer size) \return error if any */ -GF_Err gf_isom_cenc_get_sample_aux_info_buffer(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 sampleDescIndex, u32 *container_type, u8 **out_buffer, u32 *outSize); +GF_Err gf_isom_cenc_get_sample_aux_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 sampleDescIndex, u32 *container_type, u8 **out_buffer, u32 *outSize); /*! gets CENC default info for a sample description \param isom_file the target ISO file @@ -5277,23 +5748,14 @@ GF_Err gf_isom_cenc_get_sample_aux_info_buffer(GF_ISOFile *isom_file, u32 trackN \param sampleDescriptionIndex the sample description index \param container_type set to the container type of SAI data \param default_IsEncrypted set to default isEncrypted flag -\param default_IV_size set to default IV size flag -\param default_KID set to default key ID used -\param constant_IV_size set to default constant IV size -\param constant_IV set to default constant IV \param crypt_byte_block set to default crypt block size for pattern encryption \param skip_byte_block set to default skip block size for pattern encryption +\param key_info set to multikey descriptor (cf CENC and GF_PROP_PID_CENC_KEY) +\param key_info_size set to multikey descriptor size +\return error if any */ -void gf_isom_cenc_get_default_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *container_type, Bool *default_IsEncrypted, u8 *default_IV_size, bin128 *default_KID, u8 *constant_IV_size, bin128 *constant_IV, u8 *crypt_byte_block, u8 *skip_byte_block); +GF_Err gf_isom_cenc_get_default_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *container_type, Bool *default_IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size); - -/*! checks if CENC protection uses pattern encryption -\param isom_file the target ISO file -\param trackNumber the target track -\param sampleDescriptionIndex the sample description index -\return GF_TRUE if protection uses pattern encryption -*/ -Bool gf_isom_cenc_is_pattern_mode(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleDescriptionIndex); /*! gets the number of PSSH defined \param isom_file the target ISO file \return number of PSSH defined @@ -5336,16 +5798,13 @@ GF_Err gf_isom_dump_ismacryp_sample(GF_ISOFile *isom_file, u32 trackNumber, u32 \param trackNumber the target track \param sampleNumber the target sample number \param IsEncrypted set to GF_TRUE if the sample is encrypted, GF_FALSE otherwise (optional can be NULL) -\param IV_size set to IV size in bytes used for the sample (optional can be NULL) -\param KID set to key ID used for the sample (optional can be NULL) \param crypt_byte_block set to crypt block count for pattern encryption (optional can be NULL) \param skip_byte_block set to skip block count for pattern encryption (optional can be NULL) -\param constant_IV_size set to constant IV size (optional can be NULL) -\param constant_IV set to constant IV (optional can be NULL) +\param key_info set to key descriptor (cf GF_PROP_PID_CENC_KEY) +\param key_info_size set to key descriptor size \return error if any */ -GF_Err gf_isom_get_sample_cenc_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, Bool *IsEncrypted, u8 *IV_size, bin128 *KID, u8 *crypt_byte_block, u8 *skip_byte_block, u8 *constant_IV_size, bin128 *constant_IV); - +GF_Err gf_isom_get_sample_cenc_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size); /*! @} */ @@ -5397,7 +5856,8 @@ u32 gf_isom_get_meta_item_count(GF_ISOFile *isom_file, Bool root_meta, u32 track \param item_num 1-based index of item to query \param itemID set to item ID in file (optional, can be NULL) \param type set to item 4CC type -\param protection_idx set to the 1-based index of the protection in used, 0 if not protected +\param protection_scheme set to 0 if not protected, or scheme type used if item is protected. If protected but scheme type not present, set to 'unkw' +\param protection_scheme_version set to 0 if not protected, or scheme version used if item is protected \param is_self_reference set to item is the file itself \param item_name set to the item name (optional, can be NULL) \param item_mime_type set to the item mime type (optional, can be NULL) @@ -5407,10 +5867,19 @@ u32 gf_isom_get_meta_item_count(GF_ISOFile *isom_file, Bool root_meta, u32 track \return error if any */ GF_Err gf_isom_get_meta_item_info(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_num, - u32 *itemID, u32 *type, u32 *protection_idx, Bool *is_self_reference, + u32 *itemID, u32 *type, u32 *protection_scheme, u32 *protection_scheme_version, Bool *is_self_reference, const char **item_name, const char **item_mime_type, const char **item_encoding, const char **item_url, const char **item_urn); +/*! gets item flags for the givesn item + +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 +\param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_num 1-based index of item to query +\return item flags +*/ +GF_Err gf_isom_get_meta_item_flags(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_num); /*! gets item index from item ID \param isom_file the target ISO file @@ -5445,6 +5914,27 @@ GF_Err gf_isom_extract_meta_item(GF_ISOFile *isom_file, Bool root_meta, u32 trac */ GF_Err gf_isom_extract_meta_item_mem(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_id, u8 **out_data, u32 *out_size, u32 *out_alloc_size, const char **mime_type, Bool use_annex_b); + +/*! fetch CENC info for an item +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 +\param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_id the ID of the item to dump +\param is_protected set to GF_TRUE if item is protected +\param skip_byte_block set to skip_byte_block or 0 if no pattern +\param crypt_byte_block set to crypt_byte_block or 0 if no pattern +\param key_info set to key info +\param key_info_size set to key info size +\param aux_info_type_parameter set to the CENC auxiliary type param of SAI data +\param sai_out_data set to allocated buffer containing the item, shall be freeed by user - may be NULL to only retrieve the info +\param sai_out_size set to the size of the allocated buffer - may be NULL if sai_out_data is NULL +\param sai_out_alloc_size set to the allocated size of the buffer (this allows passing an existing buffer without always reallocating it) - may be NULL if sai_out_data is NULL +\return error if any +*/ +GF_Err gf_isom_extract_meta_item_get_cenc_info(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_id, Bool *is_protected, + u8 *skip_byte_block, u8 *crypt_byte_block, const u8 **key_info, u32 *key_info_size, u32 *aux_info_type_parameter, + u8 **sai_out_data, u32 *sai_out_size, u32 *sai_out_alloc_size); + /*! gets primary item ID \param isom_file the target ISO file \param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 @@ -5452,6 +5942,25 @@ GF_Err gf_isom_extract_meta_item_mem(GF_ISOFile *isom_file, Bool root_meta, u32 \return primary item ID, 0 if none found (primary can also be stored through meta XML)*/ u32 gf_isom_get_meta_primary_item_id(GF_ISOFile *isom_file, Bool root_meta, u32 track_num); +/*! gets number of references of a given type from a given item ID +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 +\param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param from_id item ID to check +\param type reference type to check +\return number of referenced items*/ +u32 gf_isom_meta_get_item_ref_count(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 from_id, u32 type); + +/*! gets ID of reference of a given type and index from a given item ID +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 +\param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param from_id item ID to check +\param type reference type to check +\param ref_idx 1-based index of reference to check +\return ID if the referred item*/ +u32 gf_isom_meta_get_item_ref_id(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 from_id, u32 type, u32 ref_idx); + /*! item tile mode*/ typedef enum { /*! not a tile item*/ @@ -5466,6 +5975,25 @@ typedef enum { TILE_ITEM_SINGLE } GF_TileItemMode; +/*! Image overlay offset properties*/ +typedef struct { + u32 horizontal; + u32 vertical; +} GF_ImageItemOverlayOffset; + +/*! Image protection item properties*/ +typedef struct +{ + u32 scheme_type; + u32 scheme_version; + u8 crypt_byte_block; + u8 skip_byte_block; + const u8 *key_info; + u32 key_info_size; + const u8 *sai_data; + u32 sai_data_size; +} GF_ImageItemProtection; + /*! Image item properties*/ typedef struct { @@ -5483,8 +6011,13 @@ typedef struct u32 vOffset; /*! angle in radians*/ u32 angle; + /*! mirroring axis: 0 = not set, 1 = vertical, 2 = horizontal*/ + u32 mirror; /*! hidden flag*/ Bool hidden; + /*! clean aperture */ + u32 clap_wnum, clap_wden, clap_hnum, clap_hden, clap_hoden, clap_voden; + s32 clap_honum, clap_vonum; /*! pointer to configuration box*/ void *config; /*! tile item mode*/ @@ -5492,15 +6025,56 @@ typedef struct /*! tile number */ u32 single_tile_number; /*! time for importing*/ - double time; + Double time; + /*! end time for importing*/ + Double end_time; + /*! step time between imports*/ + Double step_time; + /*! sample num for importing*/ + u32 sample_num; /*! file containg iCC data for importing*/ char iccPath[GF_MAX_PATH]; /*! is alpha*/ Bool alpha; + /*! is depth*/ + Bool depth; /*! number of channels*/ u8 num_channels; /*! bits per channels in bits*/ - u8 bits_per_channel[3]; + u32 bits_per_channel[3]; + /*! number of columns in grid*/ + u32 num_grid_columns; + /*! number of rows in grid*/ + u32 num_grid_rows; + /*! number of overlayed images*/ + u32 overlay_count; + /*! overlay offsets*/ + GF_ImageItemOverlayOffset *overlay_offsets; + /*! canvas overlay color*/ + u32 overlay_canvas_fill_value_r; + u32 overlay_canvas_fill_value_g; + u32 overlay_canvas_fill_value_b; + u32 overlay_canvas_fill_value_a; + /*! protection info, NULL if item is not protected*/ + GF_ImageItemProtection *cenc_info; + /*! If set, reference image from sample sample_num (same file data used for sample and item)*/ + Bool use_reference; + /*ID of item to use as source*/ + u32 item_ref_id; + /*if set, copy all properties of source item*/ + Bool copy_props; + /*only set when importing non-ref from ISOBMF*/ + GF_ISOFile *src_file; + Bool auto_grid; + Double auto_grid_ratio; + /*AV1 layer sizes except last layer - set during import*/ + u32 av1_layer_size[3]; + /*AV1 operation point index*/ + u8 av1_op_index; + + const char *aux_urn; + const u8 *aux_data; + u32 aux_data_len; } GF_ImageItemProperties; @@ -5583,7 +6157,7 @@ typedef struct \param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 \param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level \param item_name name of the item -\param item_id ID of the item, can be 0 +\param item_id ID of the item, can be NULL, can be 0 in input, set to item ID after call \param item_type four character code of item type \param mime_type mime type of the item, can be NULL \param content_encoding content encoding of the item, can be NULL @@ -5593,7 +6167,56 @@ typedef struct \param item_extent_refs list of item extend description, or NULL \return error if any */ -GF_Err gf_isom_add_meta_item_memory(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, const char *item_name, u32 item_id, u32 item_type, const char *mime_type, const char *content_encoding, GF_ImageItemProperties *image_props, char *data, u32 data_len, GF_List *item_extent_refs); +GF_Err gf_isom_add_meta_item_memory(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, const char *item_name, u32 *item_id, u32 item_type, const char *mime_type, const char *content_encoding, GF_ImageItemProperties *image_props, char *data, u32 data_len, GF_List *item_extent_refs); + +/*! adds an item to a meta box as a reference to a sample +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 +\param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_name name of the item +\param item_id ID of the item, can be 0 +\param item_type four character code of item type +\param mime_type mime type of the item, can be NULL +\param content_encoding content encoding of the item, can be NULL +\param image_props image properties information for image items +\param tk_id source track ID +\param sample_num number of sample to reference +\return error if any +*/ +GF_Err gf_isom_add_meta_item_sample_ref(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, const char *item_name, u32 *item_id, u32 item_type, const char *mime_type, const char *content_encoding, GF_ImageItemProperties *image_props, GF_ISOTrackID tk_id, u32 sample_num); + +/*! creates an image grid item +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if meta_track_number is 0 +\param meta_track_number if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_name name of the item +\param item_id ID of the item, can be 0 +\param image_props image properties information for image items +\return error if any +*/ +GF_Err gf_isom_iff_create_image_grid_item(GF_ISOFile *isom_file, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props); + +/*! creates an image overlay item +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if meta_track_number is 0 +\param meta_track_number if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_name name of the item +\param item_id ID of the item, can be 0 +\param image_props image properties information for image items +\return error if any +*/ +GF_Err gf_isom_iff_create_image_overlay_item(GF_ISOFile *isom_file, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props); + +/*! creates an image identity item +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if meta_track_number is 0 +\param meta_track_number if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_name name of the item +\param item_id ID of the item, can be 0 +\param image_props image properties information for image items +\return error if any +*/ +GF_Err gf_isom_iff_create_image_identity_item(GF_ISOFile *isom_file, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props); /*! creates image item(s) from samples of a media track \param isom_file the target ISO file @@ -5613,9 +6236,11 @@ GF_Err gf_isom_iff_create_image_item_from_track(GF_ISOFile *isom_file, Bool root \param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 \param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level \param item_num 1-based index of the item to remove +\param keep_refs do not modify item reference, typically used when replacing an item +\param keep_props keep property association for properties with 4CC listed in keep_props (coma-seprated list) \return error if any */ -GF_Err gf_isom_remove_meta_item(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_num); +GF_Err gf_isom_remove_meta_item(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_num, Bool keep_refs, const char *keep_props); /*! sets the given item as the primary one \warning This SHALL NOT be used if the meta has a valid XML data @@ -5639,9 +6264,20 @@ GF_Err gf_isom_set_meta_primary_item(GF_ISOFile *isom_file, Bool root_meta, u32 */ GF_Err gf_isom_meta_add_item_ref(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 from_id, u32 to_id, u32 type, u64 *ref_index); +/*! adds the item to the given group +\param isom_file the target ISO file +\param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 +\param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level +\param item_id ID of item to add +\param group_id ID of group, 0 if needs to be determined from the file +\param group_type four character code of group +\return error if any +*/ +GF_Err gf_isom_meta_add_item_group(GF_ISOFile *isom_file, Bool root_meta, u32 track_num, u32 item_id, u32 group_id, u32 group_type); + #endif /*GPAC_DISABLE_ISOM_WRITE*/ -/*! +/*! gets image item properties \param isom_file the target ISO file \param root_meta if GF_TRUE uses meta at the file, otherwise uses meta at the movie level if track number is 0 \param track_num if GF_TRUE and root_meta is GF_FALSE, uses meta at the track level @@ -5666,28 +6302,87 @@ typedef enum /*probe is only used to check if iTunes info are present*/ GF_ISOM_ITUNE_PROBE = 0, /*all is only used to remove all tags*/ - GF_ISOM_ITUNE_ALL = 1, - GF_ISOM_ITUNE_ALBUM = GF_4CC( 0xA9, 'a', 'l', 'b' ), - GF_ISOM_ITUNE_ARTIST = GF_4CC( 0xA9, 'A', 'R', 'T' ), - GF_ISOM_ITUNE_COMMENT = GF_4CC( 0xA9, 'c', 'm', 't' ), - GF_ISOM_ITUNE_COMPILATION = GF_4CC( 'c', 'p', 'i', 'l' ), - GF_ISOM_ITUNE_COMPOSER = GF_4CC( 0xA9, 'c', 'o', 'm' ), - GF_ISOM_ITUNE_COVER_ART = GF_4CC( 'c', 'o', 'v', 'r' ), - GF_ISOM_ITUNE_CREATED = GF_4CC( 0xA9, 'd', 'a', 'y' ), - GF_ISOM_ITUNE_DISK = GF_4CC( 'd', 'i', 's', 'k' ), - GF_ISOM_ITUNE_TOOL = GF_4CC( 0xA9, 't', 'o', 'o' ), - GF_ISOM_ITUNE_GENRE = GF_4CC( 'g', 'n', 'r', 'e' ), - GF_ISOM_ITUNE_GROUP = GF_4CC( 0xA9, 'g', 'r', 'p' ), - GF_ISOM_ITUNE_ITUNES_DATA = GF_4CC( '-', '-', '-', '-' ), - GF_ISOM_ITUNE_NAME = GF_4CC( 0xA9, 'n', 'a', 'm' ), - GF_ISOM_ITUNE_TEMPO = GF_4CC( 't', 'm', 'p', 'o' ), - GF_ISOM_ITUNE_TRACK = GF_4CC( 0xA9, 't', 'r', 'k' ), - GF_ISOM_ITUNE_TRACKNUMBER = GF_4CC( 't', 'r', 'k', 'n' ), - GF_ISOM_ITUNE_WRITER = GF_4CC( 0xA9, 'w', 'r', 't' ), - GF_ISOM_ITUNE_ENCODER = GF_4CC( 0xA9, 'e', 'n', 'c' ), - GF_ISOM_ITUNE_ALBUM_ARTIST = GF_4CC( 'a', 'A', 'R', 'T' ), - GF_ISOM_ITUNE_GAPLESS = GF_4CC( 'p', 'g', 'a', 'p' ), - GF_ISOM_ITUNE_CONDUCTOR = GF_4CC( 0xA9, 'c', 'o', 'n' ), + GF_ISOM_ITUNE_RESET = 1, + GF_ISOM_ITUNE_NAME = GF_4CC( 0xA9, 'n', 'a', 'm' ), + GF_ISOM_ITUNE_ARTIST = GF_4CC( 0xA9, 'A', 'R', 'T' ), + GF_ISOM_ITUNE_ALBUM_ARTIST = GF_4CC( 'a', 'A', 'R', 'T' ), + GF_ISOM_ITUNE_ALBUM = GF_4CC( 0xA9, 'a', 'l', 'b' ), + GF_ISOM_ITUNE_GROUP = GF_4CC( 0xA9, 'g', 'r', 'p' ), + GF_ISOM_ITUNE_WRITER = GF_4CC( 0xA9, 'w', 'r', 't' ), + GF_ISOM_ITUNE_COMMENT = GF_4CC( 0xA9, 'c', 'm', 't' ), + GF_ISOM_ITUNE_GENRE_USER = GF_4CC( 0xA9, 'g', 'n', 'r'), + GF_ISOM_ITUNE_GENRE = GF_4CC( 'g', 'n', 'r', 'e' ), + GF_ISOM_ITUNE_CREATED = GF_4CC( 0xA9, 'd', 'a', 'y' ), + GF_ISOM_ITUNE_TRACKNUMBER = GF_4CC( 't', 'r', 'k', 'n' ), + GF_ISOM_ITUNE_DISK = GF_4CC( 'd', 'i', 's', 'k' ), + GF_ISOM_ITUNE_TEMPO = GF_4CC( 't', 'm', 'p', 'o' ), + GF_ISOM_ITUNE_COMPILATION = GF_4CC( 'c', 'p', 'i', 'l' ), + GF_ISOM_ITUNE_TV_SHOW = GF_4CC( 't', 'v', 's', 'h'), + GF_ISOM_ITUNE_TV_EPISODE = GF_4CC( 't', 'v', 'e', 'n'), + GF_ISOM_ITUNE_TV_SEASON = GF_4CC( 't', 'v', 's', 'n'), + GF_ISOM_ITUNE_TV_EPISODE_NUM = GF_4CC( 't', 'v', 'e', 's'), + GF_ISOM_ITUNE_TV_NETWORK = GF_4CC( 't', 'v', 'n', 'n'), + GF_ISOM_ITUNE_DESCRIPTION = GF_4CC( 'd', 'e', 's', 'c' ), + GF_ISOM_ITUNE_LONG_DESCRIPTION = GF_4CC( 'l', 'd', 'e', 's'), + GF_ISOM_ITUNE_LYRICS = GF_4CC( 0xA9, 'l', 'y', 'r' ), + GF_ISOM_ITUNE_SORT_NAME = GF_4CC( 's', 'o', 'n', 'm' ), + GF_ISOM_ITUNE_SORT_ARTIST = GF_4CC( 's', 'o', 'a', 'r' ), + GF_ISOM_ITUNE_SORT_ALB_ARTIST = GF_4CC( 's', 'o', 'a', 'a' ), + GF_ISOM_ITUNE_SORT_ALBUM = GF_4CC( 's', 'o', 'a', 'l' ), + GF_ISOM_ITUNE_SORT_COMPOSER = GF_4CC( 's', 'o', 'c', 'o' ), + GF_ISOM_ITUNE_SORT_SHOW = GF_4CC( 's', 'o', 's', 'n' ), + GF_ISOM_ITUNE_COVER_ART = GF_4CC( 'c', 'o', 'v', 'r' ), + GF_ISOM_ITUNE_COPYRIGHT = GF_4CC( 'c', 'p', 'r', 't' ), + GF_ISOM_ITUNE_TOOL = GF_4CC( 0xA9, 't', 'o', 'o' ), + GF_ISOM_ITUNE_ENCODER = GF_4CC( 0xA9, 'e', 'n', 'c' ), + GF_ISOM_ITUNE_PURCHASE_DATE = GF_4CC( 'p', 'u', 'r', 'd' ), + GF_ISOM_ITUNE_PODCAST = GF_4CC( 'p', 'c', 's', 't' ), + GF_ISOM_ITUNE_PODCAST_URL = GF_4CC( 'p', 'u', 'r', 'l' ), + GF_ISOM_ITUNE_KEYWORDS = GF_4CC( 'k', 'y', 'y', 'w'), + GF_ISOM_ITUNE_CATEGORY = GF_4CC( 'c', 'a', 't', 'g'), + GF_ISOM_ITUNE_HD_VIDEO = GF_4CC( 'h', 'd', 'v', 'd'), + GF_ISOM_ITUNE_MEDIA_TYPE = GF_4CC( 's', 't', 'i', 'k'), + GF_ISOM_ITUNE_RATING = GF_4CC( 'r', 't', 'n', 'g'), + GF_ISOM_ITUNE_GAPLESS = GF_4CC( 'p', 'g', 'a', 'p' ), + GF_ISOM_ITUNE_COMPOSER = GF_4CC( 0xA9, 'c', 'o', 'm' ), + GF_ISOM_ITUNE_TRACK = GF_4CC( 0xA9, 't', 'r', 'k' ), + GF_ISOM_ITUNE_CONDUCTOR = GF_4CC( 0xA9, 'c', 'o', 'n' ), + + GF_ISOM_ITUNE_ART_DIRECTOR = GF_4CC( 0xA9, 'a', 'r', 'd' ), + GF_ISOM_ITUNE_ARRANGER = GF_4CC( 0xA9, 'a', 'r', 'g' ), + GF_ISOM_ITUNE_LYRICIST = GF_4CC( 0xA9, 'a', 'u', 't' ), + GF_ISOM_ITUNE_COPY_ACK = GF_4CC( 0xA9, 'c', 'a', 'k' ), + GF_ISOM_ITUNE_SONG_DESC = GF_4CC( 0xA9, 'd', 'e', 's' ), + GF_ISOM_ITUNE_DIRECTOR = GF_4CC( 0xA9, 'd', 'i', 'r' ), + GF_ISOM_ITUNE_EQ_PRESET = GF_4CC( 0xA9, 'e', 'q', 'u' ), + GF_ISOM_ITUNE_LINER_NOTES = GF_4CC( 0xA9, 'l', 'n', 't' ), + GF_ISOM_ITUNE_REC_COMPANY = GF_4CC( 0xA9, 'm', 'a', 'k' ), + GF_ISOM_ITUNE_ORIG_ARTIST = GF_4CC( 0xA9, 'o', 'p', 'e' ), + GF_ISOM_ITUNE_PHONO_RIGHTS = GF_4CC( 0xA9, 'p', 'h', 'g' ), + GF_ISOM_ITUNE_PRODUCER = GF_4CC( 0xA9, 'p', 'r', 'd' ), + GF_ISOM_ITUNE_PERFORMER = GF_4CC( 0xA9, 'p', 'r', 'f' ), + GF_ISOM_ITUNE_PUBLISHER = GF_4CC( 0xA9, 'p', 'u', 'b' ), + GF_ISOM_ITUNE_SOUND_ENG = GF_4CC( 0xA9, 's', 'n', 'e' ), + GF_ISOM_ITUNE_SOLOIST = GF_4CC( 0xA9, 's', 'o', 'l' ), + GF_ISOM_ITUNE_CREDITS = GF_4CC( 0xA9, 's', 'r', 'c' ), + GF_ISOM_ITUNE_THANKS = GF_4CC( 0xA9, 't', 'h', 'x' ), + GF_ISOM_ITUNE_ONLINE = GF_4CC( 0xA9, 'u', 'r', 'l' ), + GF_ISOM_ITUNE_EXEC_PRODUCER = GF_4CC( 0xA9, 'x', 'p', 'd' ), + + + GF_ISOM_ITUNE_ITUNES_DATA = GF_4CC( '-', '-', '-', '-' ), + + /* not mapped: +Purchase Account apID UTF-8 string iTunesAccount (read only) +Account Type akID 8-bit integer Identifies the iTunes Store account type iTunesAccountType (read only) + cnID 32-bit integer iTunes Catalog ID, used for combing SD and HD encodes in iTunes cnID +Country Code sfID 32-bit integer Identifies in which iTunes Store a file was bought iTunesCountry (read only) + atID 32-bit integer Use? atID + plID 64-bit integer Use? + geID 32-bit integer Use? geID + ©st3 UTF-8 string Use? + */ + } GF_ISOiTunesTag; /*! gets the given itunes tag info. @@ -5701,18 +6396,57 @@ typedef enum */ GF_Err gf_isom_apple_get_tag(GF_ISOFile *isom_file, GF_ISOiTunesTag tag, const u8 **data, u32 *data_len); +/*! enumerate itunes tags. + +\param isom_file the target ISO file +\param idx 0-based index of the tag to get +\param out_tag set to the tag code +\param data set to the tag data pointer - do not modify +\param data_len set to the size of the tag data. Data is set to NULL and data_size to 1 if the associated tag has no data +\param out_int_val set to the int/bool/frac numerator type for known tags, in which case data is set to NULL +\param out_int_val2 set to the frac denominator for known tags, in which case data is set to NULL +\param out_flags set to the flags value of the data container box +\return error if any (GF_URL_ERROR if no more tags) +*/ +GF_Err gf_isom_apple_enum_tag(GF_ISOFile *isom_file, u32 idx, GF_ISOiTunesTag *out_tag, const u8 **data, u32 *data_len, u64 *out_int_val, u32 *out_int_val2, u32 *out_flags); + + +/*! enumerate WMA tags. + +\param isom_file the target ISO file +\param idx 0-based index of the tag to get +\param out_tag set to the tag name +\param data set to the tag data pointer - do not modify +\param data_len set to the size of the tag data +\param version set to the WMA tag version +\param data_type set to the WMA data type +\return error if any (GF_URL_ERROR if no more tags) +*/ +GF_Err gf_isom_wma_enum_tag(GF_ISOFile *isom_file, u32 idx, char **out_tag, const u8 **data, u32 *data_len, u32 *version, u32 *data_type); + #ifndef GPAC_DISABLE_ISOM_WRITE /*! sets the given tag info. -\warning For 'genre', data may be NULL in which case the genre ID taken from the data_len parameter - \param isom_file the target ISO file \param tag the tag to set -\param data tag data buffer -\param data_len size of the tag data buffer. If data and data_len are 0, removes the given tag +\param data tag data buffer or string to parse +\param data_len size of the tag data buffer. If data is NULL and and data_len not 0, removes the given tag +\param int_val value for integer/boolean tags. If data and data_len are set, parse data as string to get the value +\param int_val2 value for fractional tags. If data and data_len are set, parse data as string to get the value \return error if any */ -GF_Err gf_isom_apple_set_tag(GF_ISOFile *isom_file, GF_ISOiTunesTag tag, const u8 *data, u32 data_len); +GF_Err gf_isom_apple_set_tag(GF_ISOFile *isom_file, GF_ISOiTunesTag tag, const u8 *data, u32 data_len, u64 int_val, u32 int_val2); + + +/*! sets the given WMA tag info (only string tags are supported). + +\param isom_file the target ISO file +\param name name of the tag to set +\param value string value to set +\return error if any +*/ +GF_Err gf_isom_wma_set_tag(GF_ISOFile *isom_file, char *name, char *value); + /*! sets compatibility tag on AVC tracks (needed by iPod to play files... hurray for standards) \param isom_file the target ISO file @@ -5720,6 +6454,7 @@ GF_Err gf_isom_apple_set_tag(GF_ISOFile *isom_file, GF_ISOiTunesTag tag, const u \return error if any */ GF_Err gf_isom_set_ipod_compatible(GF_ISOFile *isom_file, u32 trackNumber); + #endif /*GPAC_DISABLE_ISOM_WRITE*/ /*! @} */ @@ -5812,7 +6547,7 @@ u8 *gf_isom_sample_get_subsamples_buffer(GF_ISOFile *isom_file, u32 trackNumber, /*! checks if a sample has subsample information \param isom_file the target ISO file \param trackNumber the target track -\param sampleNumber the target sample number +\param sampleNumber the target sample number. Set to 0 to check for presence of subsample info (will return 1 or 0 in this case) \param flags the subsample flags to query (may be 0) \return the number of subsamples in the given sample for the given flags*/ u32 gf_isom_sample_has_subsamples(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 flags); @@ -5898,7 +6633,9 @@ enum { GF_ISOM_SAMPLE_GROUP_VIPR = GF_4CC( 'v', 'i', 'p', 'r'), //p15 GF_ISOM_SAMPLE_GROUP_LBLI = GF_4CC( 'l', 'b', 'l', 'i'), //p15 GF_ISOM_SAMPLE_GROUP_3GAG = GF_4CC( '3', 'g', 'a', 'g'), //3gpp - GF_ISOM_SAMPLE_GROUP_AVCB = GF_4CC( 'a', 'v', 'c', 'b'), //3gpp + GF_ISOM_SAMPLE_GROUP_AVCB = GF_4CC( 'a', 'v', 'c', 'b'), //avif + GF_ISOM_SAMPLE_GROUP_SPOR = GF_4CC( 's', 'p', 'o', 'r'), //p15 + GF_ISOM_SAMPLE_GROUP_SULM = GF_4CC( 's', 'u', 'l', 'm'), //p15 }; /*! gets 'rap ' and 'roll' group info for the given sample @@ -5906,7 +6643,7 @@ enum { \param trackNumber the target track \param sampleNumber the target sample number \param is_rap set to GF_TRUE if sample is a rap (open gop), GF_FALSE otherwise -\param has_roll set to GF_ISOM_SAMPLE_ROLL if sample has roll information, GF_ISOM_SAMPLE_PREROLL if sample has preroll information, GF_ISOM_SAMPLE_ROLL_NONE otherwise +\param roll_type set to GF_ISOM_SAMPLE_ROLL if sample has roll information, GF_ISOM_SAMPLE_PREROLL if sample has preroll information, GF_ISOM_SAMPLE_ROLL_NONE otherwise \param roll_distance if sample has roll information, set to roll distance \return error if any*/ GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, Bool *is_rap, GF_ISOSampleRollType *roll_type, s32 *roll_distance); @@ -5915,13 +6652,24 @@ GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *isom_file, u32 trackNumber, \param isom_file the target ISO file \param trackNumber the target track \param sample_group_description_index index of sample group description entry to query -\param grouping_type four character code of grouping typpe of sample group description to query +\param grouping_type four character code of grouping type of sample group description to query \param default_index set to the default index for this sample group description if any, 0 otherwise (no defaults) \param data set to the internal sample group description data buffer \param size set to size of the sample group description data buffer \return GF_TRUE if found, GF_FALSE otherwise*/ Bool gf_isom_get_sample_group_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sample_group_description_index, u32 grouping_type, u32 *default_index, const u8 **data, u32 *size); +/*! gets sample group description index for a given sample and grouping type. +\param isom_file the target ISO file +\param trackNumber the target track +\param sample_number sample number to query +\param grouping_type four character code of grouping type of sample group description to query +\param grouping_type_parameter grouping type parameter of sample group description to query +\param sampleGroupDescIndex set to the 1-based sample group description index, or 0 if no sample group of this type is associated +\return error if any +*/ +GF_Err gf_isom_get_sample_to_group_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, u32 *sampleGroupDescIndex); + /*! checks if a track as a CENC seig sample group used for key rolling \param isom_file the target ISO file \param trackNumber the target track @@ -5944,10 +6692,36 @@ Bool gf_isom_has_cenc_sample_group(GF_ISOFile *isom_file, u32 trackNumber); Bool gf_isom_get_tile_info(GF_ISOFile *isom_file, u32 trackNumber, u32 sample_group_description_index, u32 *default_sample_group_index, u32 *id, u32 *independent, Bool *full_frame, u32 *x, u32 *y, u32 *w, u32 *h); +/*! enumerates custom sample groups (not natively supported by this library) for a given sample +\param isom_file the target ISO file +\param trackNumber the target track +\param sample_number the target sample +\param sgrp_idx the current index. Must be et to 0 on first call, incremented by this call on each success, must not be NULL +\param sgrp_type set to the grouping type, or set to 0 if no more sample group descriptions, must not be NULL +\param sgrp_parameter set to the grouping_type_parameter or 0 if not defined +\param sgrp_data set to the sample group description data +\param sgrp_size set to the sample group description size +\return error if any +*/ +GF_Err gf_isom_enum_sample_group(GF_ISOFile *isom_file, u32 trackNumber, u32 sample_number, u32 *sgrp_idx, u32 *sgrp_type, u32 *sgrp_parameter, const u8 **sgrp_data, u32 *sgrp_size); + +/*! enumerates custom sample auxiliary data (not natively supported by this library) for a given sample +\param isom_file the target ISO file +\param trackNumber the target track +\param sample_number the target sample +\param sai_idx the current index. Must be et to 0 on first call, incremented by this call on each success, must not be NULL +\param sai_type set to the grouping type, or set to 0 if no more sample group descriptions, must not be NULL +\param sai_parameter set to the grouping_type_parameter or 0 if not defined +\param sai_data set (allocated) to the sample group description data, must not be NULL and must be freed by caller +\param sgrp_size set to the sample group description size, must not be NULL +\return error if any +*/ +GF_Err gf_isom_enum_sample_aux_data(GF_ISOFile *isom_file, u32 trackNumber, u32 sample_number, u32 *sai_idx, u32 *sai_type, u32 *sai_parameter, u8 **sai_data, u32 *sai_size); + #ifndef GPAC_DISABLE_ISOM_WRITE /*! sets rap flag for sample_number - this is used by non-IDR RAPs in AVC (also in USAC) were SYNC flag (stss table) cannot be used -\warning sample group info MUST be added in order (no insertion in the tables) +\warning Sample group info MUST be added in order (no insertion in the tables) \param isom_file the target ISO file \param trackNumber the target track @@ -5960,10 +6734,10 @@ GF_Err gf_isom_set_sample_rap_group(GF_ISOFile *isom_file, u32 trackNumber, u32 /*! sets roll_distance info for sample_number (number of frames before (<0) or after (>0) this sample to have a complete refresh of the decoded data (used by GDR in AVC) -\warning sample group info MUST be added in order (no insertion in the tables) +\warning Sample group info MUST be added in order (no insertion in the tables) \param isom_file the target ISO file \param trackNumber the target track -\param sampleNumber the target sample number +\param sampleNumber the target sample number. If 0, assumes last added sample. If 0xFFFFFFFF, marks all samples as belonging to the roll group \param roll_type indicates the sample roll recovery type \param roll_distance indicates the roll distance before a correct decoding is produced \return error if any @@ -5975,15 +6749,14 @@ GF_Err gf_isom_set_sample_roll_group(GF_ISOFile *isom_file, u32 trackNumber, u32 \param trackNumber the target track \param sampleNumber the target sample number \param isEncrypted isEncrypted flag -\param IV_size IV size, can be 0 if not encrypted -\param KeyID key ID used \param crypt_byte_block crypt block size for pattern encryption, can be 0 \param skip_byte_block skip block size for pattern encryption, can be 0 -\param constant_IV_size constant IV size, can be 0 -\param constant_IV constant IV, can be 0 +\param key_info multikey descriptor (cf CENC and GF_PROP_PID_CENC_KEY) +\param key_info_size multikey descriptor size \return error if any */ -GF_Err gf_isom_set_sample_cenc_group(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u8 isEncrypted, u8 IV_size, bin128 KeyID, u8 crypt_byte_block, u8 skip_byte_block, u8 constant_IV_size, bin128 constant_IV); +GF_Err gf_isom_set_sample_cenc_group(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u8 isEncrypted, u8 crypt_byte_block, u8 skip_byte_block, u8 *key_info, u32 key_info_size); + /*! sets a sample using the default CENC parameters in a CENC saig sample group SEIG, creating a sample group description if needed (when seig is already defined) \param isom_file the target ISO file @@ -6013,6 +6786,19 @@ GF_Err gf_isom_add_sample_group_info(GF_ISOFile *isom_file, u32 trackNumber, u32 */ GF_Err gf_isom_remove_sample_group(GF_ISOFile *isom_file, u32 trackNumber, u32 grouping_type); +/*! adds the given blob as a sample group description entry of the given grouping type for the given sample. +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleNumber the target sample number.Use 0 for setting sample group info to last sample in a track fragment +\param grouping_type the four character code of the grouping type +\param grouping_type_parameter associated grouping type parameter (usually 0) +\param data the payload of the sample group description +\param data_size the size of the payload +\return error if any +*/ +GF_Err gf_isom_set_sample_group_description(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, u32 grouping_type, u32 grouping_type_parameter, void *data, u32 data_size); + + /*! adds a sample to the given sample group \param isom_file the target ISO file \param trackNumber the target track diff --git a/include/gpac/main.h b/include/gpac/main.h index bca5f6e..e85afe8 100644 --- a/include/gpac/main.h +++ b/include/gpac/main.h @@ -39,7 +39,7 @@ extern "C" { \addtogroup sysmain_grp @{ -Thiis section decribes functions useful when developping an application using libgpac such as: +Thiis section decribes functions useful when developing an application using libgpac such as: - quick UTF8 conversion of arguments for main() on windows - setting, checking and printing libgpac arguments as given from command line */ @@ -57,16 +57,17 @@ int wmain( int argc, wchar_t** wargv )\ {\ int i;\ int res;\ - size_t len;\ - size_t res_len;\ + u32 len;\ + u32 res_len;\ char **argv;\ argv = (char **)malloc(argc*sizeof(wchar_t *));\ for (i = 0; i < argc; i++) {\ wchar_t *src_str = wargv[i];\ len = UTF8_MAX_BYTES_PER_CHAR*gf_utf8_wcslen(wargv[i]);\ argv[i] = (char *)malloc(len + 1);\ - res_len = gf_utf8_wcstombs(argv[i], len, &src_str);\ - argv[i][res_len] = 0;\ + res_len = gf_utf8_wcstombs(argv[i], len, (const unsigned short **) &src_str);\ + if (res_len != GF_UTF8_FAIL)\ + argv[i][res_len] = 0;\ if (res_len > len) {\ fprintf(stderr, "Length allocated for conversion of wide char to UTF-8 not sufficient\n");\ return -1;\ @@ -90,23 +91,29 @@ int main(int argc, char **argv) {\ #endif //win32 -/*! structure holding a gpac arg (not a filter arg)*/ +/*! macro defining fields of a libgpac arg (not a filter arg)*/ +#define GF_GPAC_ARG_BASE \ + /*! name of arg*/ \ + const char *name; \ + /*! alternate name of arg*/ \ + const char *altname; \ + /*! description of arg*/ \ + const char *description; \ + /*! default value of arg*/ \ + const char *val; \ + /*! possible value of arg*/ \ + const char *values; \ + /*! argument type for UI construction - note that argument values are not parsed and shall be set as strings*/ \ + u16 type; \ + /*! argument flags*/ \ + u16 flags; \ + + +/*! structure holding a libgpac arg (not a filter arg)*/ typedef struct { - /*! name of arg*/ - const char *name; - /*! alternate name of arg*/ - const char *altname; - /*! description of arg*/ - const char *description; - /*! default value of arg*/ - const char *val; - /*! possible value of arg*/ - const char *values; - /*! argument type for UI construction - note that argument values are not parsed and shall be set as strings*/ - u16 type; - /*! argument flags*/ - u16 flags; + /*! base structure, shall always be placed first if you extend args in your application*/ + GF_GPAC_ARG_BASE } GF_GPACArg; //these 3 values match argument hints of filters @@ -135,6 +142,8 @@ typedef struct #define GF_ARG_SUBSYS_TEXT (1<<11) /*! argument applies to the remotery subsystem*/ #define GF_ARG_SUBSYS_RMT (1<<12) +/*! argument belongs to hack tools, usually never used*/ +#define GF_ARG_SUBSYS_HACKS (1<<13) /*! argument is a boolean*/ #define GF_ARG_BOOL 0 @@ -146,6 +155,12 @@ typedef struct #define GF_ARG_STRING 3 /*! argument is a camma-separated list of strings*/ #define GF_ARG_STRINGS 4 +/*! argument is a custom arg, default value contains the syntax of the argument*/ +#define GF_ARG_4CC 5 +/*! argument is a custom arg, default value contains the syntax of the argument*/ +#define GF_ARG_4CCS 6 +/*! argument is a custom arg, default value contains the syntax of the argument*/ +#define GF_ARG_CUSTOM 7 /*! macros for defining a GF_GPACArg argument*/ #define GF_DEF_ARG(_a, _b, _c, _d, _e, _f, _g) {_a, _b, _c, _d, _e, _f, _g} @@ -160,7 +175,7 @@ const GF_GPACArg *gf_sys_get_options(); u32 gf_sys_is_gpac_arg(const char *arg_name); /*! parses config string and update config accordingly -\param opt_string section/key/val formatted as Section:Key (discard key), Section:Key=null (discard key), Section:Key=Val (set key) or Section:*=null (discard section) +\param opt_string section/key/val formatted as Section:Key (discard key), Section:Key=null (discard key), Section:Key=Val (set key) or Section=null (discard section) \return GF_TRUE if update is OK, GF_FALSE otherwise*/ Bool gf_sys_set_cfg_option(const char *opt_string); @@ -177,18 +192,18 @@ typedef enum GF_ARGMODE_ALL } GF_SysArgMode; -/*! flags for help formating*/ +/*! flags for help formatting*/ typedef enum { /*! first word in format string should be highlighted */ GF_PRINTARG_HIGHLIGHT_FIRST = 1, /*! prints
instead of new line*/ GF_PRINTARG_NL_TO_BR = 1<<1, - /*! first word in format string is an option descritptor*/ + /*! first word in format string is an option descripttor*/ GF_PRINTARG_OPT_DESC = 1<<2, /*! the format string is an application string, not a gpac core one*/ GF_PRINTARG_IS_APP = 1<<3, - /*! insert an extra '-' at the begining*/ + /*! insert an extra '-' at the beginning*/ GF_PRINTARG_ADD_DASH = 1<<4, /*! do not insert '-' before arg name*/ GF_PRINTARG_NO_DASH = 1<<5, diff --git a/include/gpac/maths.h b/include/gpac/maths.h index 5cc4daa..8160d6a 100644 --- a/include/gpac/maths.h +++ b/include/gpac/maths.h @@ -47,7 +47,7 @@ extern "C" { This section documents the math and trigo functions used in the GPAC framework. GPAC can be compiled with fixed-point support, representing float values on a 16.16 signed integer, which implies a developer must take care of float computations when using GPAC.\n - A developper should not need to know in which mode the framework has been compiled as long as he uses + A developer should not need to know in which mode the framework has been compiled as long as he uses the math functions of GPAC which work in both float and fixed-point mode.\n Using fixed-point version is decided at compilation time and cannot be changed. The feature is signaled through the GPAC_FIXED_POINT macro: when defined, GPAC has been compiled in fixed-point mode @@ -326,6 +326,15 @@ Tests if two rectangles are identical. */ Bool gf_rect_equal(GF_Rect *rc1, GF_Rect *rc2); +/*! +\brief rectangle intersection + +Intersects two rectangle. +\param rc1 rectangle to use, updated to intersection result +\param rc2 second rectangle to use +*/ +void gf_rect_intersect(GF_Rect *rc1, GF_Rect *rc2); + /*! \brief pixel-aligned rectangle diff --git a/include/gpac/media_tools.h b/include/gpac/media_tools.h index a037b20..fd918ad 100644 --- a/include/gpac/media_tools.h +++ b/include/gpac/media_tools.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Authoring Tools sub-project @@ -107,6 +107,21 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *isom_file, u32 trackNumber, */ GF_Err gf_media_change_par(GF_ISOFile *isom_file, u32 trackNumber, s32 ar_num, s32 ar_den, Bool force_par, Bool rewrite_par); +/*! Changes color property of the media (bitstream rewrite) - only AVC/H264 supported for now. See CICP for value types +Negative values keep source settings for the corresponding flags. +If source stream has no VUI info, create one and set corresponding flags to specified values. +In this case, any other flags are set to preferred values (typically, flag=0 or value=undef). +\param isom_file target ISOBMF file +\param trackNumber target track +\param fullrange fullrange flag +\param video_format video format type +\param color_primaries color primaries +\param transfer transfer characteristics +\param color_matrix olor matrix +\return error if any +*/ +GF_Err gf_media_change_color(GF_ISOFile *isom_file, u32 trackNumber, s32 fullrange, s32 video_format, s32 color_primaries, s32 transfer, s32 color_matrix); + /*! *Removes all non rap samples (sync and other RAP sample group info) from the track. \param isom_file target ISOBMF file @@ -123,6 +138,17 @@ GF_Err gf_media_remove_non_rap(GF_ISOFile *isom_file, u32 trackNumber, Bool non_ */ void gf_media_update_bitrate(GF_ISOFile *isom_file, u32 trackNumber); + +/*! gets AV1 scalable layer byte offsets of a sample for a1lx box +\param isom_file the target ISO file +\param trackNumber the target track +\param sample_number the target sample to query +\param op_index AV1 operating point index to retrieve sizes for +\param layer_size returned 3 layer sizes (4th is implied, see a1lx spec) +\return error if any +*/ +GF_Err gf_media_av1_layer_size_get(GF_ISOFile *isom_file, u32 trackNumber, u32 sample_number, u8 op_index, u32 layer_size[3]); + #endif /*! @} */ @@ -151,7 +177,7 @@ Default import FPS for video when no VUI/timing information is found otherwise it is added with the requested ESID if non-0, otherwise the new trackID is stored in ESID if use_data_ref is set, data is only referenced in the file if duration is not 0, only the first duration seconds are imported - NOTE: if an ESD is specified, its decoderSpecificInfo is also updated + \note If an ESD is specified, its decoderSpecificInfo is also updated */ @@ -383,29 +409,49 @@ typedef struct __track_import const char *filter_src_opts; /*! any filter options to pass to sink*/ const char *filter_dst_opts; - /*! filter chain to insert before destination, formated as f1[:args]@@f2[:args] options to pass to sink*/ + /*! filter chain to insert before destination, formatted as "f1[:args]@f2[:args]" options to pass to sink*/ const char *filter_chain; + Bool is_chain_old_syntax; - + /*! force mode for the created ISOBMFF sample entry*/ GF_AudioSampleEntryImportMode asemode; - Bool audio_roll_change; - s16 audio_roll; - + /*! indicate to tag the imported media as an alpha channel stream*/ Bool is_alpha; + /*! keep AU delimiter in file if allowed by specification*/ Bool keep_audelim; + /*! import as NAL-based video using inband parameter sets*/ u32 xps_inband; + /*! flag for session stats and graph dumping*/ u32 print_stats_graph; + /*! target program ID of source MPEG-2 stream to import*/ u32 prog_id; + /*! target timescale to set*/ + s32 moov_timescale; + + /*! value for created track + 0: let importer decide + 0xFFFFFFFF: try to keep source ID + other value: trackk ID value + */ + u32 target_trackID; + /*magic number for identifying source, will be set to the destination track. Only the low 32 bits are used the high 32 bits are updated by the importer as follows: 1<<33: if bit is set, source was an isobmff file */ u64 source_magic; + /*! the session in which to add the importer (for -new-fs option only). If null, the importer runs its own session right away*/ GF_FilterSession *run_in_session; + /*! muxer arguments when running multiple importers in one session*/ char *update_mux_args; + /*! muxer source ID argument when running multiple importers in one session*/ + char *update_mux_sid; + /*! index of source importer when running multiple importers in one session*/ u32 track_index; + /*! target start time in source*/ + Double start_time; } GF_MediaImporter; /*! @@ -475,10 +521,11 @@ This section documents functions for manipulating AVC and HEVC tracks in ISOBMFF \param isom_file the target ISOBMF file \param trackNumber the target track \param profile the new profile to set +\param compat profile compatibility flag for H264 \param level the new level to set \return error if any */ -GF_Err gf_media_change_pl(GF_ISOFile *isom_file, u32 trackNumber, u32 profile, u32 level); +GF_Err gf_media_change_pl(GF_ISOFile *isom_file, u32 trackNumber, u32 profile, u32 compat, u32 level); /*! Rewrite NAL-based samples (AVC/HEVC/...) samples if nalu size_length has to be changed @@ -514,7 +561,7 @@ typedef enum GF_LHVC_EXTRACTORS_ON, /*! don't use extractors and keep base track inband/outofband param set signaling*/ GF_LHVC_EXTRACTORS_OFF, - /*! don't use extractors and force inband signaling in enhancement layer (for ATSC3)*/ + /*! don't use extractors and force inband signaling in enhancement layer*/ GF_LHVC_EXTRACTORS_OFF_FORCE_INBAND } GF_LHVCExtractoreMode; @@ -570,14 +617,14 @@ typedef struct { /*! source file to be used*/ char *file_name; - /*! ID of the representation. If not set, assigned automatically*/ + /*! ID of the representation, may be NULL (assigned by dasher)*/ char *representationID; - /*! ID of the period. If not set, assigned automatically*/ + /*! ID of the period, may be NULL (assigned by dasher)*/ char *periodID; - /*! ID of the adaptation set. If not set, assigned automatically.*/ + /*! ID of the adaptation set, may be 0 (assigned by dasher)*/ u32 asID; /*! forced media duration.*/ - Double media_duration; + GF_Fraction64 media_duration; /*! number of base URLs in the baseURL structure*/ u32 nb_baseURL; /*! list of baseURL to be used for this representation*/ @@ -607,9 +654,9 @@ typedef struct /*! forces bandwidth in bits per seconds of the source media. If 0, computed from file */ u32 bandwidth; /*! forced period duration (used when using empty periods or xlink periods without content)*/ - Double period_duration; + GF_Fraction period_duration; /*! forced dash target duration for this rep*/ - Double dash_duration; + GF_Fraction dash_duration; /*! sets default start number for this representation. if not set, assigned automatically */ u32 startNumber; //TODO: start number, template /*! overrides template for this input*/ @@ -653,6 +700,8 @@ typedef enum GF_DASH_PROFILE_AVC264_LIVE, /*! industry profile DASH-IF ISOBMFF onDemand */ GF_DASH_PROFILE_AVC264_ONDEMAND, + /*! industry profile DASH-IF ISOBMFF low latency */ + GF_DASH_PROFILE_DASHIF_LL, } GF_DashProfile; @@ -668,6 +717,8 @@ typedef enum GF_DASH_BSMODE_NONE, /*! always inband parameter sets */ GF_DASH_BSMODE_INBAND, + /*! out of band parameter sets except PPS and APS, used for VVC */ + GF_DASH_BSMODE_INBAND_PPS, /*! attempts to merge parameter sets in a single sample entry */ GF_DASH_BSMODE_MERGED, /*! parameter sets are in different sample entries */ @@ -714,7 +765,7 @@ typedef struct __gf_dash_segmenter GF_DASHSegmenter; Create a new DASH segmenter \param mpdName target MPD file name, cannot be changed \param profile target DASH profile, cannot be changed -\param tmp_dir temp dir for file generation, OS NULL for default +\param tmp_dir temp dir for file generation, if NULL uses libgpac default \param timescale timescale used to specif most of the dash timings. If 0, 1000 is used \param dasher_context_file config file used to store the context of the DASH segmenter. This allows destroying the segmenter and restarting it later on with the right DASH segquence numbers, MPD and and timing info \return the DASH segmenter object @@ -815,7 +866,7 @@ GF_Err gf_dasher_set_switch_mode(GF_DASHSegmenter *dasher, GF_DashSwitchingMode GF_Err gf_dasher_set_durations(GF_DASHSegmenter *dasher, Double default_segment_duration, Double default_fragment_duration, Double sub_duration); /*! - Enables spliting at RAP boundaries + Enables splitting at RAP boundaries \param dasher the DASH segmenter object \param segments_start_with_rap segments will be split at RAP boundaries \param fragments_start_with_rap fragments will be split at RAP boundaries @@ -989,6 +1040,15 @@ typedef enum */ GF_Err gf_dasher_set_split_mode(GF_DASHSegmenter *dasher, GF_DASH_SplitMode split_mode); + +/*! + Enable/Disable last segment merging (disabled by default). + * \param dasher the DASH segmenter object + * \param merge_last_seg if true, last segment is merged into previous if duration less than half target dur + * \return error code if any +*/ +GF_Err gf_dasher_set_last_segment_merge(GF_DASHSegmenter *dasher, Bool merge_last_seg); + /*! Sets m3u8 file name - if not set, no m3u8 output \param dasher the DASH segmenter object @@ -1047,6 +1107,14 @@ void gf_dasher_set_start_date(GF_DASHSegmenter *dasher, const char *dash_utc_sta */ GF_Err gf_dasher_print_session_info(GF_DASHSegmenter *dasher, u32 fs_print_flags); +/*! + Keeps UTC creation and modification dates from sources, if any (default is no) +\param dasher the DASH segmenter object +\param keep_utc if GF_TRUE, keeps UTC times +\return error if any +*/ +GF_Err gf_dasher_keep_source_utc(GF_DASHSegmenter *dasher, Bool keep_utc); + #ifndef GPAC_DISABLE_ISOM_FRAGMENTS /*! save file as fragmented movie @@ -1088,12 +1156,12 @@ enum GF_EXPORT_RAW_SAMPLES = (1<<1), /*! NHNT format (any MPEG-4 media)*/ GF_EXPORT_NHNT = (1<<2), - /*! AVI (MPEG4 video and AVC tracks only)*/ - GF_EXPORT_AVI = (1<<3), + /*! full remux of source file - equivalent to `gpac -i in_name:FID=1 reframer:FID=2:SID=1 -o out_name:SID=2` */ + GF_EXPORT_REMUX = (1<<3), /*! MP4 (all except OD)*/ GF_EXPORT_MP4 = (1<<4), - /*! AVI->RAW to dump video (trackID=1) or audio (trackID>=2)*/ - GF_EXPORT_AVI_NATIVE = (1<<5), + /*! currently unused*/ + GF_EXPORT_UNUSED = (1<<4), /*! NHML format (any media)*/ GF_EXPORT_NHML = (1<<6), /*! SAF format*/ @@ -1123,7 +1191,7 @@ enum /*! Experimental Streaming Instructions */ GF_EXPORT_SIX = (1<<16), - /*! ony probes extraction format*/ + /*! only probes extraction format*/ GF_EXPORT_PROBE_ONLY = (1<<30), /*when set by user during export, will abort*/ GF_EXPORT_DO_ABORT = 0x80000000 //(1<<31) @@ -1148,7 +1216,10 @@ typedef struct __track_exporter char *in_name; /*! optional FILE for output*/ FILE *dump_file; + /*! filter session dump flags*/ u32 print_stats_graph; + /*! track type: 0: none specified, 1: video, 2: audio*/ + u32 track_type; } GF_MediaExporter; /*! @@ -1373,6 +1444,16 @@ GF_Err gf_saf_mux_for_time(GF_SAFMuxer *mux, u32 time_ms, Bool force_end_of_sess */ void gf_media_get_video_timing(Double fps, u32 *timescale, u32 *ts_inc); +/*! gets dolby vision level + \param width width in pixels of video + \param height height in pixels of video + \param fps_num framerate numerator + \param fps_den framerate denominator + \param codecid GPAC codec ID + \return dv level +*/ +u32 gf_dolby_vision_level(u32 width, u32 height, u64 fps_num, u64 fps_den, u32 codecid); + #ifdef __cplusplus } #endif diff --git a/include/gpac/mediaobject.h b/include/gpac/mediaobject.h index d617609..b9133f8 100644 --- a/include/gpac/mediaobject.h +++ b/include/gpac/mediaobject.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Stream Management sub-project @@ -42,7 +42,7 @@ extern "C" { \ingroup playback_grp \brief Interface between compositor and decoding engine for media data access. -This section documents the API betwwen the compositor of GPAC and the decoding engine (terminal) +This section documents the API between the compositor of GPAC and the decoding engine (terminal) @{ */ @@ -55,8 +55,8 @@ This section documents the API betwwen the compositor of GPAC and the decoding e opaque handler for all natural media objects (audio, video, image) so that compositor and systems engine are not too tied up. - NOTE: the media object location relies on the node parent graph (this is to deal with namespaces in OD framework) -therefore it is the task of the media management app to setup clear links between the scene graph and its ressources + \note The media object location relies on the node parent graph (this is to deal with namespaces in OD framework) +therefore it is the task of the media management app to setup clear links between the scene graph and its resources (but this is not mandatory, cf URLs in VRML ) */ typedef struct _mediaobj GF_MediaObject; @@ -112,7 +112,7 @@ you must use the gf_mo_get_speed and gf_mo_get_loop in order to know whether the */ /*! sets speed of media - speed is not always applied, depending on media control settings. -NOTE: audio pitching is the responsability of the rendering app +\note audio pitching is the responsability of the rendering app \param mo the target media object \param speed the playback speed to set */ @@ -229,21 +229,16 @@ Bool gf_mo_is_started(GF_MediaObject *mo); \param stride set to stride in bytes for visual objects with data frame, 0 if unknown \param pixel_ar set to the pixel aspect ratio as \code (PAR_NUM<<16)|PAR_DEN \endcode \param pixelFormat set to the pixel format of the video -\param is_flipped set to GF_TRUE if the pixels are vertically flipped (happens when reading back openGL textures) +\param is_flipped set to GF_TRUE if the pixels are vertically flipped (happens when reading back OpenGL textures) \return GF_TRUE if success*/ Bool gf_mo_get_visual_info(GF_MediaObject *mo, u32 *width, u32 *height, u32 *stride, u32 *pixel_ar, u32 *pixelFormat, Bool *is_flipped); /*! gets number of views for 3D video object \param mo the target media object -\param nb_views set to the number of views in the object +\param nb_views set to the number of views in the object, vertically packed */ void gf_mo_get_nb_views(GF_MediaObject *mo, u32 *nb_views); -/*! gets number of layers for 2D scalable video object -\param mo the target media object -\param nb_layers set to the number of layers in the object -*/ -void gf_mo_get_nb_layers(GF_MediaObject *mo, u32 *nb_layers); /*! gets visual information of a media object \param mo the target media object \param sample_rate set to the sampling frequency of the object @@ -269,7 +264,7 @@ typedef enum { /*used by animation stream to remove TEXT from display upon delete and URL change*/ GF_MO_DISPLAY_REMOVE = (1<<1), - /*used when resyncing a stream (droping late frames)*/ + /*used when resyncing a stream (dropping late frames)*/ GF_MO_IN_RESYNC = (1<<2), } GF_MOUserFlags; /*! sets flags on a media object diff --git a/include/gpac/module.h b/include/gpac/module.h index 7a75354..38733bf 100644 --- a/include/gpac/module.h +++ b/include/gpac/module.h @@ -210,15 +210,6 @@ Gets the number of modules found in the manager directory */ u32 gf_modules_count(); -/*! -\brief get all modules directories - -Update module manager with all modules directories -\param num_dirs the number of module directories -\return The list of modules directories - */ -const char **gf_modules_get_module_directories(u32* num_dirs); - /*! \brief get module file name diff --git a/include/gpac/modules/audio_out.h b/include/gpac/modules/audio_out.h index e4baef7..0c3de44 100644 --- a/include/gpac/modules/audio_out.h +++ b/include/gpac/modules/audio_out.h @@ -88,7 +88,7 @@ typedef struct _audiooutput u32 (*GetTotalBufferTime)(struct _audiooutput *aout); /*returns audio delay in ms, eg time delay until written audio data is outputed by the sound card - This function is only called after ConfigureOuput*/ + This function is only called after ConfigureOutput*/ u32 (*GetAudioDelay)(struct _audiooutput *aout); /*set output volume(between 0 and 100) */ diff --git a/include/gpac/modules/codec.h b/include/gpac/modules/codec.h index 4c4008f..a7e435c 100644 --- a/include/gpac/modules/codec.h +++ b/include/gpac/modules/codec.h @@ -118,7 +118,7 @@ enum GF_CODEC_PIXEL_FORMAT, /*signal decoder performs frame re-ordering in temporal scalability*/ GF_CODEC_REORDER, - /*signal decoder can safely handle CTS when outputing a picture. If not supported by the + /*signal decoder can safely handle CTS when outputting a picture. If not supported by the decoder, the terminal will automatically handle CTS adjustments*/ GF_CODEC_TRUSTED_CTS, @@ -282,7 +282,7 @@ typedef struct _mediadecoderframe void (*Release)(struct _mediadecoderframe *frame); //get media frame plane // @plane_idx: plane index, 0: Y or full plane, 1: U or UV plane, 2: V plane - // @outPlane: adress of target color plane + // @outPlane: address of target color plane // @outStride: stride in bytes of target color plane GF_Err (*GetPlane)(struct _mediadecoderframe *frame, u32 plane_idx, const char **outPlane, u32 *outStride); diff --git a/include/gpac/modules/video_out.h b/include/gpac/modules/video_out.h index 7ea84a1..ed4f620 100644 --- a/include/gpac/modules/video_out.h +++ b/include/gpac/modules/video_out.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2020 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / modules interfaces @@ -101,9 +101,9 @@ typedef struct _gf_sc_texture_handler GF_TextureH; the app accesses to the surface through the GF_VideoSurface handler. The module may support HW blitting of RGB or YUV data to backbuffer. - ** the 3D video output only handles window management and openGL contexts setup. + ** the 3D video output only handles window management and OpenGL contexts setup. The context shall be setup in Resize and SetFullScreen calls which are always happening in the main - rendering thread. This will take care of openGL context issues with multithreading + rendering thread. This will take care of OpenGL context issues with multithreading By default all modules are required to be setup in 2D. If 3D is needed, a GF_EVENT_VIDEO_SETUP will be sent with the desired configuration. @@ -125,7 +125,7 @@ typedef struct _video_out /*flush video: the video shall be presented to screen the destination area to update is in client display coordinates (0,0) being top-left, (w,h) bottom-right - Note: dest is always NULL in 3D mode (buffer flip only)*/ + \note dest is always NULL in 3D mode (buffer flip only)*/ GF_Err (*Flush) (struct _video_out *vout, GF_Window *dest); GF_Err (*SetFullScreen) (struct _video_out *vout, Bool fs_on, u32 *new_disp_width, u32 *new_disp_height); diff --git a/include/gpac/mpd.h b/include/gpac/mpd.h index a35cc6c..75db2f5 100644 --- a/include/gpac/mpd.h +++ b/include/gpac/mpd.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - Cyril Concolato - * Copyright (c) Telecom ParisTech 2010-2012 + * Copyright (c) Telecom ParisTech 2010-2022 * All rights reserved * * This file is part of GPAC / 3GPP/MPEG Media Presentation Description input module @@ -109,16 +109,10 @@ Some elments are typically overloaded in XML, we keep the attributes / children The children list is NULL if no extensions were found, otherwise it is a list of GF_XMLNode */ #define MPD_EXTENSIBLE \ - GF_List *attributes; \ - GF_List *children; \ + GF_List *x_attributes; \ + GF_List *x_children; \ -/*! basic extensible MPD element*/ -typedef struct -{ - MPD_EXTENSIBLE -} GF_MPD_ExtensibleVirtual; - -/*! basic extensible MPD descritpor*/ +/*! basic extensible MPD descriptor*/ typedef struct { MPD_EXTENSIBLE @@ -210,15 +204,6 @@ typedef struct s64 mediaOffset; } GF_MPD_ISOBMFInfo; - -/*! other XML descriptors*/ -typedef struct -{ - /*! list of XML descriptors*/ - char *xml_desc; -} GF_MPD_other_descriptors; - - /*! macro for MPD segment base*/ #define GF_MPD_SEGMENT_BASE \ u32 timescale; \ @@ -274,8 +259,16 @@ typedef struct char *key_url; /*! key IV of segment, HLS only*/ bin128 key_iv; - /*! UTC start time of segment, HLS only*/ - u64 hls_utc_start_time; + /*! sequence number of segment, HLS only*/ + u32 hls_seq_num; + /*! informative UTC start time of segment, HLS only*/ + u64 hls_utc_time; + /*! 0: full segment, 1: LL-HLS part, 2: independent LL-HLS part */ + u8 hls_ll_chunk_type; + /*! merge flag for byte-range subsegs 0: cannot merge, 1: can merge */ + u8 can_merge; + /*! merge flag for byte-range subsegs 0: cannot merge, 1: can merge */ + u8 is_first_part; } GF_MPD_SegmentURL; /*! SegmentList*/ @@ -290,10 +283,12 @@ typedef struct /*! xlink evaluation on load if set, otherwise on use*/ Bool xlink_actuate_on_load; - /*! GPAC intenral, number of consecutive xlink while solving*/ + /*! GPAC internal, number of consecutive xlink while solving*/ u32 consecutive_xlink_count; - /*! GPAC intenral, we store the segment template here*/ + /*! GPAC internal, we store the segment template here*/ char *dasher_segment_name; + /*! GPAC internal, we store the previous xlink before resolution*/ + char *previous_xlink_href; } GF_MPD_SegmentList; /*! SegmentTemplate*/ @@ -309,6 +304,9 @@ typedef struct char *initialization; /*! bitstream switching segment template*/ char *bitstream_switching; + + /*! internal, for HLS generation*/ + const char *hls_init_name; } GF_MPD_SegmentTemplate; /*! MPD scan types*/ @@ -337,6 +335,8 @@ MANDATORY: codecs */ #define GF_MPD_COMMON_ATTRIBUTES_ELEMENTS \ + GF_List *x_attributes; \ + GF_List *x_children; \ char *profiles; \ u32 width; \ u32 height; \ @@ -389,7 +389,7 @@ typedef struct { char *wallclock; /*! presentation time in timescale of the Representation*/ u64 presentation_time; - /*! UTC timing desc if any/*/ + /*! UTC timing desc if any */ GF_MPD_Descriptor *utc_timing; } GF_MPD_ProducerReferenceTime; @@ -440,8 +440,18 @@ typedef struct u32 enhancement_rep_index_plus_one; /*! set to true if the representation comes from a broadcast link (ATSC3, eMBMS)*/ Bool broadcast_flag; + + /*! if set indicates the associated representations use vvc rpr switching*/ + Bool vvc_rpr_switch; + + /*! start of segment name in full url*/ + const char *init_seg_name_start; /*! opaque data*/ void *udta; + /*! SHA1 digest for xlinks / m3u8*/ + u8 xlink_digest[GF_SHA1_DIGEST_SIZE]; + /*! set to TRUE if not modified in the update of an xlink*/ + Bool not_modified; } GF_DASH_RepresentationPlayback; /*! segment context used by the dasher, GPAC internal*/ @@ -450,9 +460,9 @@ typedef struct /*! ID of active period*/ char *period_id; /*! start of active period*/ - Double period_start; + GF_Fraction64 period_start; /*! duration of active period*/ - Double period_duration; + GF_Fraction64 period_duration; /*! if GF_TRUE, representation is over*/ Bool done; /*! niumber of last packet processed (to resume dashing)*/ @@ -478,7 +488,7 @@ typedef struct /*! indicates if uses multi PID (eg, multiple sample descriptions in init segment)*/ Bool multi_pids; /*! target segment duration for this stream*/ - Double dash_dur; + GF_Fraction dash_dur; /*! estimated next segment start time in MPD timescale*/ u64 next_seg_start; /*! first CTS of stream in stream timescale*/ @@ -513,6 +523,19 @@ typedef struct Bool subdur_forced; } GF_DASH_SegmenterContext; +/*! fragment context info for LL-HLS*/ +typedef struct +{ + /*! frag offset in bytes*/ + u64 offset; + /*! frag size in bytes*/ + u64 size; + /*! frag duration in representation timescale*/ + u32 duration; + /*! fragment contains an IDR*/ + Bool independent; +} GF_DASH_FragmentContext; + /*! Segment context - GPAC internal, used to produce HLS manifests and segment lists/timeline*/ typedef struct { @@ -534,6 +557,20 @@ typedef struct u64 index_offset; /*! segment number */ u32 seg_num; + /*! number of fragment infos */ + u32 nb_frags; + /*! number of fragment infos */ + GF_DASH_FragmentContext *frags; + /*! HLS LL signaling - 0: disabled, 1: byte range, 2: files */ + u32 llhls_mode; + /*! HLS LL segment done */ + Bool llhls_done; + /*! HLS set to TRUE if encrypted */ + Bool encrypted; + /*! HLS key params (URI and co)*/ + char *hls_key_uri; + /*! HLS IV*/ + bin128 hls_iv; } GF_DASH_SegmentContext; /*! Representation*/ @@ -563,9 +600,6 @@ typedef struct { /*! number of subrepresentation*/ GF_List *sub_representations; - /*! other MPD descriptors*/ - GF_List *other_descriptors; - /*! all the below members are GPAC internal*/ /*! GPAC playback implementation*/ @@ -574,6 +608,10 @@ typedef struct { u32 m3u8_media_seq_min; /*! internal, HLS: max sequence number of segments in playlist*/ u32 m3u8_media_seq_max; + /*! internal, HLS: indicate this is a low latency rep*/ + u32 m3u8_low_latency; + /*! internal, HLS: sequence number of last indeendent segment or PART in playlist*/ + u32 m3u8_media_seq_indep_last; /*! GPAC dasher context*/ GF_DASH_SegmenterContext *dasher_ctx; @@ -586,7 +624,7 @@ typedef struct { /*! segment manifest timescale (for HLS)*/ u32 timescale_mpd; /*! dash duration*/ - Double dash_dur; + GF_Fraction dash_dur; /*! init segment name for HLS single file*/ const char *hls_single_file_name; /*! number of audio channels - HLS only*/ @@ -602,6 +640,19 @@ typedef struct { char *m3u8_var_name; /*! temp file for m3u8 generation*/ FILE *m3u8_var_file; + + /*! for m3u8: 0: not encrypted, 1: full segment, 2: CENC*/ + u8 crypto_type; + u8 def_kms_used; + + u32 nb_hls_master_tags; + const char **hls_master_tags; + + u32 nb_hls_variant_tags; + const char **hls_variant_tags; + + /*! target part (cmaf chunk) duration for HLS LL*/ + Double hls_ll_part_dur; } GF_MPD_Representation; /*! AdaptationSet*/ @@ -609,8 +660,8 @@ typedef struct { /*! inherits common attributes*/ GF_MPD_COMMON_ATTRIBUTES_ELEMENTS - /*! ID of this set*/ - u32 id; + /*! ID of this set, -1 if not set*/ + s32 id; /*! group ID for this set, default value is -1: not set in MPD*/ s32 group; /*! language*/ @@ -668,11 +719,23 @@ typedef struct char *xlink_href; /*! xlink evaluation on load if set, otherwise on use*/ Bool xlink_actuate_on_load; - /*! other descriptors*/ - GF_List *other_descriptors; /*! user private, eg used by dasher*/ void *udta; + + /*! mpegh compatible profile hack*/ + u32 nb_alt_mha_profiles, *alt_mha_profiles; + Bool alt_mha_profiles_only; + + /*! max number of valid chunks in smooth manifest*/ + u32 smooth_max_chunks; + + /*! INTRA-ONLY trick mode*/ + Bool intra_only; + /*! adaptation set uses HLS LL*/ + Bool use_hls_ll; + /*target fragment duration*/ + Double hls_ll_target_frag_dur; } GF_MPD_AdaptationSet; /*! MPD offering type*/ @@ -688,6 +751,9 @@ typedef enum { /*! Period*/ typedef struct { + /*! inherits from extensible*/ + MPD_EXTENSIBLE + /*! ID of period*/ char *ID; /*! start time in milliseconds, relative to the start of the MPD */ @@ -714,17 +780,26 @@ typedef struct /*! xlink evaluation on load if set, otherwise on use*/ Bool xlink_actuate_on_load; - /*! other descriptors*/ - GF_List *other_descriptors; - /*! original xlink URL before resolution, used to identify already resolved xlinks in MPD updates - GPAC internal*/ + /*! original xlink URL before resolution - GPAC internal. Used to + - identify already resolved xlinks in MPD updates + - resolve URLs in remote period if no baseURL is explictly listed + */ char *origin_base_url; + /*! broken/ignored xlink, used to identify ignored xlinks in MPD updates - GPAC internal*/ + char *broken_xlink; /*! type of the period - GPAC internal*/ GF_MPD_Type type; + + /*! period is preroll - test only, GPAC internal*/ + Bool is_preroll; } GF_MPD_Period; /*! Program info*/ typedef struct { + /*! inherits from extensible*/ + MPD_EXTENSIBLE + /*! languae*/ char *lang; /*! title*/ @@ -783,10 +858,15 @@ typedef struct { /*! set during parsing, to set during authoring, won't be freed by GPAC*/ const char *xml_namespace; - /*! UTC timing desc if any/*/ + /*! UTC timing desc if any */ GF_List *utc_timings; + /*! Essential properties */ + GF_List *essential_properties; + /*! Supplemental properties */ + GF_List *supplemental_properties; /* internal variables for dasher*/ + Bool inject_service_desc; /*! dasher init NTP clock in ms - GPAC internal*/ u64 gpac_init_ntp_ms; @@ -803,6 +883,15 @@ typedef struct { Bool create_m3u8_files; /*! indicates to insert clock reference in variant playlists*/ Bool m3u8_time; + /*! indicates LL-HLS forced generation. 0: regular write, 1: write as byterange, 2: write as independent files*/ + u32 force_llhls_mode; + /*! HLS extensions to append in the master playlist*/ + u32 nb_hls_ext_master; + const char **hls_ext_master; + /*! if true inject EXT-X-PRELOAD-HINT*/ + Bool llhls_preload; + /*! if true inject EXT-X-RENDITION-REPORT*/ + Bool llhls_rendition_reports; } GF_MPD; /*! parses an MPD Element (and subtree) from DOM @@ -927,7 +1016,7 @@ struct _gf_file_get \param reload_count number of times the manifest was reloaded \param mimeTypeForM3U8Segments default mime type for the segments in case not found in the m3u8 \param do_import if GF_TRUE, will try to load the media segments to extract more info -\param use_mpd_templates if GF_TRUE, will use MPD SegmentTemplate instead of SegmentList +\param use_mpd_templates if GF_TRUE, will use MPD SegmentTemplate instead of SegmentList (only if parse_sub_playlist is GF_TRUE) \param use_segment_timeline if GF_TRUE, uses SegmentTimeline to describe the varying duration of segments \param getter HTTP interface object \param mpd MPD structure to fill, or NULL if converting to file @@ -939,12 +1028,14 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, const char *m /*! solves an m3u8 xlink on a representation, and fills the SegmentList accordingly \param rep the target representation +\param base_url base URL of master manifest (representation xlink is likely relative to this URL) \param getter HTTP interface object \param is_static set to GF_TRUE if the variant subplaylist is on demand \param duration set to the duration of the parsed subplaylist -\return error if any +\param signature SHA1 digest of last solved version, updated if changed +\return error if any, GF_EOS if no changes */ -GF_Err gf_m3u8_solve_representation_xlink(GF_MPD_Representation *rep, GF_FileDownload *getter, Bool *is_static, u64 *duration); +GF_Err gf_m3u8_solve_representation_xlink(GF_MPD_Representation *rep, const char *base_url, GF_FileDownload *getter, Bool *is_static, u64 *duration, u8 signature[GF_SHA1_DIGEST_SIZE]); /*! creates a segment list from a remote segment list DOM root \param mpd the target MPD to write @@ -965,7 +1056,7 @@ GF_Err gf_mpd_init_smooth_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *de \param segment_list the segment list to delete*/ void gf_mpd_delete_segment_list(GF_MPD_SegmentList *segment_list); -/*! deletes a list content and optionaly destructs the list +/*! deletes a list content and optionally destructs the list \param list the target list \param __destructor the destructor function to use to destroy list items \param reset_only if GF_TRUE, does not destroy the target list @@ -1012,6 +1103,8 @@ typedef enum GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE, /*! same as GF_MPD_RESOLVE_URL_MEDIA but does not use startNumber*/ GF_MPD_RESOLVE_URL_MEDIA_NOSTART, + /*! same as GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE but ignores base URL*/ + GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE_NO_BASE, } GF_MPD_URLResolveType; /*! resolves a URL based for a given segment, based on the MPD url, the type of resolution @@ -1031,10 +1124,12 @@ typedef enum \param is_in_base_url set to GF_TRUE if the resuloved URL is a sub-part of the baseURL (optional, may be NULL) \param out_key_url set to the key URL for the segment for HLS (optional, may be NULL) \param key_iv set to the key IV for the segment for HLS (optional, may be NULL) +\param out_start_number set to the start_number used (optional, may be NULL) + \return error if any */ GF_Err gf_mpd_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set, GF_MPD_Period *period, const char *mpd_url, u32 base_url_index, GF_MPD_URLResolveType resolve_type, u32 item_index, u32 nb_segments_removed, - char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url, char **out_key_url, bin128 *key_iv); + char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url, char **out_key_url, bin128 *key_iv, u32 *out_start_number); /*! get duration of the presentation \param mpd the target MPD @@ -1123,12 +1218,19 @@ typedef struct \param stream_id the ID of the stream for which we load cues (typically, TrackID or GF_PROP_PID_ID) \param cues_timescale set to the timescale used in the cues document \param use_edit_list set to GF_TRUE if the cts values of cues have edit list applied (i.e. are ISOBMFF presentation times) +\param ts_offset set to the timestamp offset to subtract from DTS/CTS values \param out_cues set to a newly allocated list of cues, to free by the caller \param nb_cues set to the number of cues parsed \return error if any */ -GF_Err gf_mpd_load_cues(const char *cues_file, u32 stream_id, u32 *cues_timescale, Bool *use_edit_list, GF_DASHCueInfo **out_cues, u32 *nb_cues); +GF_Err gf_mpd_load_cues(const char *cues_file, u32 stream_id, u32 *cues_timescale, Bool *use_edit_list, s32 *ts_offset, GF_DASHCueInfo **out_cues, u32 *nb_cues); +/*! gets first MPD descriptor from descriptor list for a given scheme_id +\param desclist list of MPD Descriptors +\param scheme_id scheme ID to look for +\return descriptor if found, NUL otherwise +*/ +GF_MPD_Descriptor *gf_mpd_get_descriptor(GF_List *desclist, char *scheme_id); /*! @} */ #endif /*GPAC_DISABLE_CORE_TOOLS*/ diff --git a/include/gpac/mpeg4_odf.h b/include/gpac/mpeg4_odf.h index f652e24..955eee1 100644 --- a/include/gpac/mpeg4_odf.h +++ b/include/gpac/mpeg4_odf.h @@ -155,7 +155,7 @@ typedef struct /*! default descriptor. - NOTE: The decoderSpecificInfo is used as a default desc with tag 0x05 */ + \note The decoderSpecificInfo is used as a default desc with tag 0x05 */ typedef struct { BASE_DESCRIPTOR @@ -183,7 +183,7 @@ typedef struct GF_List *extensionDescriptors; /*MPEG-2 (or other service mux formats) service ID*/ u32 ServiceID; - /*for ATSC, instructs client to keep OD alive even though URL string is set*/ + /*for ROUTE, instructs client to keep OD alive even though URL string is set*/ Bool RedirectOnly; /*set to true for fake remote ODs in BT/XMT (remote ODs created for OD with ESD with MuxInfo)*/ Bool fake_remote; @@ -205,7 +205,7 @@ typedef struct GF_List *extensionDescriptors; /*MPEG-2 (or other service mux formats) service ID*/ u16 ServiceID; - /*for ATSC, instructs client to keep OD alive even though URL string is set*/ + /*for ROUTE, instructs client to keep OD alive even though URL string is set*/ Bool RedirectOnly; /*set to true for fake remote ODs in BT/XMT (remote ODs created for OD with ESD with MuxInfo)*/ Bool fake_remote; @@ -235,7 +235,7 @@ typedef struct /*MPEG-2 (or other service mux formats) service ID*/ u32 ServiceID; - /*for ATSC, instructs client to keep OD alive even though URL string is set*/ + /*for ROUTE, instructs client to keep OD alive even though URL string is set*/ Bool RedirectOnly; /*set to true for fake remote ODs in BT/XMT (remote ODs created for OD with ESD with MuxInfo)*/ Bool fake_remote; @@ -425,10 +425,16 @@ typedef struct __tag_bifs_config /*! flags for text style*/ enum { + /*! normal*/ GF_TXT_STYLE_NORMAL = 0, + /*! bold*/ GF_TXT_STYLE_BOLD = 1, - GF_TXT_STYLE_ITALIC = 2, - GF_TXT_STYLE_UNDERLINED = 4 + /*! italic*/ + GF_TXT_STYLE_ITALIC = 1<<1, + /*! underlined*/ + GF_TXT_STYLE_UNDERLINED = 1<<2, + /*! strikethrough - not 3GPP/QT defined, GPAC only*/ + GF_TXT_STYLE_STRIKETHROUGH = 1<<3, }; /*! text style record*/ @@ -849,7 +855,7 @@ typedef struct { } GF_ContentCreatorInfo; /*! Content Creator Name GF_Descriptor -NOTE: the desctructor will delete all the items in the list +\note The desctructor will delete all the items in the list (GF_ContentCreatorInfo items) */ typedef struct { BASE_DESCRIPTOR @@ -915,15 +921,21 @@ typedef struct { u8 profileLevelIndicationIndex; } GF_PL_IDX; -/*! used for storing AVC sequenceParameterSetNALUnit and pictureParameterSetNALUnit*/ +/*! used for storing NALU-based parameter set in AVC/HEVC/VVC configuration record*/ typedef struct { + /*! size of nal*/ u16 size; + /*! nal data*/ u8 *data; - /* used of AVC/SVC detection */ + /*! ID of param set, used by some importers but not written in file*/ s32 id; + /*! CRC of nal, used by some importers but not written in file*/ u32 crc; -} GF_AVCConfigSlot; +} GF_NALUFFParam; + +/*! pre v1.1 naming of NALU config record*/ +typedef GF_NALUFFParam GF_AVCConfigSlot; /*! AVC config record - not a real MPEG-4 descriptor */ @@ -959,7 +971,10 @@ typedef struct u8 type; u8 array_completeness; GF_List *nalus; -} GF_HEVCParamArray; +} GF_NALUFFParamArray; + +/*! pre v1.1 naming of NALU param array*/ +typedef GF_NALUFFParamArray GF_HEVCParamArray; /*! HEVC config record - not a real MPEG-4 descriptor*/ typedef struct @@ -1002,6 +1017,41 @@ typedef struct } GF_HEVCConfig; + + +/*! VVC config record - not a real MPEG-4 descriptor*/ +typedef struct +{ + u8 general_profile_idc; + u8 general_tier_flag; + u8 general_sub_profile_idc; + u8 num_constraint_info; + u8 *general_constraint_info; + u8 general_level_idc; + + u8 ptl_sublayer_present_mask; + u8 sublayer_level_idc[8]; + + u8 chroma_format; + u8 bit_depth; + u16 avgFrameRate; + u8 constantFrameRate; + u8 numTemporalLayers; + u16 maxPictureWidth, maxPictureHeight; + + Bool ptl_present, ptl_frame_only_constraint, ptl_multilayer_enabled; + u8 num_sub_profiles; + u32 *sub_profiles_idc; + + u16 ols_idx; + u8 nal_unit_size; + + GF_List *param_array; + + Bool write_annex_b; +} GF_VVCConfig; + + /*! used for storing AV1 OBUs*/ typedef struct { @@ -1056,7 +1106,7 @@ typedef struct int RefFrameHeight[VP9_NUM_REF_FRAMES]; } GF_VPConfig; -/*! DolbyVision config dvcC */ +/*! DolbyVision config dvcC/dvvC */ typedef struct { u8 dv_version_major; u8 dv_version_minor; @@ -1065,7 +1115,12 @@ typedef struct { Bool rpu_present_flag; Bool el_present_flag; Bool bl_present_flag; - //const unsigned int (32)[5] reserved = 0; + u8 dv_bl_signal_compatibility_id; //4 bits + //const unsigned int (28) reserved = 0; + //const unsigned int (32)[4] reserved = 0; + + //internal, force dvhe or dvh1 signaling + u8 force_dv; } GF_DOVIDecoderConfigurationRecord; /*! Media Segment Descriptor used for Media Control Extensions*/ @@ -1284,7 +1339,7 @@ GF_BIFSConfig *gf_odf_get_bifs_config(GF_DefaultDescriptor *dsi, u32 codecid); \return error if any */ GF_Err gf_odf_get_laser_config(GF_DefaultDescriptor *dsi, GF_LASERConfig *cfg); -/*! sepcial function for authoring - convert DSI to TextConfig +/*! special function for authoring - convert DSI to TextConfig \param data TEXT decoder config block \param data_len TEXT decoder config block size \param codecid TEXT codecid/object type indication @@ -1380,6 +1435,42 @@ GF_HEVCConfig *gf_odf_hevc_cfg_read_bs(GF_BitStream *bs, Bool is_lhvc); GF_HEVCConfig *gf_odf_hevc_cfg_read(u8 *dsi, u32 dsi_size, Bool is_lhvc); +/*! VVC config constructor +\return the created VVC config*/ +GF_VVCConfig *gf_odf_vvc_cfg_new(); + +/*! VVC config destructor +\param cfg the VVC config to destroy*/ +void gf_odf_vvc_cfg_del(GF_VVCConfig *cfg); + +/*! writes GF_VVCConfig as MPEG-4 DSI in a bitstream object +\param cfg the VVC config to encode +\param bs output bitstream object in which the config is written +\return error if any + */ +GF_Err gf_odf_vvc_cfg_write_bs(GF_VVCConfig *cfg, GF_BitStream *bs); + +/*! writes GF_VVCConfig as MPEG-4 DSI +\param cfg the VVC config to encode +\param outData encoded dsi buffer - it is the caller responsability to free this +\param outSize encoded dsi buffer size +\return error if any + */ +GF_Err gf_odf_vvc_cfg_write(GF_VVCConfig *cfg, u8 **outData, u32 *outSize); + +/*! gets GF_VVCConfig from bitstream MPEG-4 DSI +\param bs bitstream containing the encoded VVC decoder specific info +\return the decoded VVC config + */ +GF_VVCConfig *gf_odf_vvc_cfg_read_bs(GF_BitStream *bs); + +/*! gets GF_VVCConfig from MPEG-4 DSI +\param dsi encoded VVC decoder specific info +\param dsi_size encoded VVC decoder specific info size +\return the decoded VVC config + */ +GF_VVCConfig *gf_odf_vvc_cfg_read(u8 *dsi, u32 dsi_size); + /*! AV1 config constructor \return the created AV1 config*/ GF_AV1Config *gf_odf_av1_cfg_new(); @@ -1474,6 +1565,87 @@ GF_Err gf_odf_dovi_cfg_write_bs(GF_DOVIDecoderConfigurationRecord *cfg, GF_BitSt \param cfg the DolbyVision config to destroy*/ void gf_odf_dovi_cfg_del(GF_DOVIDecoderConfigurationRecord *cfg); + +/*! AC-3 config record extension for EAC-3 - see dolby specs*/ +typedef struct __ec3_stream +{ + /*! AC3 fs code*/ + u8 fscod; + /*! AC3 bsid code*/ + u8 bsid; + /*! AC3 bs mode*/ + u8 bsmod; + /*! AC3 ac mode*/ + u8 acmod; + /*! LF on*/ + u8 lfon; + /*! asvc mode, only for EC3*/ + u8 asvc; + /*! deps, only for EC3*/ + u8 nb_dep_sub; + /*! channel loc, only for EC3*/ + u8 chan_loc; +} GF_AC3StreamInfo; + +/*! AC3 config record*/ +typedef struct __ac3_config +{ + /*! indicates if ec3*/ + u8 is_ec3; + /*! if AC3 this is the bitrate code, otherwise cumulated data rate of EC3 streams*/ + u16 brcode; + /*! number of streams : + 1 for AC3 + max 8 for EC3, main stream is included + */ + u8 nb_streams; + /*! streams info*/ + GF_AC3StreamInfo streams[8]; + + //! \cond used in parsing not part of the AC3 config record + u32 bitrate; + u32 sample_rate; + u32 framesize; + u32 channels; + u16 substreams; //bit-mask, used for channel map > 5.1 + + //! \endcond private + +} GF_AC3Config; + + +/*! writes Dolby AC3/EAC3 config to buffer +\param cfg the Dolby AC3 config to write +\param bs the bitstream object in which to write the config +\return error if any +*/ +GF_Err gf_odf_ac3_cfg_write_bs(GF_AC3Config *cfg, GF_BitStream *bs); +/*! writes Dolby AC3/EAC3 config to buffer +\param cfg the Dolby AC3 config to write +\param data set to created output buffer, must be freed by caller +\param size set to created output buffer size +\return error if any +*/ +GF_Err gf_odf_ac3_cfg_write(GF_AC3Config *cfg, u8 **data, u32 *size); + + +/*! parses an AC3/EC3 sample description +\param dsi the encoded config +\param dsi_len the encoded config size +\param is_ec3 indicates that the encoded config is for an EC3 track +\param cfg the AC3/EC3 config to fill +\return Error if any +*/ +GF_Err gf_odf_ac3_config_parse(u8 *dsi, u32 dsi_len, Bool is_ec3, GF_AC3Config *cfg); + +/*! parses an AC3/EC3 sample description from bitstream +\param bs the bitstream object +\param is_ec3 indicates that the encoded config is for an EC3 track +\param cfg the AC3/EC3 config to fill +\return Error if any +*/ +GF_Err gf_odf_ac3_config_parse_bs(GF_BitStream *bs, Bool is_ec3, GF_AC3Config *cfg); + /*! destroy the descriptors in a list but not the list \param descList descriptor list to destroy \return error if any diff --git a/include/gpac/mpegts.h b/include/gpac/mpegts.h index a736725..9a5fa37 100644 --- a/include/gpac/mpegts.h +++ b/include/gpac/mpegts.h @@ -97,6 +97,8 @@ enum /* ... */ GF_M2TS_MPEG4_ODUPDATE_DESCRIPTOR = 0x35, + GF_M2TS_HEVC_VIDEO_DESCRIPTOR = 0x38, + /* 0x2D - 0x3F - ISO/IEC 13818-6 values */ /* 0x40 - 0xFF - User Private values */ GF_M2TS_DVB_NETWORK_NAME_DESCRIPTOR = 0x40, @@ -137,6 +139,8 @@ enum /* ... */ GF_M2TS_DVB_EAC3_DESCRIPTOR = 0x7A, GF_M2TS_DVB_LOGICAL_CHANNEL_DESCRIPTOR = 0x83, + + GF_M2TS_DOLBY_VISION_DESCRIPTOR = 0xB0 }; /*! Reserved PID values */ @@ -215,62 +219,81 @@ enum { /*! MPEG-2 TS Media types*/ typedef enum { - GF_M2TS_VIDEO_MPEG1 = 0x01, - GF_M2TS_VIDEO_MPEG2 = 0x02, - GF_M2TS_AUDIO_MPEG1 = 0x03, - GF_M2TS_AUDIO_MPEG2 = 0x04, - GF_M2TS_PRIVATE_SECTION = 0x05, - GF_M2TS_PRIVATE_DATA = 0x06, - GF_M2TS_MHEG = 0x07, - GF_M2TS_13818_1_DSMCC = 0x08, - GF_M2TS_H222_1 = 0x09, - GF_M2TS_13818_6_ANNEX_A = 0x0A, - GF_M2TS_13818_6_ANNEX_B = 0x0B, - GF_M2TS_13818_6_ANNEX_C = 0x0C, - GF_M2TS_13818_6_ANNEX_D = 0x0D, - GF_M2TS_13818_1_AUXILIARY = 0x0E, - GF_M2TS_AUDIO_AAC = 0x0F, - GF_M2TS_VIDEO_MPEG4 = 0x10, - GF_M2TS_AUDIO_LATM_AAC = 0x11, - - GF_M2TS_SYSTEMS_MPEG4_PES = 0x12, - GF_M2TS_SYSTEMS_MPEG4_SECTIONS = 0x13, - - GF_M2TS_METADATA_PES = 0x15, - - GF_M2TS_VIDEO_H264 = 0x1B, - GF_M2TS_VIDEO_SVC = 0x1F, - GF_M2TS_VIDEO_HEVC = 0x24, - GF_M2TS_VIDEO_HEVC_TEMPORAL = 0x25, - GF_M2TS_VIDEO_MVCD = 0x26, - GF_M2TS_TEMI = 0x27, - GF_M2TS_VIDEO_SHVC = 0x28, - GF_M2TS_VIDEO_SHVC_TEMPORAL = 0x29, - GF_M2TS_VIDEO_MHVC = 0x2A, - GF_M2TS_VIDEO_MHVC_TEMPORAL = 0x2B, - - GF_M2TS_GREEN = 0x2C, - GF_M2TS_MHAS_MAIN = 0x2D, - GF_M2TS_MHAS_AUX = 0x2E, - - GF_M2TS_QUALITY_SEC = 0x2F, - GF_M2TS_MORE_SEC = 0x30, - - GF_M2TS_VIDEO_HEVC_MCTS = 0x31, - + GF_M2TS_VIDEO_MPEG1 = 0x01, + GF_M2TS_VIDEO_MPEG2 = 0x02, + GF_M2TS_AUDIO_MPEG1 = 0x03, + GF_M2TS_AUDIO_MPEG2 = 0x04, + GF_M2TS_PRIVATE_SECTION = 0x05, + GF_M2TS_PRIVATE_DATA = 0x06, + GF_M2TS_MHEG = 0x07, + GF_M2TS_13818_1_DSMCC = 0x08, + GF_M2TS_H222_1 = 0x09, + GF_M2TS_13818_6_ANNEX_A = 0x0A, + GF_M2TS_13818_6_ANNEX_B = 0x0B, + GF_M2TS_13818_6_ANNEX_C = 0x0C, + GF_M2TS_13818_6_ANNEX_D = 0x0D, + GF_M2TS_13818_1_AUXILIARY = 0x0E, + GF_M2TS_AUDIO_AAC = 0x0F, + GF_M2TS_VIDEO_MPEG4 = 0x10, + GF_M2TS_AUDIO_LATM_AAC = 0x11, + GF_M2TS_SYSTEMS_MPEG4_PES = 0x12, + GF_M2TS_SYSTEMS_MPEG4_SECTIONS = 0x13, + GF_M2TS_SYNC_DOWNLOAD_PROTOCOL = 0x14, + GF_M2TS_METADATA_PES = 0x15, + GF_M2TS_METADATA_SECTION = 0x16, + GF_M2TS_METADATA_DATA_CAROUSEL = 0x17, + GF_M2TS_METADATA_OBJECT_CAROUSEL = 0x18, + GF_M2TS_METADATA_SYNC_DOWNLOAD_PROTOCOL = 0x19, + GF_M2TS_IPMP = 0x1A, + GF_M2TS_VIDEO_H264 = 0x1B, + GF_M2TS_MPEG4_AUDIO_NO_SYNTAX = 0x1C, + GF_M2TS_MPEG4_TEXT = 0x1D, + GF_M2TS_AUX_VIDEO_23002_2 = 0x1E, + GF_M2TS_VIDEO_SVC = 0x1F, + GF_M2TS_VIDEO_MVC = 0x20, + GF_M2TS_VIDEO_15444_1 = 0x21, + GF_M2TS_VIDEO_MPEG2_ADD_STEREO = 0x22, + GF_M2TS_VIDEO_H264_ADD_STEREO = 0x23, + GF_M2TS_VIDEO_HEVC = 0x24, + GF_M2TS_VIDEO_HEVC_TEMPORAL = 0x25, + GF_M2TS_VIDEO_MVCD = 0x26, + GF_M2TS_TEMI = 0x27, + GF_M2TS_VIDEO_SHVC = 0x28, + GF_M2TS_VIDEO_SHVC_TEMPORAL = 0x29, + GF_M2TS_VIDEO_MHVC = 0x2A, + GF_M2TS_VIDEO_MHVC_TEMPORAL = 0x2B, + GF_M2TS_GREEN = 0x2C, + GF_M2TS_MHAS_MAIN = 0x2D, + GF_M2TS_MHAS_AUX = 0x2E, + GF_M2TS_QUALITY_SEC = 0x2F, + GF_M2TS_MORE_SEC = 0x30, + GF_M2TS_VIDEO_HEVC_MCTS = 0x31, + GF_M2TS_JPEG_XS = 0x32, + GF_M2TS_VIDEO_VVC = 0x33, + GF_M2TS_VIDEO_VVC_TEMPORAL = 0x34, + + GF_M2TS_HLS_AC3_CRYPT = 0xc1, + GF_M2TS_HLS_EC3_CRYPT = 0xc2, + GF_M2TS_HLS_AAC_CRYPT = 0xcf, + GF_M2TS_HLS_AVC_CRYPT = 0xdb, + + /*the rest is internal use*/ + + GF_M2TS_VIDEO_VC1 = 0xEA, GF_M2TS_VIDEO_DCII = 0x80, GF_M2TS_AUDIO_AC3 = 0x81, - GF_M2TS_AUDIO_DTS = 0x8A, + GF_M2TS_AUDIO_DTS = 0x82, + GF_M2TS_AUDIO_TRUEHD = 0x83, + GF_M2TS_AUDIO_EC3 = 0x84, GF_M2TS_MPE_SECTIONS = 0x90, GF_M2TS_SUBTITLE_DVB = 0x100, - - /*internal use*/ - GF_M2TS_AUDIO_EC3 = 0x150, - GF_M2TS_VIDEO_VC1 = 0x151, + GF_M2TS_AUDIO_OPUS = 0x101, + GF_M2TS_DVB_TELETEXT = 0x152, GF_M2TS_DVB_VBI = 0x153, GF_M2TS_DVB_SUBTITLE = 0x154, GF_M2TS_METADATA_ID3_HLS = 0x155, + } GF_M2TSStreamType; @@ -278,7 +301,15 @@ typedef enum enum { GF_M2TS_RA_STREAM_AC3 = GF_4CC('A','C','-','3'), + GF_M2TS_RA_STREAM_EAC3 = GF_4CC('E','A','C','3'), GF_M2TS_RA_STREAM_VC1 = GF_4CC('V','C','-','1'), + GF_M2TS_RA_STREAM_HEVC = GF_4CC('H','E','V','C'), + GF_M2TS_RA_STREAM_DTS1 = GF_4CC('D','T','S','1'), + GF_M2TS_RA_STREAM_DTS2 = GF_4CC('D','T','S','2'), + GF_M2TS_RA_STREAM_DTS3 = GF_4CC('D','T','S','3'), + GF_M2TS_RA_STREAM_OPUS = GF_4CC('O','p','u','s'), + GF_M2TS_RA_STREAM_DOVI = GF_4CC('D','O','V','I'), + GF_M2TS_RA_STREAM_GPAC = GF_4CC('G','P','A','C') }; @@ -462,7 +493,9 @@ enum /*! a TEMI locator has been found or repeated*/ GF_M2TS_EVT_TEMI_LOCATION, /*! a TEMI timecode has been found*/ - GF_M2TS_EVT_TEMI_TIMECODE + GF_M2TS_EVT_TEMI_TIMECODE, + /*! a stream is about to be removed - - associated parameter: pointer to GF_M2TS_ES being removed*/ + GF_M2TS_EVT_STREAM_REMOVED }; /*! table parsing state*/ @@ -592,7 +625,7 @@ typedef struct const char *external_URL; Bool is_announce, is_splicing; Bool reload_external; - Double activation_countdown; + GF_Fraction activation_countdown; } GF_M2TS_TemiLocationDescriptor; /*! MPEG-2 TS demuxer TEMI timecode*/ @@ -687,7 +720,9 @@ enum /*! flag used to signal next discontinuity on stream should be ignored*/ GF_M2TS_ES_IGNORE_NEXT_DISCONTINUITY = 1<<17, /*! flag used by importers/readers to mark streams that have been seen already in PMT process (update/found)*/ - GF_M2TS_ES_ALREADY_DECLARED = 1<<18 + GF_M2TS_ES_ALREADY_DECLARED = 1<<18, + /*! flag indicates TEMI info is declared on this stream*/ + GF_M2TS_ES_TEMI_INFO = 1<<19 }; /*! macro for abstract Section/PES stream object, only used for type casting*/ @@ -702,6 +737,7 @@ enum void *user; \ GF_List *props; \ u64 first_dts; \ + Bool is_seg_start; \ u32 service_id; /*! abstract Section/PES stream object*/ @@ -822,7 +858,7 @@ typedef struct tag_m2ts_pes /*! PES reframer callback. If NULL, pes processing is skiped - returns the number of bytes NOT consummed from the input data buffer - these bytes are kept when reassembling the next PES packet*/ + returns the number of bytes NOT consumed from the input data buffer - these bytes are kept when reassembling the next PES packet*/ u32 (*reframe)(struct tag_m2ts_demux *ts, struct tag_m2ts_pes *pes, Bool same_pts, u8 *data, u32 data_len, GF_M2TS_PESHeader *hdr); /*! DVB subtitling info*/ @@ -841,6 +877,10 @@ typedef struct tag_m2ts_pes GF_M2TS_TemiTimecodeDescriptor temi_tc; /*! flag set to indicate a TEMI descriptor should be flushed with next packet*/ Bool temi_pending; + /*! flag set to indicate the last PES packet was not flushed (HLS) to avoid warning on same PTS/DTS used*/ + Bool is_resume; + /*! DolbiVison info, last byte set to 1 if non-compatible signaling*/ + u8 dv_info[25]; } GF_M2TS_PES; /*! reserved streamID for PES headers*/ @@ -1114,6 +1154,12 @@ void gf_m2ts_demux_del(GF_M2TS_Demuxer *demux); \param demux the target MPEG-2 TS demultiplexer */ void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *demux); + +/*! set all streams is_seg_start variable to GF_TRUE +\param demux the target MPEG-2 TS demultiplexer +*/ +void gf_m2ts_mark_seg_start(GF_M2TS_Demuxer *demux); + /*! resets all parsers (PES, sections) of a given program \param demux the target MPEG-2 TS demultiplexer \param program the target MPEG-2 TS program @@ -1149,13 +1195,15 @@ GF_M2TS_SDT *gf_m2ts_get_sdt_info(GF_M2TS_Demuxer *demux, u32 program_id); /*! flushes a given stream. This is used to flush internal demultiplexer buffers on end of stream \param demux the target MPEG-2 demultiplexer \param pes the target stream to flush +\param force_flush if GF_TRUE, flushes all streams, otherwise do not flush stream with known PES length and not yet completed (for HLS) */ -void gf_m2ts_flush_pes(GF_M2TS_Demuxer *demux, GF_M2TS_PES *pes); +void gf_m2ts_flush_pes(GF_M2TS_Demuxer *demux, GF_M2TS_PES *pes, Bool force_flush); /*! flushes all streams in the mux. This is used to flush internal demultiplexer buffers on end of stream \param demux the target MPEG-2 demultiplexer +\param no_force_flush do not force a flush of incomplete PES (used for HLS) */ -void gf_m2ts_flush_all(GF_M2TS_Demuxer *demux); +void gf_m2ts_flush_all(GF_M2TS_Demuxer *demux, Bool no_force_flush); /*! MPEG-2 TS packet header*/ @@ -1233,7 +1281,7 @@ typedef struct \brief Basic stream interface API used by MPEG-2 TS muxer. This section documents the ES interface used by the MPEG-2 TS muxer. This interface is used to -describe streams and packets consummed by the TS muxer independently from the rest of GPAC (filter packets) +describe streams and packets consumed by the TS muxer independently from the rest of GPAC (filter packets) @{ */ @@ -1343,6 +1391,12 @@ enum GF_ESI_STREAM_WITHOUT_MPEG4_SYSTEMS = 1<<3, /*! stream is not signaled through MPEG-4 Systems (OD stream) */ GF_ESI_AAC_USE_LATM = 1<<4, + /*! temporrary end of stream (flush of segment)*/ + GF_ESI_STREAM_FLUSH = 1<<5, + /*! stream uses HLS SAES encryption*/ + GF_ESI_STREAM_HLS_SAES = 1<<6, + /*! stream uses non-backward DolbyVision signaling*/ + GF_ESI_FORCE_DOLBY_VISION = 1<<7, }; /*! elementary stream information*/ @@ -1385,6 +1439,11 @@ typedef struct __elementary_stream_ifce void *output_udta; /*! stream dependency ID*/ u32 depends_on_stream; + + /*! dv info, not valid if first byte not 1*/ + u8 dv_info[24]; + + u32 ra_code; } GF_ESInterface; /*! @} */ @@ -1487,8 +1546,6 @@ typedef struct __m2ts_mux_stream { Bool pcr_only_mode; /*! tables for section PIDs*/ GF_M2TS_Mux_Table *tables; - /*! init verision of table*/ - u8 initial_version_number; /*! total table sizes for bitrate estimation (PMT/PAT/...)*/ u32 total_table_size; /*! current table - used for on-the-fly packetization of sections */ @@ -1499,6 +1556,10 @@ typedef struct __m2ts_mux_stream { u32 current_section_offset; /*! carousel rate in ms*/ u32 refresh_rate_ms; + /*! init verision of table*/ + u8 initial_version_number; + /*! PES version of transport for this codec type is forced*/ + u8 force_pes; /*! table needs updating*/ Bool table_needs_update; /*! table needs send*/ @@ -1532,8 +1593,10 @@ typedef struct __m2ts_mux_stream { u32 next_payload_size; /*! number of bytes to copy from next packet*/ u32 copy_from_next_packets; - /*! size of nex next payload, 0 if unknown*/ + /*! size of next next payload, 0 if unknown*/ u32 next_next_payload_size; + /*! size of next next next payload, 0 if unknown*/ + u32 next_next_next_payload_size; /*! size of packetized packet*/ u32 pes_data_len; /*! remaining bytes to send as TS packets*/ @@ -1590,6 +1653,9 @@ typedef struct __m2ts_mux_stream { u32 pck_sap_type; /*! packet SAP time (=PTS) when segmenting the TS*/ u64 pck_sap_time; + + /*! last process result*/ + u32 process_res; } GF_M2TS_Mux_Stream; /*! MPEG-4 systems signaling mode*/ @@ -1598,7 +1664,7 @@ enum { GF_M2TS_MPEG4_SIGNALING_NONE = 0, /*! Full MPEG-4 signaling*/ GF_M2TS_MPEG4_SIGNALING_FULL, - /*MPEG-4 over MPEG-2 profile where PES media streams may be refered to by the scene without SL-packetization*/ + /*MPEG-4 over MPEG-2 profile where PES media streams may be referred to by the scene without SL-packetization*/ GF_M2TS_MPEG4_SIGNALING_SCENE }; @@ -1749,7 +1815,9 @@ struct __m2ts_mux { /*! static write bitstream object for formatting packets*/ GF_BitStream *pck_bs; - /*set to TRUE if the packet output is the first packet of a SAP AU (used when dashing)*/ + /*! PID to watch for SAP insertions*/ + u32 ref_pid; + /* if the packet output starts (first PES) with the first packet of a SAP AU (used when dashing), set to TRUE*/ Bool sap_inserted; /*! SAP time (used when dashing)*/ u64 sap_time; @@ -1860,7 +1928,7 @@ typedef enum \return packet produced or NULL if error or idle */ const u8 *gf_m2ts_mux_process(GF_M2TS_Mux *muxer, GF_M2TSMuxState *status, u32 *usec_till_next); -/*! gets the system clock of the multiplexer (time ellapsed since start) +/*! gets the system clock of the multiplexer (time elapsed since start) \param muxer the target MPEG-2 TS multiplexer \return system clock of the multiplexer in milliseconds */ diff --git a/include/gpac/network.h b/include/gpac/network.h index 77f7cd2..edcc36b 100644 --- a/include/gpac/network.h +++ b/include/gpac/network.h @@ -113,6 +113,16 @@ Encodes URL by replacing special characters with their % encodings. */ char *gf_url_percent_encode(const char *path); +/*! +\brief URL decoding + +Decodes URL by % encodings with the special characters they correspond to +\param path encoded URL of the service +\return decoded path name , or NULL if error + \note the returned string must be freed by user + */ +char *gf_url_percent_decode(const char *path); + /*! \brief URL to file system @@ -124,12 +134,16 @@ void gf_url_to_fs_path(char *url); /*! \brief get first after a filename/path -Returns a pointer to the first colon at the end of a filename or URL, if any +Returns a pointer to the first colon at the end of a filename or URL, if any. + +If assign_sep is specified, for example '=', the function will make sure that the colon is after the file extension if found and that '=' is not present between colon and file ext. +This is used to parse 'a:b.mp4:c' (expected result ':c...' and not ':b...') vs 'a:b=c.mp4' ' (expected result ':b') + \param URL path or URL to inspect +\param assign_sep value of assignment operand character. If 0, only checks for colon, otherwise chec that no assign sep or colon is present before file extension, if present \return position of first colon, or NULL */ -char* gf_url_colon_suffix(const char* URL); - +char* gf_url_colon_suffix(const char* URL, char assign_sep); /*! \brief Extract resource name from URL @@ -141,14 +155,13 @@ Extracts the resource name from the URL const char *gf_url_get_resource_name(const char *url); /*! -\brief Extract resource path from URL +\brief Gets resource path from URL -Extracts the reource path from the URL +Gets the resource path and name from the URL, stripping scheme, server ID, port... \param url input url -\param res_path buffer for resulting path storage -\return 1 if path was extracted, 0 if url is a single file name. +\return the extracted path, or the original path if no scheme indication, or NULL of no path */ -Bool gf_url_get_resource_path(const char *url, char *res_path); +const char *gf_url_get_path(const char *url); /*! @} */ @@ -594,6 +607,26 @@ Checks if connection has been closed by remote peer */ GF_Err gf_sk_probe(GF_Socket *sock); + +/*! socket selection mode*/ +typedef enum +{ + /*! select for both read and write operations */ + GF_SK_SELECT_BOTH=0, + /*! select for both read operations */ + GF_SK_SELECT_READ, + /*! select for both write operations */ + GF_SK_SELECT_WRITE, +} GF_SockSelectMode; + +/*! +Checks if socket can is ready for read or write +\param sock the socket object +\param mode the operation mode desired +\return GF_OK if ready, GF_IP_SOCK_WOULD_BLOCK if not ready, otherwise error if any (GF_IP_CONNECTION_CLOSED if connection is closed) + */ +GF_Err gf_sk_select(GF_Socket *sock, GF_SockSelectMode mode); + /*! @} */ /*! @@ -625,17 +658,6 @@ Unregisters a socket from a socket group */ void gf_sk_group_unregister(GF_SockGroup *sg, GF_Socket *sk); -/*! socket selection mode*/ -typedef enum -{ - /*! select for both read and write operations */ - GF_SK_SELECT_BOTH=0, - /*! select for both read operations */ - GF_SK_SELECT_READ, - /*! select for both write operations */ - GF_SK_SELECT_WRITE, -} GF_SockSelectMode; - /*! Performs a select (wait) on the socket group \param sg socket group object diff --git a/include/gpac/nodes_svg.h b/include/gpac/nodes_svg.h index d2cfbb9..4e2e2bc 100644 --- a/include/gpac/nodes_svg.h +++ b/include/gpac/nodes_svg.h @@ -39,6 +39,7 @@ enum { TAG_SVG_animateTransform, TAG_SVG_animation, TAG_SVG_audio, + TAG_SVG_clip_path, TAG_SVG_circle, TAG_SVG_defs, TAG_SVG_desc, @@ -321,6 +322,7 @@ struct _all_atts { SVG_Overlay *overlay; SVG_Boolean *fullscreen; SVG_Motion *motionTransform; + SVG_ClipPath *clip_path; SVG_Boolean *gpac_useAsPrimary; SVG_Number *gpac_depthOffset; diff --git a/include/gpac/options.h b/include/gpac/options.h index fd9259f..16c3371 100644 --- a/include/gpac/options.h +++ b/include/gpac/options.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / Stream Management sub-project @@ -198,7 +198,7 @@ enum GF_BACK_CULL_OFF = 0, /*! backface culliong enabled*/ GF_BACK_CULL_ON, - /*! backface culling enabled alos for transparent meshes*/ + /*! backface culling enabled also for transparent meshes*/ GF_BACK_CULL_ALPHA, }; @@ -295,7 +295,7 @@ enum GF_OPT_FORCE_AUDIO_CONFIG, /*! 3D ONLY OPTIONS */ - /*! set/get raster outline flag (value: boolean) - when set, no vectorial outlining is done, only openGL raster outline*/ + /*! set/get raster outline flag (value: boolean) - when set, no vectorial outlining is done, only OpenGL raster outline*/ GF_OPT_RASTER_OUTLINES, /*! set/get pow2 emulation flag (value: boolean) - when set, video textures with non power of 2 dimensions are emulated as pow2 by expanding the video buffer (image is not scaled). Otherwise the entire image diff --git a/include/gpac/path2d.h b/include/gpac/path2d.h index 1b22e76..33547ef 100644 --- a/include/gpac/path2d.h +++ b/include/gpac/path2d.h @@ -461,12 +461,14 @@ enum { /*! Path is filled using the zero-nonzero rule. If not set, filling uses odd/even rule*/ GF_PATH_FILL_ZERO_NONZERO = 1, + /*! Path is filled using the odd-even rule but only even surface is filled*/ + GF_PATH_FILL_EVEN = 1<<1, /*! When set bbox must be recomputed. \note Read only, used to avoid wasting time on bounds calculation*/ - GF_PATH_BBOX_DIRTY = 2, + GF_PATH_BBOX_DIRTY = 1<<2, /*! Indicates the path is flattened flattened \note Read only, used to avoid wasting time on flattening*/ - GF_PATH_FLATTENED = 4, + GF_PATH_FLATTENED = 1<<3, }; /*! diff --git a/include/gpac/route.h b/include/gpac/route.h new file mode 100644 index 0000000..cdbcc0f --- /dev/null +++ b/include/gpac/route.h @@ -0,0 +1,300 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2017-2020 + * All rights reserved + * + * This file is part of GPAC / ROUTE (ATSC3, DVB-I) demuxer + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _GF_ROUTE_H_ +#define _GF_ROUTE_H_ + +#include + +#ifndef GPAC_DISABLE_ROUTE + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +\file +\brief Specific extensions for ROUTE ( ATSC3, DVB-I) protocol +*/ + +/*! +\addtogroup route_grp ROUTE +\ingroup media_grp +\brief ROUTE ATSC 3.0 reciever + +The ROUTE receiver implements part of the ATSC 3.0 specification, mostly low-level signaling and ROUTE reception. +It gathers objects from a ROUTE session and sends them back to the user through a callback, or deletes them if no callback is sent. +The route demuxer does not try to repairing files, it is the user responsability to do so. + +@{ +*/ + + +/*! ATSC3.0 bootstrap address for LLS*/ +#define GF_ATSC_MCAST_ADDR "224.0.23.60" +/*! ATSC3.0 bootstrap port for LLS*/ +#define GF_ATSC_MCAST_PORT 4937 + +/*!The GF_ROUTEDmx object.*/ +typedef struct __gf_routedmx GF_ROUTEDmx; + +/*!The types of events used to communicate withe the demuxer user.*/ +typedef enum +{ + /*! A new service detected, service ID is in evt_param, no file info*/ + GF_ROUTE_EVT_SERVICE_FOUND = 0, + /*! Service scan completed, no evt_param, no file info*/ + GF_ROUTE_EVT_SERVICE_SCAN, + /*! New MPD available for service, service ID is in evt_param, no file info*/ + GF_ROUTE_EVT_MPD, + /*! static file update (with predefined TOI), service ID is in evt_param*/ + GF_ROUTE_EVT_FILE, + /*! Segment reception, identified through a file template, service ID is in evt_param*/ + GF_ROUTE_EVT_DYN_SEG, + /*! fragment reception (part of a segment), identified through a file template, service ID is in evt_param + \note The data is always beginning at the start of the object + */ + GF_ROUTE_EVT_DYN_SEG_FRAG, + /*! Object deletion (only for dynamic TOIs), used to notify the cache that an object is no longer available. File info only contains the filename being removed*/ + GF_ROUTE_EVT_FILE_DELETE, +} GF_ROUTEEventType; + +enum +{ + /*No-operation extension header*/ + GF_LCT_EXT_NOP = 0, + /*Authentication extension header*/ + GF_LCT_EXT_AUTH = 1, + /*Time extension header*/ + GF_LCT_EXT_TIME = 2, + /*FEC object transmission information extension header*/ + GF_LCT_EXT_FTI = 64, + /*Extension header for FDT - FLUTE*/ + GF_LCT_EXT_FDT = 192, + /*Extension header for FDT content encoding - FLUTE*/ + GF_LCT_EXT_CENC = 193, + /*TOL extension header - ROUTE - 24 bit payload*/ + GF_LCT_EXT_TOL24 = 194, + /*TOL extension header - ROUTE - HEL + 28 bit payload*/ + GF_LCT_EXT_TOL48 = 67, +}; + +/*! LCT fragment information*/ +typedef struct +{ + /*! offset in bytes of fragment in object / file*/ + u32 offset; + /*! size in bytes of fragment in object / file*/ + u32 size; +} GF_LCTFragInfo; + + +/*! Structure used to communicate file objects properties to the user*/ +typedef struct +{ + /*! original file name*/ + const char *filename; + /*! blob data pointer*/ + GF_Blob *blob; + /*! total size of object if known, 0 otherwise*/ + u32 total_size; + /*! object TSI*/ + u32 tsi; + /*! object TOI*/ + u32 toi; + /*! download time in ms*/ + u32 download_ms; + /*! flag set if file content has been modified - not set for GF_ROUTE_EVT_DYN_SEG (always true)*/ + Bool updated; + + /*! number of fragments, only set for GF_ROUTE_EVT_DYN_SEG*/ + u32 nb_frags; + /*! fragment info, only set for GF_ROUTE_EVT_DYN_SEG*/ + GF_LCTFragInfo *frags; + + /*! user data set to current object after callback, and passed back on next callbacks on same object + Only used for GF_ROUTE_EVT_FILE, GF_ROUTE_EVT_DYN_SEG, GF_ROUTE_EVT_DYN_SEG_FRAG and GF_ROUTE_EVT_FILE_DELETE + */ + void *udta; +} GF_ROUTEEventFileInfo; + +/*! Creates a new ROUTE ATSC3.0 demultiplexer +\param ifce network interface to monitor, NULL for INADDR_ANY +\param sock_buffer_size default buffer size for the udp sockets. If 0, uses 0x2000 + \param on_event the user callback function + \param udta the user data passed back by the callback +\return the ROUTE demultiplexer created +*/ +GF_ROUTEDmx *gf_route_atsc_dmx_new(const char *ifce, u32 sock_buffer_size, void (*on_event)(void *udta, GF_ROUTEEventType evt, u32 evt_param, GF_ROUTEEventFileInfo *finfo), void *udta); + +/*! Creates a new ROUTE demultiplexer +\param ip IP address of ROUTE session +\param port port of ROUTE session +\param ifce network interface to monitor, NULL for INADDR_ANY +\param sock_buffer_size default buffer size for the udp sockets. If 0, uses 0x2000 + \param on_event the user callback function + \param udta the user data passed back by the callback +\return the ROUTE demultiplexer created +*/ +GF_ROUTEDmx *gf_route_dmx_new(const char *ip, u32 port, const char *ifce, u32 sock_buffer_size, void (*on_event)(void *udta, GF_ROUTEEventType evt, u32 evt_param, GF_ROUTEEventFileInfo *finfo), void *udta); + +/*! Deletes an ROUTE demultiplexer +\param routedmx the ROUTE demultiplexer to delete +*/ +void gf_route_dmx_del(GF_ROUTEDmx *routedmx); + +/*! Processes demultiplexing, returns when nothing to read +\param routedmx the ROUTE demultiplexer +\return error code if any, GF_IP_NETWORK_EMPTY if nothing was read + */ +GF_Err gf_route_dmx_process(GF_ROUTEDmx *routedmx); + + +/*! Sets reordering on. +\param routedmx the ROUTE demultiplexer +\param force_reorder if TRUE, the order flag in ROUTE/LCT is ignored and objects are gathered for the given time. Otherwise, if order flag is set in ROUTE/LCT, an object is considered done as soon as a new object starts +\param timeout_ms maximum delay to wait before considering the object is done when ROUTE/LCT order is not used. A value of 0 implies waiting forever (default value is 5s). +\return error code if any + */ +GF_Err gf_route_set_reorder(GF_ROUTEDmx *routedmx, Bool force_reorder, u32 timeout_ms); + +/*! Allow segments to be sent while being downloaded. + +\note Files with a static TOI association are always sent once completely received, other files using TOI templating may be sent while being received if enabled. The data sent is always contiguous data since the beginning of the file in that case. + +\param routedmx the ROUTE demultiplexer +\param allow_progressive if TRUE, fragments of segments will be sent during download +\return error code if any + */ +GF_Err gf_route_set_allow_progressive_dispatch(GF_ROUTEDmx *routedmx, Bool allow_progressive); + +/*! Sets the service ID to tune into for ATSC 3.0 +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to tune in. 0 means no service, 0xFFFFFFFF means all services and 0xFFFFFFFE means first service found +\param tune_others if set, will tune all non-selected services to get the MPD, but won't receive any media data +\return error code if any + */ +GF_Err gf_route_atsc3_tune_in(GF_ROUTEDmx *routedmx, u32 service_id, Bool tune_others); + + +/*! Gets the number of objects currently loaded in the service +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to query +\return number of objects in service + */ +u32 gf_route_dmx_get_object_count(GF_ROUTEDmx *routedmx, u32 service_id); + +/*! Removes an object with a given filename +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to query +\param fileName name of the file associated with the object +\param purge_previous if set, indicates that all objects with the same TSI and a TOI less than TOI of the deleted object will be removed +\return error if any, GF_NOT_FOUND if no such object + */ +GF_Err gf_route_dmx_remove_object_by_name(GF_ROUTEDmx *routedmx, u32 service_id, char *fileName, Bool purge_previous); + +/*! Flags an object to be kept until \ref gf_route_dmx_remove_object_by_name is called +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to query +\param fileName name of the file associated with the object +\return error if any, GF_NOT_FOUND if no such object + */ +GF_Err gf_route_dmx_force_keep_object_by_name(GF_ROUTEDmx *routedmx, u32 service_id, char *fileName); + +/*! Removes the first object loaded in the service +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to query +\return GF_TRUE if success, GF_FALSE if no object could be removed (the object is in download) + */ +Bool gf_route_dmx_remove_first_object(GF_ROUTEDmx *routedmx, u32 service_id); + +/*! Checks existence of a service for atsc 3.0 +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to query +\return true if service is found, false otherwise + */ +Bool gf_route_dmx_find_atsc3_service(GF_ROUTEDmx *routedmx, u32 service_id); + +/*! Removes all non-signaling objects (ie TSI!=0), keeping only init segments and currently/last downloaded objects +\note this is mostly useful in case of looping session, or at MPD switch boundaries +\param routedmx the ROUTE demultiplexer +\param service_id ID of the service to cleanup + */ +void gf_route_dmx_purge_objects(GF_ROUTEDmx *routedmx, u32 service_id); + + +/*! Gets high resolution system time clock of the first packet received +\param routedmx the ROUTE demultiplexer +\return system clock in microseconds of first packet received + */ +u64 gf_route_dmx_get_first_packet_time(GF_ROUTEDmx *routedmx); + +/*! Gets high resolution system time clock of the last packet received +\param routedmx the ROUTE demultiplexer +\return system clock in microseconds of last packet received + */ +u64 gf_route_dmx_get_last_packet_time(GF_ROUTEDmx *routedmx); + +/*! Gets the number of packets received since start of the session, for all active services +\param routedmx the ROUTE demultiplexer +\return number of packets received + */ +u64 gf_route_dmx_get_nb_packets(GF_ROUTEDmx *routedmx); + +/*! Gets the number of bytes received since start of the session, for all active services +\param routedmx the ROUTE demultiplexer +\return number of bytes received + */ +u64 gf_route_dmx_get_recv_bytes(GF_ROUTEDmx *routedmx); + +/*! Gather only objects with given TSI (for debug purposes) +\param routedmx the ROUTE demultiplexer +\param tsi the target TSI, 0 for no filtering + */ +void gf_route_dmx_debug_tsi(GF_ROUTEDmx *routedmx, u32 tsi); + +/*! Sets udta for given service id +\param routedmx the ROUTE demultiplexer +\param service_id the target service +\param udta the target user data + */ +void gf_route_dmx_set_service_udta(GF_ROUTEDmx *routedmx, u32 service_id, void *udta); + +/*! Gets udta for given service id +\param routedmx the ROUTE demultiplexer +\param service_id the target service +\return the user data associated with the service + */ +void *gf_route_dmx_get_service_udta(GF_ROUTEDmx *routedmx, u32 service_id); + +/*! @} */ +#ifdef __cplusplus +} +#endif + +#endif /* GPAC_DISABLE_ROUTE */ + +#endif //_GF_ROUTE_H_ + diff --git a/include/gpac/scene_engine.h b/include/gpac/scene_engine.h index d4084bc..b23fafd 100644 --- a/include/gpac/scene_engine.h +++ b/include/gpac/scene_engine.h @@ -62,7 +62,7 @@ typedef void (*gf_seng_callback)(void *udta, u16 ESID, u8 *data, u32 size, u64 t \param inputContext is the name of a scene file (bt, xmt or mp4) to initialize the coding context \param load_type is the preferred loader type for the content (e.g. SVG vs DIMS) \param dump_path is the path where scenes are dumped -\param embed_resources indicates if images and scripts should be encoded inlined with the content +\param embed_resources indicates if images and scripts should be encoded inline with the content \return e scene engine object */ GF_SceneEngine *gf_seng_init(void *calling_object, char *inputContext, u32 load_type, char *dump_path, Bool embed_resources); diff --git a/include/gpac/scene_manager.h b/include/gpac/scene_manager.h index 5456292..c85d86e 100644 --- a/include/gpac/scene_manager.h +++ b/include/gpac/scene_manager.h @@ -338,7 +338,7 @@ void gf_sm_load_done(GF_SceneLoader *sload); \param sload the target scene loader \param str the string to load; MUST be at least 4 bytes long in order to detect BOM (unicode encoding); can be either UTF-8 or UTF-16 data -\param clean_at_end if GF_TRUE, associated parser is terminated. Otherwise, a call to gf_sm_load_done must be done to clean ressources (needed for SAX progressive loading) +\param clean_at_end if GF_TRUE, associated parser is terminated. Otherwise, a call to gf_sm_load_done must be done to clean resources (needed for SAX progressive loading) \return error if any */ GF_Err gf_sm_load_string(GF_SceneLoader *sload, const char *str, Bool clean_at_end); diff --git a/include/gpac/scenegraph.h b/include/gpac/scenegraph.h index 3ffef98..c2f1f2d 100644 --- a/include/gpac/scenegraph.h +++ b/include/gpac/scenegraph.h @@ -343,7 +343,7 @@ enum /*flag set whenever a field of the node has been modified*/ GF_SG_NODE_DIRTY = 1, /*flag set whenever a child node of this node has been modified - NOTE: unloaded extern protos always invalidate their parent subgraph to get a chance + \note Unloaded extern protos always invalidate their parent subgraph to get a chance of being loaded. It is the user responsability to clear the CHILD_DIRTY flag before traversing if relying on this flag for sub-tree discarding (eg, culling or similar)*/ GF_SG_CHILD_DIRTY = 1<<1, @@ -426,8 +426,7 @@ typedef struct _route GF_Route; /*! Node Field/attribute information for VRML/BIFS/SVG -Note: -all scene graph implementations should answer node field query with this interface. +\note all scene graph implementations should answer node field query with this interface. In case an implementation does not use this: - the implementation shall handle the parent node dirty flag itself most of the time - the implementation shall NOT allow referencing of a graph node in a parent graph node (when inlining @@ -488,7 +487,7 @@ GF_SceneGraph *gf_sg_new(); /*! creates a sub scene graph (typically used with Inline node): independent graph with same private stack, and user callbacks as parent. All routes triggered in this subgraph are executed in the parent graph (this means you only have to activate routes on the main graph) -NOTE: the resulting graph is not destroyed when the parent graph is +\note The resulting graph is not destroyed when the parent graph is \param scene the parent scene graph \return a new scene graph */ @@ -972,7 +971,7 @@ typedef struct s32 send_event_y; }; Bool aggregated; - /*some commands need to never be applied; for instance when building an aggregate carrousel*/ + /*some commands need to never be applied; for instance when building an aggregate carousel*/ Bool never_apply; } GF_Command; @@ -1008,13 +1007,6 @@ GF_Err gf_sg_command_apply_list(GF_SceneGraph *sg, GF_List *comList, Double time \return new commandFieldInfo structure*/ GF_CommandField *gf_sg_command_field_new(GF_Command *com); -/*! executes JS code in the root context of the scene graph -\param sg the target scene graph where to execute the script -\param com javascript code to execute -\return error if any -*/ -GF_Err gf_scene_execute_script(GF_SceneGraph *sg, const char *com); - /*! XML node from DOM parser */ typedef struct _xml_node *GF_DOMXMLNODE; diff --git a/include/gpac/scenegraph_svg.h b/include/gpac/scenegraph_svg.h index a81c5bd..82f9280 100644 --- a/include/gpac/scenegraph_svg.h +++ b/include/gpac/scenegraph_svg.h @@ -288,6 +288,7 @@ enum TAG_SVG_ATT_overlay, TAG_SVG_ATT_fullscreen, TAG_SVG_ATT_motionTransform, + TAG_SVG_ATT_clip_path, TAG_SVG_ATT_filter_transfer_type, TAG_SVG_ATT_filter_table_values, @@ -666,7 +667,9 @@ event list when destructed.*/ /* JavaScript context in which the listener is applicable */ \ struct js_handler_context *js_data;\ /* text content of the callback */ \ - char *callback; + char *callback; \ + /* parent timed elt */ \ + GF_Node *timed_elt; /*! DOM Event handler*/ typedef struct __xml_ev_handler @@ -940,7 +943,7 @@ Bool gf_svg_attribute_is_interpolatable(u32 type); \param a first attribute \param b second attribute \param c destination attribute -\param coef interpolation coeficient +\param coef interpolation coefficient \param clamp if GF_TRUE, the interpolated value is clamped to its min/max possible values \return error if any */ diff --git a/include/gpac/scenegraph_vrml.h b/include/gpac/scenegraph_vrml.h index 5dc9b84..c356625 100644 --- a/include/gpac/scenegraph_vrml.h +++ b/include/gpac/scenegraph_vrml.h @@ -200,7 +200,7 @@ typedef struct { } SFCommandBuffer; /*! Script - Note: the javascript or vrml script is handled in its decompressed (textual) format + \note The javascript or vrml script is handled in its decompressed (textual) format since most JS interpreter work with text*/ typedef struct { char* script_text; @@ -706,7 +706,7 @@ construction of proto dictionaries in case of nested protos GF_SceneGraph *gf_sg_proto_get_graph(GF_Proto *proto); /*! adds node code - a proto is build of several nodes, the first node is used for rendering -and the others are kept private. This set of nodes is refered to as the proto "node code" +and the others are kept private. This set of nodes is referred to as the proto "node code" \param proto the target proto \param n the node to add to the proto code \return error if any diff --git a/include/gpac/setup.h b/include/gpac/setup.h index cc101f3..a7793f5 100644 --- a/include/gpac/setup.h +++ b/include/gpac/setup.h @@ -180,7 +180,7 @@ typedef unsigned int size_t; /*! default path separator of the current platform*/ #define GF_PATH_SEPARATOR '\\' -/*we must explicitely export our functions...*/ +/*we must explicitly export our functions...*/ /*! macro for cross-platform signaling of exported function of libgpac*/ #define GF_EXPORT EXPORT_C @@ -432,12 +432,21 @@ typedef struct { #if (defined (WIN32) || defined (_WIN32_WCE)) && (defined(__MINGW32__) || !defined(__GNUC__)) -/*! macro for cross-platform suffix used for formating s64 integers in logs and printf routines*/ +#if defined(__MINGW32__) +/*! macro for cross-platform suffix used for formatting s64 integers in logs and printf routines*/ +#define LLD_SUF "lld" +/*! macro for cross-platform suffix used for formatting u64 integers in logs and printf routines*/ +#define LLU_SUF "llu" +/*! macro for cross-platform suffix used for formatting u64 integers as hex in logs and printf routines*/ +#define LLX_SUF "llx" +#else +/*! macro for cross-platform suffix used for formatting s64 integers in logs and printf routines*/ #define LLD_SUF "I64d" -/*! macro for cross-platform suffix used for formating u64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers in logs and printf routines*/ #define LLU_SUF "I64u" -/*! macro for cross-platform suffix used for formating u64 integers as hex in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers as hex in logs and printf routines*/ #define LLX_SUF "I64x" +#endif #ifdef _WIN64 /*! macro for cross-platform casting a pointer to an integer*/ @@ -449,11 +458,11 @@ typedef struct { #elif defined (__SYMBIAN32__) -/*! macro for cross-platform suffix used for formating s64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting s64 integers in logs and printf routines*/ #define LLD_SUF "d" -/*! macro for cross-platform suffix used for formating u64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers in logs and printf routines*/ #define LLU_SUF "u" -/*! macro for cross-platform suffix used for formating u64 integers as hex in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers as hex in logs and printf routines*/ #define LLX_SUF "x" /*! macro for cross-platform casting a pointer to an integer*/ @@ -462,11 +471,11 @@ typedef struct { /*seems that even though _LP64 is defined in OSX, %ll modifiers are still needed*/ #elif defined(__DARWIN__) || defined(__APPLE__) -/*! macro for cross-platform suffix used for formating s64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting s64 integers in logs and printf routines*/ #define LLD_SUF "lld" -/*! macro for cross-platform suffix used for formating u64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers in logs and printf routines*/ #define LLU_SUF "llu" -/*! macro for cross-platform suffix used for formating u64 integers as hex in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers as hex in logs and printf routines*/ #define LLX_SUF "llx" #ifdef __LP64__ /* Mac OS 64 bits */ @@ -479,11 +488,11 @@ typedef struct { #elif defined(_LP64) /*Unix 64 bits*/ -/*! macro for cross-platform suffix used for formating s64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting s64 integers in logs and printf routines*/ #define LLD_SUF "ld" -/*! macro for cross-platform suffix used for formating u64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers in logs and printf routines*/ #define LLU_SUF "lu" -/*! macro for cross-platform suffix used for formating u64 integers as hex in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers as hex in logs and printf routines*/ #define LLX_SUF "lx" /*! macro for cross-platform casting a pointer to an integer*/ @@ -491,11 +500,11 @@ typedef struct { #else /*Unix 32 bits*/ -/*! macro for cross-platform suffix used for formating s64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting s64 integers in logs and printf routines*/ #define LLD_SUF "lld" -/*! macro for cross-platform suffix used for formating u64 integers in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers in logs and printf routines*/ #define LLU_SUF "llu" -/*! macro for cross-platform suffix used for formating u64 integers as hex in logs and printf routines*/ +/*! macro for cross-platform suffix used for formatting u64 integers as hex in logs and printf routines*/ #define LLX_SUF "llx" /*! macro for cross-platform casting a pointer to an integer*/ @@ -654,7 +663,7 @@ typedef struct { \brief Memory management GPAC can use its own memory tracker, depending on compilation option. It is recommended to use only the functions -defined in this section to allocate and free memory whenever developping within the GPAC library. +defined in this section to allocate and free memory whenever developing within the GPAC library. \warning these functions shall only be used after initializing the library using \ref gf_sys_init @{ @@ -691,14 +700,14 @@ void gf_free(void *ptr); /*! allocates memory, shall be freed using \ref gf_free \param size same as malloc() -\return adress of allocated block +\return address of allocated block */ void* gf_malloc(size_t size); /*! allocates memory array, shall be freed using \ref gf_free \param num same as calloc() \param size_of same as calloc() -\return adress of allocated block +\return address of allocated block */ void* gf_calloc(size_t num, size_t size_of); @@ -711,7 +720,7 @@ char* gf_strdup(const char *str); /*! reallocates memory, shall be freed using \ref gf_free \param ptr same as realloc() \param size same as realloc() -\return adress of reallocated block +\return address of reallocated block */ void* gf_realloc(void *ptr, size_t size); @@ -721,6 +730,13 @@ void* gf_realloc(void *ptr, size_t size); /*end GPAC memory tracking*/ +/*! copy source string to destination, ensuring 0-terminated string result +\param dst destination buffer +\param src source buffer +\param dsize size of destination buffer +\return same as strlcpy +*/ +size_t gf_strlcpy(char *dst, const char *src, size_t dsize); #ifdef __cplusplus } diff --git a/include/gpac/svg_types.h b/include/gpac/svg_types.h index cd83e59..a32a21f 100644 --- a/include/gpac/svg_types.h +++ b/include/gpac/svg_types.h @@ -110,6 +110,7 @@ enum { SMIL_Accumulate_datatype, SMIL_Restart_datatype, SMIL_Fill_datatype, + SVG_ClipPath_datatype, SVG_LAST_U8_PROPERTY, @@ -176,6 +177,9 @@ enum { LASeR_Size_datatype, SVG_Matrix2D_datatype, + + /*internal type for node list*/ + SVG_NodeList_datatype }; //! @cond Doxygen_Suppress @@ -378,7 +382,7 @@ typedef struct __xml_ri { } XMLRI; /*! XML IDREF object - Note: the same structure is used to watch for IDREF changes (LASeR node replace) + \note the same structure is used to watch for IDREF changes (LASeR node replace) */ typedef struct __xml_ri XML_IDREF; @@ -894,7 +898,7 @@ enum { /*! DOM Event phase*/ typedef u8 XMLEV_Phase; -/*! SMIL sync behaviour types */ +/*! SMIL sync behavior types */ enum { SMIL_SYNCBEHAVIOR_INHERIT = 0, /*LASeR order*/ @@ -903,7 +907,7 @@ enum { SMIL_SYNCBEHAVIOR_INDEPENDENT, SMIL_SYNCBEHAVIOR_LOCKED, }; -/*! SMIL sync behaviour*/ +/*! SMIL sync behavior*/ typedef u8 SMIL_SyncBehavior; /*! SMIL sync tolerance types */ @@ -977,7 +981,7 @@ enum { /*! SVG initial visibility*/ typedef u8 SVG_InitialVisibility; -/*! SVG transform behaviour types */ +/*! SVG transform behavior types */ enum { SVG_TRANSFORMBEHAVIOR_GEOMETRIC = 0, SVG_TRANSFORMBEHAVIOR_PINNED, @@ -985,7 +989,7 @@ enum { SVG_TRANSFORMBEHAVIOR_PINNED270, SVG_TRANSFORMBEHAVIOR_PINNED90, }; -/*! SVG transform behaviour*/ +/*! SVG transform behavior*/ typedef u8 SVG_TransformBehavior; /*! SVG overlay types */ @@ -1026,6 +1030,12 @@ enum { /*! SVG spread method*/ typedef u8 SVG_SpreadMethod; +/*! SVG clip-path attribute*/ +typedef struct +{ + XMLRI target; +} SVG_ClipPath; + /*! LASeR choice types */ enum { LASeR_CHOICE_ALL = 0, diff --git a/include/gpac/term_info.h b/include/gpac/term_info.h index 7b6ebbd..7558f98 100644 --- a/include/gpac/term_info.h +++ b/include/gpac/term_info.h @@ -171,9 +171,10 @@ typedef struct u32 au_duration; u32 nb_iraps; s32 ntp_diff; + //0 if mono, 2 or more otherwise + u32 nb_views; - /*set if ISMACryp present on the object - will need refinement for IPMPX... - 0: not protected - 1: protected and OK - 2: protected and DRM failed*/ + /*4CC of original protection scheme used*/ u32 protection; u32 lang; @@ -260,7 +261,7 @@ GF_Err gf_term_get_service_info(GF_Terminal *term, GF_ObjectManager *odm, GF_Ter /*! retrieves world info of the scene of an object. \param term the target terminal -\param scene_od the object manager to query. If this is an inlined OD, the world info of the inlined content is retrieved. If NULL, the world info of the main scene is retrieved +\param scene_od the object manager to query. If this is an inline OD, the world info of the inline content is retrieved. If NULL, the world info of the main scene is retrieved \param descriptions any textual descriptions is stored here (const strings not allocated, do NOT modify) \return NULL if no WorldInfo available or world title if available */ @@ -272,7 +273,7 @@ const char *gf_term_get_world_info(GF_Terminal *term, GF_ObjectManager *scene_od \param filename sets to the complete filename (rad + ext) and shall be destroyed by caller (optional can be NULL) \param xml_dump if GF_TRUE, duimps using XML format (XMT-A, X3D) for scene graphs having both XML and simple text representations \param skip_proto is GF_TRUE, proto declarations are not dumped -\param odm if this is an inlined OD, the inlined scene is dumped; if this is NULL, the main scene is dumped; otherwise the parent scene is dumped +\param odm if this is an inline OD, the inline scene is dumped; if this is NULL, the main scene is dumped; otherwise the parent scene is dumped \return error if any */ GF_Err gf_term_dump_scene(GF_Terminal *term, char *rad_name, char **filename, Bool xml_dump, Bool skip_proto, GF_ObjectManager *odm); diff --git a/include/gpac/terminal.h b/include/gpac/terminal.h index 54255a3..366bb86 100644 --- a/include/gpac/terminal.h +++ b/include/gpac/terminal.h @@ -123,7 +123,7 @@ u32 gf_term_get_time_in_ms(GF_Terminal *term); /*! gets elapsed time since loading of the scene - may be different from scene time when seeking or live content \param term the target terminal -\return time ellapsed in milliseconds +\return time elapsed in milliseconds */ u32 gf_term_get_elapsed_time_in_ms(GF_Terminal *term); @@ -202,13 +202,6 @@ Double gf_term_get_simulation_frame_rate(GF_Terminal *term, u32 *nb_frames_drawn \return error if any */ GF_Err gf_term_get_visual_output_size(GF_Terminal *term, u32 *width, u32 *height); - -/*! process shortcuts for key events -\param term the target terminal -\param ev the event to process -*/ -void gf_term_process_shortcut(GF_Terminal *term, GF_Event *ev); - /*! sets playback speed \param term the target terminal \param speed the requested speed @@ -267,7 +260,7 @@ Bool gf_term_process_step(GF_Terminal *term); /*! post user interaction to terminal \param term the target terminal \param event the event to post -\return GF_TRUE if event was directly consummed +\return GF_TRUE if event was directly consumed */ Bool gf_term_user_event(GF_Terminal *term, GF_Event *event); @@ -275,7 +268,7 @@ Bool gf_term_user_event(GF_Terminal *term, GF_Event *event); \warning NOT NEEDED WHEN THE TERMINAL IS HANDLING THE DISPLAY WINDOW (cf user.h) \param term the target terminal \param evt the event to post -\return GF_TRUE if event was directly consummed +\return GF_TRUE if event was directly consumed */ Bool gf_term_send_event(GF_Terminal *term, GF_Event *evt); diff --git a/include/gpac/thread.h b/include/gpac/thread.h index b749971..4b9dc77 100644 --- a/include/gpac/thread.h +++ b/include/gpac/thread.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2021 * All rights reserved * * This file is part of GPAC / common tools sub-project @@ -64,7 +64,7 @@ The thread object allows executing some code independently of the main process o //atomic ref_count++ / ref_count-- -#if defined(WIN32) || defined(_WIN32_WCE) +#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__) #include #include @@ -74,11 +74,11 @@ The thread object allows executing some code independently of the main process o #define safe_int_dec(__v) InterlockedDecrement((int *) (__v)) /*! atomic integer addition */ #define safe_int_add(__v, inc_val) InterlockedAdd((int *) (__v), inc_val) -/*! atomic integer substraction */ +/*! atomic integer subtraction */ #define safe_int_sub(__v, dec_val) InterlockedAdd((int *) (__v), -dec_val) /*! atomic large integer addition */ #define safe_int64_add(__v, inc_val) InterlockedAdd64((LONG64 *) (__v), inc_val) -/*! atomic large integer substraction */ +/*! atomic large integer subtraction */ #define safe_int64_sub(__v, dec_val) InterlockedAdd64((LONG64 *) (__v), -dec_val) #else @@ -91,11 +91,11 @@ The thread object allows executing some code independently of the main process o #define safe_int_dec(__v) __atomic_sub_fetch((int *) (__v), 1, __ATOMIC_SEQ_CST) /*! atomic integer addition */ #define safe_int_add(__v, inc_val) __atomic_add_fetch((int *) (__v), inc_val, __ATOMIC_SEQ_CST) -/*! atomic integer substraction */ +/*! atomic integer subtraction */ #define safe_int_sub(__v, dec_val) __atomic_sub_fetch((int *) (__v), dec_val, __ATOMIC_SEQ_CST) /*! atomic large integer addition */ #define safe_int64_add(__v, inc_val) __atomic_add_fetch((int64_t *) (__v), inc_val, __ATOMIC_SEQ_CST) -/*! atomic large integer substraction */ +/*! atomic large integer subtraction */ #define safe_int64_sub(__v, dec_val) __atomic_sub_fetch((int64_t *) (__v), dec_val, __ATOMIC_SEQ_CST) #else @@ -106,11 +106,11 @@ The thread object allows executing some code independently of the main process o #define safe_int_dec(__v) __sync_sub_and_fetch((int *) (__v), 1) /*! atomic integer addition */ #define safe_int_add(__v, inc_val) __sync_add_and_fetch((int *) (__v), inc_val) -/*! atomic integer substraction */ +/*! atomic integer subtraction */ #define safe_int_sub(__v, dec_val) __sync_sub_and_fetch((int *) (__v), dec_val) /*! atomic large integer addition */ #define safe_int64_add(__v, inc_val) __sync_add_and_fetch((int64_t *) (__v), inc_val) -/*! atomic large integer substraction */ +/*! atomic large integer subtraction */ #define safe_int64_sub(__v, dec_val) __sync_sub_and_fetch((int64_t *) (__v), dec_val) #endif //GPAC_NEED_LIBATOMIC @@ -266,30 +266,30 @@ GF_Mutex *gf_mx_new(const char *name); \brief mutex denstructor Destroys a mutex object. This will wait for the mutex to be released if needed. -\param mx the mutex object +\param mx the mutex object, may be NULL */ void gf_mx_del(GF_Mutex *mx); /*! \brief mutex locking Locks the mutex object, making sure that another thread locking this mutex cannot execute until the mutex is unlocked. -\param mx the mutex object -\return 1 if success, 0 if error locking the mutex (which should never happen) +\param mx the mutex object, may be NULL +\return 1 if success or mutex is NULL, 0 if error locking the mutex (which should never happen) */ u32 gf_mx_p(GF_Mutex *mx); /*! \brief mutex unlocking Unlocks the mutex object, allowing other threads waiting on this mutex to continue their execution -\param mx the mutex object +\param mx the mutex object, may be NULL */ void gf_mx_v(GF_Mutex *mx); /*! \brief mutex non-blocking lock Attemps to lock the mutex object without blocking until the object is released. -\param mx the mutex object -\return GF_TRUE if the mutex has been successfully locked, in which case it shall then be unlocked, or GF_FALSE if the mutex is locked by another thread. +\param mx the mutex object, may be NULL +\return GF_TRUE if the mutex has been successfully locked or if the mutex is NULL, in which case it shall then be unlocked, or GF_FALSE if the mutex is locked by another thread. */ Bool gf_mx_try_lock(GF_Mutex *mx); @@ -297,8 +297,8 @@ Bool gf_mx_try_lock(GF_Mutex *mx); \brief get mutex number of locks Returns the number of locks on the mutex if the caller thread is holding the mutex. -\param mx the mutex object -\return -1 if the mutex is not hold by the calling thread, or the number of locks (possibly 0) otherwise. +\param mx the mutex object, may be NULL +\return -1 if the mutex is not hold by the calling thread, or the number of locks (possibly 0) otherwise. Returns 0 if mutex is NULL */ s32 gf_mx_get_num_locks(GF_Mutex *mx); @@ -309,7 +309,7 @@ s32 gf_mx_get_num_locks(GF_Mutex *mx); \brief Semaphore -The semaphore object allows controling how portions of the code (typically access to variables) are +The semaphore object allows controlling how portions of the code (typically access to variables) are executed by two threads (or a thread and the main process) at the same time. The best image for a semaphore is a limited set of money coins (always easy to understand hmm?). If no money is in the set, nobody can buy anything until a coin is put back in the set. When the set is full, the money is wasted (call it "the bank"...). diff --git a/include/gpac/tools.h b/include/gpac/tools.h index 80674fe..ad97165 100644 --- a/include/gpac/tools.h +++ b/include/gpac/tools.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2020 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / common tools sub-project @@ -67,7 +67,7 @@ Macro transforming its input name into a string \brief 4CC Formatting \hideinitializer -Macro formating a 4-character code (or 4CC) "abcd" as 0xAABBCCDD +Macro formatting a 4-character code (or 4CC) "abcd" as 0xAABBCCDD */ #ifndef GF_4CC #define GF_4CC(a,b,c,d) ((((u32)a)<<24)|(((u32)b)<<16)|(((u32)c)<<8)|((u32)d)) @@ -82,6 +82,12 @@ Macro formating a 4-character code (or 4CC) "abcd" as 0xAABBCCDD */ const char *gf_4cc_to_str(u32 type); +/*! converts a 4CC string to its 32 bits value +\param val four character string +\return code value or 0 if error +*/ +u32 gf_4cc_parse(const char *val); + /*! @} */ /*! @@ -131,7 +137,7 @@ typedef enum GF_SCRIPT_ERROR = -8, /*! Buffer is too small to contain decoded data. Decoders shall use this error whenever they need to resize their output memory buffers*/ GF_BUFFER_TOO_SMALL = -9, - /*! Bitstream is not compliant to the specfication it refers to*/ + /*! The bitstream is not compliant to the specfication it refers to*/ GF_NON_COMPLIANT_BITSTREAM = -10, /*! No filter could be found to handle the desired media type*/ GF_FILTER_NOT_FOUND = -11, @@ -143,6 +149,9 @@ typedef enum GF_REMOTE_SERVICE_ERROR = -14, /*! The desired stream could not be found in the service*/ GF_STREAM_NOT_FOUND = -15, + /*! The URL no longer exists*/ + GF_URL_REMOVED = -16, + /*! The IsoMedia file is not a valid one*/ GF_ISOM_INVALID_FILE = -20, /*! The IsoMedia file is not complete. Either the file is being downloaded, or it has been truncated*/ @@ -218,9 +227,9 @@ const char *gf_error_to_string(GF_Err e); Macro allocating memory and zero-ing it */ #define GF_SAFEALLOC(__ptr, __struct) {\ - __ptr = (__struct *) gf_malloc(sizeof(__struct));\ + (__ptr) = (__struct *) gf_malloc(sizeof(__struct));\ if (__ptr) {\ - memset((void *) __ptr, 0, sizeof(__struct));\ + memset((void *) (__ptr), 0, sizeof(__struct));\ }\ } @@ -231,9 +240,9 @@ Macro allocating memory and zero-ing it Macro allocating memory for n structures and zero-ing it */ #define GF_SAFE_ALLOC_N(__ptr, __n, __struct) {\ - __ptr = (__struct *) gf_malloc( __n * sizeof(__struct));\ + (__ptr) = (__struct *) gf_malloc( __n * sizeof(__struct));\ if (__ptr) {\ - memset((void *) __ptr, 0, __n * sizeof(__struct));\ + memset((void *) (__ptr), 0, __n * sizeof(__struct));\ }\ } @@ -249,6 +258,121 @@ Dynamic concatenation of string with optional separator */ GF_Err gf_dynstrcat(char **str, const char *to_append, const char *sep); + +/*! +\brief fraction parsing + +Parse a 64 bit fraction from string +\param str string to parse +\param frac fraction to fill +\return GF_TRUE if success, GF_FALSE otherwise ( fraction being set to {0,0} ) + */ +Bool gf_parse_lfrac(const char *str, GF_Fraction64 *frac); + +/*! +\brief fraction parsing + +Parse a 32 bit fraction from string +\param str string to parse +\param frac fraction to fill +\return GF_TRUE if success, GF_FALSE otherwise ( fraction being set to {0,0} ) + */ +Bool gf_parse_frac(const char *str, GF_Fraction *frac); + +/*! +\brief search string without case + +Search a aubstring in a string witout checking for case +\param text text to search +\param subtext string to find +\param subtext_len length of string to find +\return GF_TRUE if success, GF_FALSE otherwise + */ +Bool gf_strnistr(const char *text, const char *subtext, u32 subtext_len); + + +/*! +\brief safe timestamp rescale + +Rescale a 64 bit timestamp value to new timescale, i.e. performs value * new_timescale / timescale +\param value value to rescale. A value of -1 means no timestamp defined and is returned unmodified +\param timescale timescale of value. Assumed to be less than 0xFFFFFFFF +\param new_timescale new timescale? Assumed to be less than 0xFFFFFFFF +\return new value + */ +u64 gf_timestamp_rescale(u64 value, u64 timescale, u64 new_timescale); + +/*! +\brief safe signed timestamp rescale + +Rescale a 64 bit timestamp value to new timescale, i.e. performs value * new_timescale / timescale +\param value value to rescale +\param timescale timescale of value. Assumed to be less than 0xFFFFFFFF +\param new_timescale new timescale. Assumed to be less than 0xFFFFFFFF +\return new value + */ +s64 gf_timestamp_rescale_signed(s64 value, u64 timescale, u64 new_timescale); + +/*! +\brief compare timestamps + +Compares two timestamps +\param value1 value to rescale +\param timescale1 timescale of value. Assumed to be less than 0xFFFFFFFF +\param value2 value to rescale +\param timescale2 timescale of value. Assumed to be less than 0xFFFFFFFF +\return GF_TRUE if (value1 / timescale1) is stricly less than (value2 / timescale2) + */ +Bool gf_timestamp_less(u64 value1, u64 timescale1, u64 value2, u64 timescale2); + +/*! +\brief compare timestamps + +Compares two timestamps +\param value1 value to rescale +\param timescale1 timescale of value. Assumed to be less than 0xFFFFFFFF +\param value2 value to rescale +\param timescale2 timescale of value. Assumed to be less than 0xFFFFFFFF +\return GF_TRUE if (value1 / timescale1) is stricly less than or equal to (value2 / timescale2) + */ +Bool gf_timestamp_less_or_equal(u64 value1, u64 timescale1, u64 value2, u64 timescale2); + +/*! +\brief compare timestamps + +Compares two timestamps +\param value1 value to rescale +\param timescale1 timescale of value. Assumed to be less than 0xFFFFFFFF +\param value2 value to rescale +\param timescale2 timescale of value. Assumed to be less than 0xFFFFFFFF +\return GF_TRUE if (value1 / timescale1) is stricly greater than (value2 / timescale2) + */ +Bool gf_timestamp_greater(u64 value1, u64 timescale1, u64 value2, u64 timescale2); + +/*! +\brief compare timestamps + +Compares two timestamps +\param value1 value to rescale +\param timescale1 timescale of value. Assumed to be less than 0xFFFFFFFF +\param value2 value to rescale +\param timescale2 timescale of value. Assumed to be less than 0xFFFFFFFF +\return GF_TRUE if (value1 / timescale1) is stricly greater than or equal to (value2 / timescale2) + */ +Bool gf_timestamp_greater_or_equal(u64 value1, u64 timescale1, u64 value2, u64 timescale2); + +/*! +\brief compare timestamps + +Compares two timestamps +\param value1 value to rescale +\param timescale1 timescale of value. Assumed to be less than 0xFFFFFFFF +\param value2 value to rescale +\param timescale2 timescale of value. Assumed to be less than 0xFFFFFFFF +\return GF_TRUE if (value1 / timescale1) is equal to (value2 / timescale2) + */ +Bool gf_timestamp_equal(u64 value1, u64 timescale1, u64 value2, u64 timescale2); + /*! @} */ /*! @@ -298,7 +422,7 @@ The profile allows using a different global config file than the default, and ma GF_Err gf_sys_init(GF_MemTrackerType mem_tracker_type, const char *profile); /*! \brief System closing -Closes the system high-resolution clock and any CPU associated ressources. +Closes the system high-resolution clock and any CPU associated resources. \note This can be called several times but the system will be closed when no more users are counted. */ void gf_sys_close(); @@ -308,7 +432,7 @@ void gf_sys_close(); Sets the user app arguments (used by GUI mode) \param argc Number of arguments -\param argv Array of arguments +\param argv Array of arguments - the first string is ignored (considered to be the executable name) \return error code if any, GF_OK otherwise */ GF_Err gf_sys_set_args(s32 argc, const char **argv); @@ -338,6 +462,14 @@ Gets the number of argument of the user application if any */ const char *gf_sys_get_arg(u32 arg); +/*! +\brief Locate a global filter arg + +Looks for a filter option specified as global argument +\param arg name of option to search, without "--" or "-+" specififers +\return argument value string, empty string for booleans or NULL if not found + */ +const char *gf_sys_find_global_arg(const char *arg); /*! \brief Mark arg as used @@ -507,13 +639,13 @@ typedef enum \brief Log exits at first error assignment When GF_LOG_ERROR happens, program leaves with instruction exit(1); -\param strict strict behaviour when encoutering a serious error. +\param strict strict behavior when encoutering a serious error. \return old value before the call. */ Bool gf_log_set_strict_error(Bool strict); /*! -\brief gets string-formated log tools +\brief gets string-formatted log tools Gets the string-formatted log tools and levels. Returned string shall be freed by the caller. \return string-formatted log tools. @@ -540,15 +672,11 @@ typedef enum GF_LOG_HTTP, /*! Log message from the RTP/RTCP stack (TS info) and packet structure & hinting (debug)*/ GF_LOG_RTP, - /*! Log message from authoring subsystem (file manip, import/export)*/ - GF_LOG_AUTHOR, - /*! Log message from the sync layer of the terminal*/ - GF_LOG_SYNC, /*! Log message from a codec*/ GF_LOG_CODEC, - /*! Log message from any XML parser (context loading, etc)*/ + /*! Log message from any textual (XML, ...) parser (context loading, etc)*/ GF_LOG_PARSER, - /*! Log message from the terminal/compositor, indicating media object state*/ + /*! Generic log message from a filter (not from filter core library)*/ GF_LOG_MEDIA, /*! Log message from the scene graph/scene manager (handling of nodes and attribute modif, DOM core)*/ GF_LOG_SCENE, @@ -558,14 +686,14 @@ typedef enum GF_LOG_INTERACT, /*! Log message from compositor*/ GF_LOG_COMPOSE, + /*! Log message from the terminal/compositor, indicating media object state*/ + GF_LOG_COMPTIME, /*! Log for video object cache */ GF_LOG_CACHE, /*! Log message from multimedia I/O devices (audio/video input/output, ...)*/ GF_LOG_MMIO, /*! Log for runtime info (times, memory, CPU usage)*/ GF_LOG_RTI, - /*! Log for SMIL timing and animation*/ - GF_LOG_SMIL, /*! Log for memory tracker*/ GF_LOG_MEMORY, /*! Log for audio compositor*/ @@ -578,12 +706,12 @@ typedef enum GF_LOG_CONDITION, /*! Log for all HTTP streaming */ GF_LOG_DASH, - /*! Log for all messages coming from filters */ + /*! Log for all messages from filter core library (not from a filter) */ GF_LOG_FILTER, /*! Log for filter scheduler only */ GF_LOG_SCHEDULER, - /*! Log for all ATSC3 message */ - GF_LOG_ATSC, + /*! Log for all ROUTE message */ + GF_LOG_ROUTE, /*! Log for all messages coming from GF_Terminal or script alert()*/ GF_LOG_CONSOLE, /*! Log for all messages coming the application, not used by libgpac or the modules*/ @@ -632,9 +760,9 @@ gf_log_cbk gf_log_set_callback(void *usr_cbk, gf_log_cbk cbk); \cond DUMMY_DOXY_SECTION */ #ifndef GPAC_DISABLE_LOG -/*note: - to turn log on, change to GPAC_ENABLE_LOG - to turn log off, change to GPAC_DISABLE_LOG +/*\note + - to turn log on, change to GPAC_ENABLE_LOG + - to turn log off, change to GPAC_DISABLE_LOG this is needed by configure+sed to modify this file directly */ #define GPAC_ENABLE_LOG @@ -846,6 +974,13 @@ Parses 128 bit from string */ GF_Err gf_bin128_parse(const char *string, bin128 value); + +enum +{ + GF_BLOB_IN_TRANSFER = 1, + GF_BLOB_CORRUPTED = 1<<1, +}; + /*! * Blob structure used to pass data pointer around */ @@ -855,16 +990,28 @@ typedef struct u8 *data; /*! size of blob */ u32 size; + /*! blob flags */ + u32 flags; + /*! blob mutex for multi-thread access */ + struct __tag_mutex *mx; } GF_Blob; /*! - * Retrieves data associated with a blob url + * Retrieves data associated with a blob url. If success, \ref gf_blob_release must be called after this \param blob_url URL of blob object (ie gmem://%p) \param out_data if success, set to blob data pointer \param out_size if success, set to blob data size +\param blob_flags if success, set to blob flags - may be NULL +\return error code + */ +GF_Err gf_blob_get(const char *blob_url, u8 **out_data, u32 *out_size, u32 *blob_flags); + +/*! + * Releases blob data +\param blob_url URL of blob object (ie gmem://%p) \return error code */ -GF_Err gf_blob_get_data(const char *blob_url, u8 **out_data, u32 *out_size); +GF_Err gf_blob_release(const char *blob_url); /*! \addtogroup time_grp @@ -919,7 +1066,7 @@ u64 gf_net_get_utc(); \brief converts an ntp timestamp into UTC time in milliseconds Converts NTP 64-bit timestamp to UTC clock in milliseconds -\u64 ntp NTP timestamp +\param ntp NTP timestamp \return UTC time in milliseconds */ u64 gf_net_ntp_to_utc(u64 ntp); @@ -957,6 +1104,14 @@ Gets timezone adjustment in seconds, with localtime - timezone = UTC time */ s32 gf_net_get_timezone(); +/*! +\brief gets timezone daylight saving time status + +Gets timezone daylight saving time +\return GF_TRUE if DST is active + */ +Bool gf_net_time_is_dst(); + /*! \brief gets time from UTC timestamp @@ -1131,7 +1286,7 @@ Cleanup a directory within the full path, removing all the files and the directo \param DirPathName the dir path name. \return error if any */ -GF_Err gf_cleanup_dir(const char* DirPathName); +GF_Err gf_dir_cleanup(const char* DirPathName); /** @@ -1274,10 +1429,11 @@ Opens a file, potentially using file IO if the parent URL is a File IO wrapper \param file_name same as fopen \param parent_url URL of parent file. If not a file io wrapper (gfio://), the function is equivalent to gf_fopen \param mode same as fopen +\param no_warn if GF_TRUE, do not throw log message if failure \return stream handle of the file object \note You only need to call this function if you're suspecting the file to be a large one (usually only media files), otherwise use regular stdio. \return stream habdle of the file or file IO object*/ -FILE *gf_fopen_ex(const char *file_name, const char *parent_url, const char *mode); +FILE *gf_fopen_ex(const char *file_name, const char *parent_url, const char *mode, Bool no_warn); /*! \brief file closing @@ -1323,7 +1479,6 @@ char* gf_file_basename(const char* filename); */ char* gf_file_ext_start(const char* filename); - /*!\brief FileEnum info object The FileEnumInfo object is used to get file attributes upon enumeration of a directory. @@ -1403,7 +1558,7 @@ FILE *gf_file_temp(char ** const fileName); /*! \brief File Modification Time -Gets the modification time of the given file. The exact meaning of this value is system dependent +Gets the UTC modification time of the given file in microseconds \param filename file to check \return modification time of the file */ @@ -1433,11 +1588,12 @@ typedef struct __gf_file_io GF_FileIO; /*! open proc for memory file IO \param fileio_ref reference file_io. A file can be opened multiple times for the same reference, your code must handle this \param url target file name. -\param mode opening mode of file, same as fopen mode. The following additionnal modes are defined: +\param mode opening mode of file, same as fopen mode. The following additional modes are defined: - "ref": indicates this FileIO object is used by some part of the code and must not be destroyed upon closing of the file. Associated URL is null - "unref": indicates this FileIO object is not used by some part of the code and may be destroyed if no more references to this object are set. Associated URL is null - "url": indicates to create a new FileIO object for the given URL without opening the output file. The resulting FileIO object must be garbage collected by the app in case its is never used by the callers - "probe": checks if the file exists, but no need to open the file. The function should return NULL in this case. If file does not exist, set out_error to GF_URL_ERROR + - "close": indicates the fileIO object is being closed (fclose) \param out_error must be set to error code if any (never NULL) \return the opened GF_FileIO if success, or NULL otherwise */ @@ -1556,6 +1712,22 @@ Bool gf_fileio_get_stats(GF_FileIO *fileio, u64 *bytes_done, u64 *file_size, Boo */ GF_FileIO *gf_fileio_open_url(GF_FileIO *fileio, const char *url, const char *mode, GF_Err *out_err); + +/*! Tags a FileIO object to be accessed from main thread only +\param fileio target file IO object +\return error if any +*/ +GF_Err gf_fileio_tag_main_thread(GF_FileIO *fileio); + +/*! Check if a FileIO object is to be accessed from main thread only + + \note Filters accessing FileIO objects by other means that a filter option must manually tag themselves as main thread, potentially rescheduling a configure call to next process. Not doing so can result in binding crashes in multi-threaded mode. + +\param url target url +\return GF_TRUE if object is tagged for main thread, GF_FALSE otherwise +*/ +Bool gf_fileio_is_main_thread(const char *url); + /*! Gets GF_FileIO object from its URL The url uses the protocol scheme "gfio://" \param url the URL of the File IO object @@ -1564,7 +1736,7 @@ GF_FileIO *gf_fileio_open_url(GF_FileIO *fileio, const char *url, const char *mo GF_FileIO *gf_fileio_from_url(const char *url); /*! Constructs a new GF_FileIO object from a URL - The url can be absolute or relative to the parent GF_FileIO. This is typcically needed by filters (dash input, dasher, NHML/NHNT writers...) generating or consuming additionnal files associated with the main file IO object but being written or read by other filters. + The url can be absolute or relative to the parent GF_FileIO. This is typcically needed by filters (dash input, dasher, NHML/NHNT writers...) generating or consuming additional files associated with the main file IO object but being written or read by other filters. The function will not open the associated resource, only create the file IO wrapper for later usage If you need to create a new fileIO to be opened immediately, use \ref gf_fopen_ex. @@ -1769,6 +1941,13 @@ void gf_sha1_finish(GF_SHA1Context *ctx, u8 digest[GF_SHA1_DIGEST_SIZE] ); */ GF_Err gf_sha1_file(const char *filename, u8 digest[GF_SHA1_DIGEST_SIZE]); +/*! gets SHA1 message digest of a opened file +\param file handle to open file +\param digest buffer to store message digest +\return error if any +*/ +GF_Err gf_sha1_file_ptr(FILE *file, u8 digest[GF_SHA1_DIGEST_SIZE] ); + /*! gets SHA-1 of input buffer \param buf input buffer to hash \param buflen sizeo of input buffer in bytes @@ -1909,8 +2088,8 @@ extern void gf_fm_request_set_callback(void *cbk_obj, fm_callback_func cbk_func) void gf_fm_request_call(u32 type, u32 param, int *value); #endif //GPAC_CONFIG_ANDROID -/*to call whenever the OpenGL library is opened - this function is needed to bind openGL and remotery, and to load -openGL extensions on windows +/*to call whenever the OpenGL library is opened - this function is needed to bind OpenGL and remotery, and to load +OpenGL extensions on windows not exported, and not included in src/compositor/gl_inc.h since it may be needed even when no OpenGL calls are made by the caller*/ void gf_opengl_init(); @@ -1937,6 +2116,7 @@ typedef struct _gl_texture_wrap Bool is_yuv; u32 bit_depth, uv_w, uv_h; u32 scale_10bit; + u32 init_active_texture; u32 gl_format; u32 bytes_per_pix; @@ -1947,13 +2127,18 @@ typedef struct _gl_texture_wrap struct _gf_filter_frame_interface *frame_ifce; Bool first_tx_load; - //PBO state - must be managed by caller, especially if using seperated push and texImg steps through gf_gl_txw_setup calls + //PBO state - must be managed by caller, especially if using separated push and texImg steps through gf_gl_txw_setup calls GF_GLPBOState pbo_state; Bool flip; + //YUV is full video range + Bool fullrange; + s32 mx_cicp; + + u32 last_program; } GF_GLTextureWrapper; -Bool gf_gl_txw_insert_fragment_shader(u32 pix_fmt, const char *tx_name, char **f_source); -Bool gf_gl_txw_setup(GF_GLTextureWrapper *tx, u32 pix_fmt, u32 width, u32 height, u32 stride, u32 uv_stride, Bool linear_interp, struct _gf_filter_frame_interface *frame_ifce); +Bool gf_gl_txw_insert_fragment_shader(u32 pix_fmt, const char *tx_name, char **f_source, Bool y_flip); +Bool gf_gl_txw_setup(GF_GLTextureWrapper *tx, u32 pix_fmt, u32 width, u32 height, u32 stride, u32 uv_stride, Bool linear_interp, struct _gf_filter_frame_interface *frame_ifce, Bool full_range, s32 matrix_coef_or_neg); Bool gf_gl_txw_upload(GF_GLTextureWrapper *tx, const u8 *data, struct _gf_filter_frame_interface *frame_ifce); Bool gf_gl_txw_bind(GF_GLTextureWrapper *tx, const char *tx_name, u32 gl_program, u32 texture_unit); void gf_gl_txw_reset(GF_GLTextureWrapper *tx); diff --git a/include/gpac/utf.h b/include/gpac/utf.h index 40f0003..b44de3a 100644 --- a/include/gpac/utf.h +++ b/include/gpac/utf.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2019 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / common tools sub-project @@ -49,6 +49,8 @@ The wide characters in GPAC are unsignad shorts, in other words GPAC only suppor #include +/*! error code for UTF-8 conversion errors*/ +#define GF_UTF8_FAIL 0xFFFFFFFF /*! \brief wide-char to multibyte conversion @@ -56,9 +58,9 @@ Converts a wide-char string to a multibyte string \param dst multibyte destination buffer \param dst_len multibyte destination buffer size \param srcp address of the wide-char string. This will be set to the next char to be converted in the input buffer if not enough space in the destination, or NULL if conversion was completed. -\return length (in byte) of the multibyte string or -1 if error. +\return length (in byte) of the multibyte string or GF_UTF8_FAIL if error. */ -size_t gf_utf8_wcstombs(char* dst, size_t dst_len, const unsigned short** srcp); +u32 gf_utf8_wcstombs(char* dst, size_t dst_len, const unsigned short** srcp); /*! \brief multibyte to wide-char conversion @@ -67,9 +69,9 @@ Converts a multibyte string to a wide-char string \param dst wide-char destination buffer \param dst_len wide-char destination buffer size \param srcp address of the multibyte character buffer. This will be set to the next char to be converted in the input buffer if not enough space in the destination, or NULL if conversion was completed. -\return length (in unsigned short) of the wide-char string or -1 if error. +\return length (in unsigned short) of the wide-char string or GF_UTF8_FAIL if error. */ -size_t gf_utf8_mbstowcs(unsigned short* dst, size_t dst_len, const char** srcp); +u32 gf_utf8_mbstowcs(unsigned short* dst, size_t dst_len, const char** srcp); /*! \brief wide-char string length @@ -78,19 +80,31 @@ Gets the length in character of a wide-char string \param s the wide-char string \return the wide-char string length */ -size_t gf_utf8_wcslen(const unsigned short *s); +u32 gf_utf8_wcslen(const unsigned short *s); /*! \brief returns a UTF8 string from a string started with BOM -Returns the length in character of a wide-char string +Returns UTF8 from data \param data the string or wide-char string \param size of the data buffer size of the data buffer -\param out_ptr set to an allocated buffer if needed for conversion, shall be destroyed by caller -\return the UTF8 string corresponding +\param out_ptr set to an allocated buffer if needed for conversion, shall be destroyed by caller. Must not be NULL +\param result set to resulting UTF8 string. Must not be NULL +\return error if any: GF_IO_ERR if UTF decode error or GF_BAD_PARAM */ -char *gf_utf_get_utf8_string_from_bom(u8 *data, u32 size, char **out_ptr); +GF_Err gf_utf_get_utf8_string_from_bom(const u8 *data, u32 size, char **out_ptr, char **result); + +/*! +\brief Checks validity of a UTF8 string + +Checks if a given byte sequence is a valid UTF-8 encoding +\param data the byte equence buffer +\param size the length of the byte sequence +\return GF_TRUE if valid UTF8, GF_FALSE otherwise + */ +Bool gf_utf8_is_legal(const u8 *data, u32 size); + /*! \brief string bidi reordering @@ -103,7 +117,7 @@ Performs a simple reordering of words in the string based on each word direction Bool gf_utf8_reorder_bidi(u16 *utf_string, u32 len); /*! maximum character size in bytes*/ -static const size_t UTF8_MAX_BYTES_PER_CHAR = 4; +static const u32 UTF8_MAX_BYTES_PER_CHAR = 4; /*! diff --git a/include/gpac/version.h b/include/gpac/version.h index 9779903..2a58be3 100644 --- a/include/gpac/version.h +++ b/include/gpac/version.h @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2012-2019 + * Copyright (c) Telecom ParisTech 2012-2022 * All rights reserved * * This file is part of GPAC @@ -42,11 +42,13 @@ * SONAME versions must be digits (not strings) */ /*! Macro giving GPAC version name expressed as a printable string*/ -#define GPAC_VERSION "1.0.1" +#define GPAC_VERSION "2.0" + +// WARNING: when bumping, reflect the changes in share/python/libgpac.py !! /*! ABI Major number of libgpac */ -#define GPAC_VERSION_MAJOR 10 +#define GPAC_VERSION_MAJOR 11 /*! ABI Minor number of libgpac */ -#define GPAC_VERSION_MINOR 1 +#define GPAC_VERSION_MINOR 0 /*! ABI Micro number of libgpac */ #define GPAC_VERSION_MICRO 0 @@ -65,6 +67,18 @@ const char *gf_gpac_copyright(); */ const char *gf_gpac_copyright_cite(); +/*!gets libgpac ABI major version +\return major number of libgpac ABI version*/ +u32 gf_gpac_abi_major(); + +/*!gets libgpac ABI minor version +\return minor number of libgpac ABI version*/ +u32 gf_gpac_abi_minor(); + +/*!gets libgpac ABI major version +\return micro number of libgpac ABI version*/ +u32 gf_gpac_abi_micro(); + /*! @} */ #endif //_GF_VERSION_H diff --git a/include/gpac/webvtt.h b/include/gpac/webvtt.h index 46898c7..e4da19c 100644 --- a/include/gpac/webvtt.h +++ b/include/gpac/webvtt.h @@ -110,9 +110,10 @@ GF_Err gf_webvtt_dump_header_boxed(FILE *dump, const u8 *data, u32 dataLength, u \param data the WebVTT ISOBMFF sample payload \param dataLength the size of the payload in bytes \param start the start time in milliseconds of the WebVTT cue +\param end the end time in milliseconds of the WebVTT cue \return new list of cues, to destroy by caller */ -GF_List *gf_webvtt_parse_cues_from_data(const u8 *data, u32 dataLength, u64 start); +GF_List *gf_webvtt_parse_cues_from_data(const u8 *data, u32 dataLength, u64 start, u64 end); /*! @} */ diff --git a/include/gpac/xml.h b/include/gpac/xml.h index 912f87a..902d1d2 100644 --- a/include/gpac/xml.h +++ b/include/gpac/xml.h @@ -51,7 +51,7 @@ This section documents the XML functions (full doc parsing and SAX parsing) of t \ingroup xml_grp \defgroup dom_grp DOM Parsing \ingroup xml_grp -\defgroup xmlb_grp XML Binary Formating +\defgroup xmlb_grp XML Binary Formatting \ingroup xml_grp */ @@ -99,6 +99,8 @@ typedef struct _xml_node GF_List *attributes; /*! list of children nodes of the node, for XML node type only*/ GF_List *content; + /*! original pos in parent (used for DASH MPD)*/ + u32 orig_pos; } GF_XMLNode; /*! @} */ @@ -295,13 +297,28 @@ u32 gf_xml_dom_get_root_nodes_count(GF_DOMParser *parser); */ GF_XMLNode *gf_xml_dom_get_root_idx(GF_DOMParser *parser, u32 idx); +/*! Gets the root node of the document and assign the parser root to NULL. +\param parser the DOM parser to use +\return the root element at the given index, or NULL if error. The element must be freed by the caller +*/ +GF_XMLNode *gf_xml_dom_detach_root(GF_DOMParser *parser); /*! Serialize a node to a string \param node the node to flush \param content_only Whether to include or not the parent node +\param no_escape if set, disable escape of XML reserved chars (<,>,",') in text nodes \return The resulting serialization. The string has to be freed with gf_free */ -char *gf_xml_dom_serialize(GF_XMLNode *node, Bool content_only); +char *gf_xml_dom_serialize(GF_XMLNode *node, Bool content_only, Bool no_escape); + + +/*! Serialize a root document node - same as \ref gf_xml_dom_serialize but insert \code \endcode at beginning +\param node the node to flush +\param content_only Whether to include or not the parent node +\param no_escape if set, disable escape of XML reserved chars (<,>,",') in text nodes +\return The resulting serialization. The string has to be freed with gf_free + */ +char *gf_xml_dom_serialize_root(GF_XMLNode *node, Bool content_only, Bool no_escape); /*! Get the root element -- the only top level element -- of the document. \param parser the DOM structure @@ -324,17 +341,6 @@ GF_XMLAttribute *gf_xml_dom_create_attribute(const char* name, const char* value */ GF_Err gf_xml_dom_append_child(GF_XMLNode *node, GF_XMLNode *child); -/*! -\brief Removes the node to the list of children of this node. - -Removes the node to the list of children of this node. -\warning Doesn't free the memory of the removed children. - -\param node the GF_XMLNode node -\param child the GF_XMLNode child to remove -\return Error code if any, otherwise GF_OK - */ -GF_Err gf_xml_dom_rem_child(GF_XMLNode *node, GF_XMLNode *child); /*! Destroys a node, its attributes and its children @@ -342,6 +348,14 @@ GF_Err gf_xml_dom_rem_child(GF_XMLNode *node, GF_XMLNode *child); */ void gf_xml_dom_node_del(GF_XMLNode *node); +/*! Reset a node + +\param node the node to reset +\param reset_attribs if GF_TRUE, reset all node attributes +\param reset_children if GF_TRUE, reset all node children + */ +void gf_xml_dom_node_reset(GF_XMLNode *node, Bool reset_attribs, Bool reset_children); + /*! Gets the element and check that the namespace is known ('xmlns'-only supported for now) \param n the node to process diff --git a/manifest.rc b/manifest.rc new file mode 100644 index 0000000..5d68078 --- /dev/null +++ b/manifest.rc @@ -0,0 +1 @@ +1 24 "build/msvc14/gpac_manifest.xml" \ No newline at end of file diff --git a/mkdmg.sh b/mkdmg.sh index 0332efa..a85b7fd 100755 --- a/mkdmg.sh +++ b/mkdmg.sh @@ -69,12 +69,13 @@ install_name_tool -change ../bin/gcc/libgpac.dylib @executable_path/lib/libgpac. cd ../../../.. -echo Copying GUI +echo Copying shared resources rsync -r --exclude=.git $source_path/share/res ./tmpdmg/GPAC.app/Contents/MacOS/share/ rsync -r --exclude=.git $source_path/share/gui ./tmpdmg/GPAC.app/Contents/MacOS/share/ rsync -r --exclude=.git $source_path/share/vis ./tmpdmg/GPAC.app/Contents/MacOS/share/ rsync -r --exclude=.git $source_path/share/shaders ./tmpdmg/GPAC.app/Contents/MacOS/share/ rsync -r --exclude=.git $source_path/share/scripts ./tmpdmg/GPAC.app/Contents/MacOS/share/ +rsync -r --exclude=.git $source_path/share/python ./tmpdmg/GPAC.app/Contents/MacOS/share/ cp $source_path/share/default.cfg ./tmpdmg/GPAC.app/Contents/MacOS/share/ echo Building DMG @@ -94,7 +95,7 @@ then full_version="$full_version-rev$rev" else #if no revision can be extracted, use date - $rev = $(date +%Y%m%d) + rev = $(date +%Y%m%d) fi sed 's/.*<\/string>/'"$version"'<\/string>/' tmpdmg/GPAC.app/Contents/Info.plist > tmpdmg/GPAC.app/Contents/Info.plist.new && sed 's/.*<\/string>/'"$rev"'<\/string>/' tmpdmg/GPAC.app/Contents/Info.plist.new > tmpdmg/GPAC.app/Contents/Info.plist && rm tmpdmg/GPAC.app/Contents/Info.plist.new diff --git a/modules/dektec_out/dektec_video_decl.c b/modules/dektec_out/dektec_video_decl.c index 5766a9f..b81c4fc 100644 --- a/modules/dektec_out/dektec_video_decl.c +++ b/modules/dektec_out/dektec_video_decl.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Romain Bouqueau, Jean Le Feuvre -* Copyright (c) 2014-2016 GPAC Licensing +* Copyright (c) 2014-2022 GPAC Licensing * Copyright (c) 2016-2020 Telecom Paris * All rights reserved * @@ -32,6 +32,10 @@ #else #define OFFS(_n) #_n, -1 +static GF_Err dtout_config_dummy(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) +{ + return GF_OK; +} static GF_Err dtout_process_dummy(GF_Filter *filter) { return GF_OK; @@ -40,12 +44,12 @@ static GF_Err dtout_process_dummy(GF_Filter *filter) static const GF_FilterArgs DTOutArgs[] = { - { OFFS(bus), "PCI bus number - if not set, device discovery is used", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_EXPERT}, - { OFFS(slot), "PCI bus number - if not set, device discovery is used", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_EXPERT }, + { OFFS(bus), "PCI bus number. If not set, device discovery is used", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_EXPERT}, + { OFFS(slot), "PCI bus number. If not set, device discovery is used", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_EXPERT }, { OFFS(fps), "default FPS to use if input stream fps cannot be detected", GF_PROP_FRACTION, "30/1", NULL, GF_FS_ARG_HINT_ADVANCED }, { OFFS(clip), "clip YUV data to valid SDI range, slower", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED }, { OFFS(port), "set sdi output port of card", GF_PROP_UINT, "1", NULL, GF_FS_ARG_HINT_ADVANCED }, - { OFFS(start), "set playback start offset, [-1, 0] means percent of media dur, eg -1 == dur", GF_PROP_DOUBLE, "0.0", NULL, GF_FS_ARG_HINT_NORMAL }, + { OFFS(start), "set playback start offset, [-1, 0] means percent of media dur, e.g. -1 == dur", GF_PROP_DOUBLE, "0.0", NULL, GF_FS_ARG_HINT_NORMAL }, { 0 } }; @@ -100,9 +104,11 @@ GF_FilterRegister *dtout_register(GF_FilterSession *session) DTOutRegister.configure_pid = dtout_configure_pid; DTOutRegister.process = dtout_process; #else + DTOutRegister.configure_pid = dtout_config_dummy; DTOutRegister.process = dtout_process_dummy; #ifdef GPAC_ENABLE_COVERAGE + dtout_config_dummy(NULL, NULL, GF_FALSE); dtout_process_dummy(NULL); #endif diff --git a/modules/dektec_out/out_dektec.vcxproj b/modules/dektec_out/out_dektec.vcxproj index 859a1e1..fc6f56d 100644 --- a/modules/dektec_out/out_dektec.vcxproj +++ b/modules/dektec_out/out_dektec.vcxproj @@ -132,6 +132,7 @@ $(IntDir)$(TargetFileName).embed.manifest + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) true @@ -177,6 +178,7 @@ $(IntDir)$(TargetFileName).embed.manifest + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) true @@ -227,6 +229,9 @@ true $(IntDir)$(ProjectName).bsc + + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) + @@ -270,6 +275,9 @@ true $(IntDir)$(ProjectName).bsc + + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) + diff --git a/modules/droid_out/droid_vout.c b/modules/droid_out/droid_vout.c index 734db28..5ae1113 100644 --- a/modules/droid_out/droid_vout.c +++ b/modules/droid_out/droid_vout.c @@ -814,7 +814,7 @@ static GF_Err droid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) static GF_Err droid_SetFullScreen(GF_VideoOutput *dr, Bool bOn, u32 *outWidth, u32 *outHeight) { - RAWCTX;; + RAWCTX; *outWidth = dr->max_screen_width; *outHeight = dr->max_screen_height; diff --git a/modules/dx_hw/dx_hw.rc b/modules/dx_hw/dx_hw.rc index d49b695..936bd06 100644 --- a/modules/dx_hw/dx_hw.rc +++ b/modules/dx_hw/dx_hw.rc @@ -7,19 +7,17 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include "windows.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// Français (France) resources +// French (France) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) -#ifdef _WIN32 LANGUAGE LANG_FRENCH, SUBLANG_FRENCH #pragma code_page(1252) -#endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -32,13 +30,18 @@ BEGIN "resource.h\0" END - 3 TEXTINCLUDE BEGIN "\r\n" "\0" END +2 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + #endif // APSTUDIO_INVOKED @@ -48,8 +51,10 @@ END // IDC_HAND_PTR CURSOR "hand.cur" + IDC_COLLIDE CURSOR "collide.cur" + ///////////////////////////////////////////////////////////////////////////// // // Icon @@ -58,7 +63,8 @@ IDC_COLLIDE CURSOR "collide.cur" // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_OSMO_ICON ICON "../../share/doc/osmo4.ico" -#endif // Français (France) resources + +#endif // French (France) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/modules/dx_hw/dx_window.c b/modules/dx_hw/dx_window.c index 81f8e35..4a1bdd9 100644 --- a/modules/dx_hw/dx_window.c +++ b/modules/dx_hw/dx_window.c @@ -605,7 +605,9 @@ static void SetWindowless(GF_VideoOutput *vout, HWND hWnd) return; #else /* use VerifyVersionInfo() instead of GetVersionEx? */ +#if !defined(__GNUC__) #pragma warning(disable : 4996) +#endif const char *opt; u32 a, r, g, b; COLORREF ckey; diff --git a/modules/ft_font/ft_font.c b/modules/ft_font/ft_font.c index f59e5b4..7b537e2 100644 --- a/modules/ft_font/ft_font.c +++ b/modules/ft_font/ft_font.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2012 + * Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / FreeType font engine module @@ -56,6 +56,7 @@ typedef struct /*default fonts*/ char *font_serif, *font_sans, *font_fixed, *font_default; + Bool cache_checked; } FTBuilder; static const char * BEST_FIXED_FONTS[] = { @@ -123,7 +124,7 @@ static Bool ft_enum_fonts(void *cbck, char *file_name, char *file_path, GF_FileE GF_FontReader *dr = cbck; FTBuilder *ftpriv = dr->udta; - GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Enumerating font %s (%s)\n", file_name, file_path)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[FreeType] Enumerating font %s (%s)\n", file_name, file_path)); if (FT_New_Face(ftpriv->library, file_path, 0, & face )) return 0; if (!face || !face->family_name) return 0; @@ -198,7 +199,7 @@ static Bool ft_enum_fonts(void *cbck, char *file_name, char *file_path, GF_FileE static Bool ft_enum_fonts_dir(void *cbck, char *file_name, char *file_path, GF_FileEnumInfo *file_info) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Scanning directory %s (%s)\n", file_name, file_path)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[FreeType] Scanning directory %s (%s)\n", file_name, file_path)); gf_enum_directory(file_path, 0, ft_enum_fonts, cbck, "ttf;ttc"); return (gf_enum_directory(file_path, 1, ft_enum_fonts_dir, cbck, NULL)==GF_OK) ? GF_FALSE : GF_TRUE; } @@ -209,9 +210,12 @@ static void ft_rescan_fonts(GF_FontReader *dr) u32 i, count; FTBuilder *ftpriv = (FTBuilder *)dr->udta; - GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Rescaning %d font directories\n", gf_list_count(ftpriv->font_dirs) )); + ftpriv->cache_checked = GF_TRUE; + + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[FreeType] Rescaning %d font directories\n", gf_list_count(ftpriv->font_dirs) )); gf_opts_del_section("FontCache"); + gf_opts_del_section("temp_freetype"); gf_opts_set_key("core", "rescan-fonts", "no"); if (ftpriv->font_fixed) gf_free(ftpriv->font_fixed); @@ -297,7 +301,7 @@ static void ft_rescan_fonts(GF_FontReader *dr) gf_opts_set_key("FontCache", "FontSerif", ftpriv->font_serif); gf_opts_set_key("FontCache", "FontSans", ftpriv->font_sans); - GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Font directories scanned\n")); + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[FreeType] Font directories scanned\n")); } @@ -305,20 +309,31 @@ static void ft_rescan_fonts(GF_FontReader *dr) static GF_Err ft_init_font_engine(GF_FontReader *dr) { const char *sOpt; - Bool rescan = GF_FALSE; + u32 rescan = 0; + GF_Err e; FTBuilder *ftpriv = (FTBuilder *)dr->udta; - sOpt = gf_opts_get_key("core", "font-dirs"); - if (!sOpt) { - GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[FreeType] No fonts directory indicated!")); - return GF_BAD_PARAM; - } /*inits freetype*/ if (FT_Init_FreeType(&ftpriv->library) ) { - GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[FreeType] Cannot initialize FreeType\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[FreeType] Cannot initialize FreeType\n")); return GF_IO_ERR; } + if (!gf_opts_get_key_count("FontCache")) + rescan = 1; + else { + sOpt = gf_opts_get_key("core", "rescan-fonts"); + if (!sOpt || !strcmp(sOpt, "yes") ) + rescan = 1; + } + +rescan_font_dirs: + sOpt = gf_opts_get_key("core", "font-dirs"); + if (!sOpt) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[FreeType] No fonts directory indicated!")); + return GF_BAD_PARAM; + } + while (sOpt) { char dir[GF_MAX_PATH]; char *sep = (char *) strchr(sOpt, ','); @@ -341,14 +356,8 @@ static GF_Err ft_init_font_engine(GF_FontReader *dr) sep[0] = ','; sOpt = sep+1; } - if (!gf_opts_get_key_count("FontCache")) - rescan = GF_TRUE; - else { - sOpt = gf_opts_get_key("core", "rescan-fonts"); - if (!sOpt || !strcmp(sOpt, "yes") ) - rescan = GF_TRUE; - } +rescan_fonts: if (rescan) ft_rescan_fonts(dr); @@ -366,7 +375,53 @@ static GF_Err ft_init_font_engine(GF_FontReader *dr) sOpt = gf_opts_get_key("FontCache", "FontFixed"); ftpriv->font_fixed = gf_strdup(sOpt ? sOpt : ""); } - GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Init OK - %d font directory (first %s)\n", gf_list_count(ftpriv->font_dirs), gf_list_get(ftpriv->font_dirs, 0) )); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[FreeType] Init OK - %d font directory (first %s)\n", gf_list_count(ftpriv->font_dirs), gf_list_get(ftpriv->font_dirs, 0) )); + + e = dr->set_font(dr, ftpriv->font_serif, 0); + if (!e) e = dr->set_font(dr, ftpriv->font_sans, 0); + if (!e) e = dr->set_font(dr, ftpriv->font_fixed, 0); + if (!e) return GF_OK; + + if (rescan==3) + return e; + + if (ftpriv->font_serif) gf_free(ftpriv->font_serif); + ftpriv->font_serif = NULL; + if (ftpriv->font_sans) gf_free(ftpriv->font_sans); + ftpriv->font_sans = NULL; + if (ftpriv->font_fixed) gf_free(ftpriv->font_fixed); + ftpriv->font_fixed = NULL; + + //error and we rescanned font dirs, restore default fonts + if (e && ftpriv->cache_checked) + rescan = 2; + + if (!rescan) { + sOpt = gf_opts_get_key("core", "font-dirs"); + rescan = 2; + if (sOpt) { + GF_LOG(GF_LOG_WARNING, GF_LOG_MODULE, ("[FreeType] Default fonts not valid, rescanning font directories %s\n", sOpt)); + goto rescan_fonts; + } + } + if (rescan==2) { + void gf_get_default_font_dir(char szPath[GF_MAX_PATH]); + + char szPath[GF_MAX_PATH]; + //check if font directory is default one, if not reset and rescan + gf_get_default_font_dir(szPath); + sOpt = gf_opts_get_key("core", "font-dirs"); + if (sOpt && !strcmp(sOpt, szPath)) + return e; + + GF_LOG(GF_LOG_WARNING, GF_LOG_MODULE, ("[FreeType] No fonts found in %s, restoring default directories %s and rescanning\n", sOpt, szPath)); + gf_opts_set_key("core", "font-dirs", szPath); + rescan = 3; + while (gf_list_count(ftpriv->font_dirs)) { + gf_free(gf_list_pop_back(ftpriv->font_dirs)); + } + goto rescan_font_dirs; + } return GF_OK; } @@ -441,6 +496,7 @@ static GF_Err ft_set_font(GF_FontReader *dr, const char *OrigFontName, u32 style char *fname; char *fontName; const char *opt; + Bool is_def_font = GF_FALSE; FTBuilder *ftpriv = (FTBuilder *)dr->udta; fontName = (char *) OrigFontName; @@ -451,21 +507,33 @@ static GF_Err ft_set_font(GF_FontReader *dr, const char *OrigFontName, u32 style if (!fontName || !strlen(fontName) || !stricmp(fontName, "SERIF")) { fontName = ftpriv->font_serif; + is_def_font = GF_TRUE; + OrigFontName = ""; } else if (!stricmp(fontName, "SANS") || !stricmp(fontName, "sans-serif")) { fontName = ftpriv->font_sans; + is_def_font = GF_TRUE; + OrigFontName = "SANS"; } else if (!stricmp(fontName, "TYPEWRITER") || !stricmp(fontName, "monospace")) { fontName = ftpriv->font_fixed; + is_def_font = GF_TRUE; + OrigFontName = "TYPEWRITER"; } /*first look in loaded fonts*/ ftpriv->active_face = ft_font_in_cache(ftpriv, fontName, styles); if (ftpriv->active_face) return GF_OK; - /*check cfg file - gf_free(type is slow at loading fonts so we keep the (font name + styles)=fontfile associations - in the cfg file*/ - if (!fontName || !strlen(fontName)) return GF_NOT_SUPPORTED; + //we likely have a problem with the font cache, rebuild if + if (!fontName || !strlen(fontName)) { + if (is_def_font && !ftpriv->cache_checked) { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[FreeType] No default font set, rescanning fonts\n")); + ft_rescan_fonts(dr); + return ft_set_font(dr, OrigFontName, styles); + } + return GF_NOT_SUPPORTED; + } fname = gf_malloc(sizeof(char) * (strlen(fontName) + 50)); { @@ -500,7 +568,7 @@ checkFont: } } - GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Font %s (%s) not found\n", fontName, fname)); + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[FreeType] Font %s (%s) not found\n", fontName, fname)); gf_free(fname); gf_opts_set_key("temp_freetype", OrigFontName, "not found"); return GF_NOT_SUPPORTED; @@ -525,7 +593,6 @@ static GF_Err ft_get_font_info(GF_FontReader *dr, char **font_name, u32 *em_size static GF_Err ft_get_glyphs(GF_FontReader *dr, const char *utf_string, u32 *glyph_buffer, u32 *io_glyph_buffer_size, const char *xml_lang, Bool *is_rtl) { - size_t _len; u32 len; u32 i; u16 *conv; @@ -545,9 +612,8 @@ static GF_Err ft_get_glyphs(GF_FontReader *dr, const char *utf_string, u32 *glyp *io_glyph_buffer_size = len+1; return GF_BUFFER_TOO_SMALL; } - _len = gf_utf8_mbstowcs((u16*) glyph_buffer, *io_glyph_buffer_size, (const char **) &utf8); - if (_len==(size_t)-1) return GF_IO_ERR; - len = (u32) _len; + len = gf_utf8_mbstowcs((u16*) glyph_buffer, *io_glyph_buffer_size, (const char **) &utf8); + if (len == GF_UTF8_FAIL) return GF_IO_ERR; if (utf8) return GF_IO_ERR; /*perform bidi relayout*/ @@ -634,7 +700,7 @@ static GF_Glyph *ft_load_glyph(GF_FontReader *dr, u32 glyph_name) glyph_idx = FT_Get_Char_Index(ftpriv->active_face, glyph_name); /*missing glyph*/ if (!glyph_idx) { - GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[FreeType] Glyph not found for char %d in font %s (style %s)\n", glyph_name, ftpriv->active_face->family_name, ftpriv->active_face->style_name)); + GF_LOG(GF_LOG_WARNING, GF_LOG_MODULE, ("[FreeType] Glyph not found for char %d in font %s (style %s)\n", glyph_name, ftpriv->active_face->family_name, ftpriv->active_face->style_name)); return NULL; } diff --git a/modules/jack/jack.c b/modules/jack/jack.c index a869d1e..cc73226 100644 --- a/modules/jack/jack.c +++ b/modules/jack/jack.c @@ -331,6 +331,7 @@ Jack_Configure(GF_AudioOutput * dr, u32 * SampleRate, u32 * NbChannels, u32 *aud i++; } } + jack_free (matching_outputs); } ctx->isActive = GF_TRUE; } diff --git a/modules/sdl_out/video.c b/modules/sdl_out/video.c index a570b8e..1502d3e 100644 --- a/modules/sdl_out/video.c +++ b/modules/sdl_out/video.c @@ -2,7 +2,7 @@ * GPAC - Multimedia Framework C SDK * * Authors: Jean Le Feuvre - Romain Bouqueau -* Copyright (c) Telecom ParisTech 2000-2020 +* Copyright (c) Telecom ParisTech 2000-2022 * All rights reserved * * This file is part of GPAC / SDL audio and video module @@ -731,8 +731,10 @@ static Bool SDLVid_InitializeWindow(SDLVidCtx *ctx, GF_VideoOutput *dr) #if SDL_VERSION_ATLEAST(1, 2, 10) vinf = SDL_GetVideoInfo(); - dr->max_screen_width = vinf->current_w; - dr->max_screen_height = vinf->current_h; + if (vinf) { + dr->max_screen_width = vinf->current_w; + dr->max_screen_height = vinf->current_h; + } dr->max_screen_bpp = 8; #else { @@ -1553,7 +1555,7 @@ static GF_Err SDLVid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) break; case GF_EVENT_SHOWHIDE: /*the only way to have proper show/hide with SDL is to shutdown the video system and reset it up - which we don't want to do since the setup MUST occur in the rendering thread for some configs (openGL)*/ + which we don't want to do since the setup MUST occur in the rendering thread for some configs (OpenGL)*/ return GF_NOT_SUPPORTED; case GF_EVENT_SIZE: { @@ -1776,9 +1778,12 @@ static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window break; case GF_PIXEL_YUV: pool = &ctx->pool_yuv; - format=SDL_PIXELFORMAT_YV12; format=SDL_PIXELFORMAT_IYUV; break; + case GF_PIXEL_YVU: + pool = &ctx->pool_yuv; + format=SDL_PIXELFORMAT_YV12; + break; case GF_PIXEL_YUV422: case GF_PIXEL_YUV444: case GF_PIXEL_YUV444_10: diff --git a/modules/test_filter/Makefile b/modules/test_filter/Makefile new file mode 100644 index 0000000..d8b53d5 --- /dev/null +++ b/modules/test_filter/Makefile @@ -0,0 +1,43 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/modules/test_filter + +CFLAGS=-I"$(SRC_PATH)/include" $(OPTFLAGS) + +ifeq ($(DEBUGBUILD),yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD),yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS=test_filter.o + +SRCS := $(OBJS:.o=.c) + +LIB=gf_test_filter$(DYN_LIB_SUFFIX) + + +all: $(LIB) + +$(LIB): $(OBJS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) $(LDFLAGS) -L../../bin/gcc -lgpac + + +clean: + rm -f $(OBJS) ../../bin/gcc/$(LIB) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/modules/test_filter/test_filter.c b/modules/test_filter/test_filter.c new file mode 100644 index 0000000..bdc53fc --- /dev/null +++ b/modules/test_filter/test_filter.c @@ -0,0 +1,115 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2010-2021 + * All rights reserved + * + * This file is part of GPAC / test sink filter + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include + + +typedef struct +{ + Bool opt1; +} TestContext; + + +static GF_Err testfilter_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) +{ + TestContext *ctx = (TestContext *)gf_filter_get_udta(filter); + //if first time we see the pid, send a play event + TestContext *pctx = (TestContext *)gf_filter_pid_get_udta(pid); + if (!pctx && !is_remove) { + GF_FilterEvent evt; + gf_filter_pid_set_udta(pid, ctx); + GF_FEVT_INIT(evt, GF_FEVT_PLAY, pid); + gf_filter_pid_send_event(pid, &evt); + } + + return GF_OK; +} + + +static Bool testfilter_process_event(GF_Filter *filter, const GF_FilterEvent *fevt) +{ + return GF_FALSE; +} + + +static GF_Err testfilter_process(GF_Filter *filter) +{ + u32 i, count = gf_filter_get_ipid_count(filter); + for (i = 0; i < count; i++) { + GF_FilterPid *pid = gf_filter_get_ipid(filter, i); + GF_FilterPacket *pck = gf_filter_pid_get_packet(pid); + gf_filter_pid_drop_packet(pid); + } + return GF_OK; +} + +static GF_Err testfilter_initialize(GF_Filter *filter) +{ + TestContext *ctx = (TestContext *) gf_filter_get_udta(filter); + return GF_OK; +} + +static void testfilter_finalize(GF_Filter *filter) +{ + TestContext *ctx = (TestContext *) gf_filter_get_udta(filter); +} + +static const GF_FilterCapability TestFilterCaps[] = +{ + //anything but file + CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE) +}; + +#define OFFS(_n) #_n, offsetof(TestContext, _n) + +static const GF_FilterArgs TestFilterArgs[] = +{ + { OFFS(opt1), "some boolean option", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED}, + {0} +}; + +GF_FilterRegister TestFilterRegister = { + .name = "testfilter", + GF_FS_SET_DESCRIPTION("Test Filter") + GF_FS_SET_HELP("This filter tests loading of filters from dynmaic libraries") + .private_size = sizeof(TestContext), + SETCAPS(TestFilterCaps), + .args = TestFilterArgs, + .initialize = testfilter_initialize, + .finalize = testfilter_finalize, + .configure_pid = testfilter_configure_pid, + .process = testfilter_process, + .process_event = testfilter_process_event, +}; + +GPAC_MODULE_EXPORT +GF_FilterRegister *RegisterFilter(GF_FilterSession *session) +{ + return &TestFilterRegister; +} + diff --git a/modules/test_filter/test_filter.vcxproj b/modules/test_filter/test_filter.vcxproj new file mode 100644 index 0000000..a5e1749 --- /dev/null +++ b/modules/test_filter/test_filter.vcxproj @@ -0,0 +1,292 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {042D3628-67F3-4B6C-8CC0-CD9AFA526974} + test_filter + 8.1 + test_filter + + + + DynamicLibrary + false + MultiByte + v140 + + + DynamicLibrary + false + MultiByte + v140 + + + DynamicLibrary + false + MultiByte + v140 + + + DynamicLibrary + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ../../bin/$(Platform)\$(Configuration)/ + ../../bin/$(Platform)\$(Configuration)/ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + true + true + true + true + ../../bin/$(Platform)\$(Configuration)/ + ../../bin/$(Platform)\$(Configuration)/ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + false + gf_$(ProjectName) + gf_$(ProjectName) + gf_$(ProjectName) + gf_$(ProjectName) + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\obj/test_filter_deb/test_filter.tlb + + + + + Disabled + ../../include;../../extra_lib/include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + $(IntDir)$(ProjectName).pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + + + true + $(IntDir)gf_$(ProjectName).pdb + $(IntDir)gf_$(ProjectName).lib + MachineX86 + + + $(IntDir)$(TargetFileName).embed.manifest + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) + + + true + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\obj/test_filter_deb/test_filter.tlb + + + + + Disabled + ../../include;../../extra_lib/include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + $(IntDir)$(ProjectName).pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + + + true + $(IntDir)gf_$(ProjectName).pdb + $(IntDir)gf_$(ProjectName).lib + + + $(IntDir)$(TargetFileName).embed.manifest + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\obj/test_filter_rel/test_filter.tlb + + + + + MaxSpeed + OnlyExplicitInline + ../../include;../../extra_lib/include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + $(IntDir)$(ProjectName).pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + + + $(IntDir)gf_$(ProjectName).pdb + $(IntDir)gf_$(ProjectName).lib + MachineX86 + + + true + $(IntDir)$(ProjectName).bsc + + + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\obj/test_filter_rel/test_filter.tlb + + + + + Full + AnySuitable + ../../include;../../extra_lib/include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + $(IntDir)$(ProjectName).pch + $(IntDir) + $(IntDir) + $(IntDir) + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + + + $(IntDir)gf_$(ProjectName).pdb + $(IntDir)gf_$(ProjectName).lib + + + true + $(IntDir)$(ProjectName).bsc + + + $(SolutionDir)gpac_manifest.xml %(AdditionalManifestFiles) + + + + + + + + + {d3540754-e0cf-4604-ac11-82de9bd4d814} + + + + + + \ No newline at end of file diff --git a/modules/validator/validator.c b/modules/validator/validator.c index f2c74d3..1159bf2 100644 --- a/modules/validator/validator.c +++ b/modules/validator/validator.c @@ -1,8 +1,8 @@ /* * GPAC - Multimedia Framework C SDK * - * Authors: Cyril Concolato - * Copyright (c) Telecom ParisTech 2010-2020 + * Authors: Cyril Concolato, Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2010-2022 * All rights reserved * * This file is part of GPAC / Test Suite Validator Recorder sub-project @@ -84,7 +84,7 @@ static void validator_xvs_add_snapshot_node(GF_Validator *validator, const char GF_XMLAttribute *att; GF_SAFEALLOC(snap_node, GF_XMLNode); if (!snap_node) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate snapshot\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate snapshot\n")); return; } snap_node->name = gf_strdup("snapshot"); @@ -92,7 +92,7 @@ static void validator_xvs_add_snapshot_node(GF_Validator *validator, const char att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate snapshot\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate snapshot\n")); return; } att->name = gf_strdup("time"); @@ -102,7 +102,7 @@ static void validator_xvs_add_snapshot_node(GF_Validator *validator, const char att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate snapshot\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate snapshot\n")); return; } att->name = gf_strdup("image"); @@ -113,7 +113,7 @@ static void validator_xvs_add_snapshot_node(GF_Validator *validator, const char /* adding an extra text node for line break in serialization */ GF_SAFEALLOC(snap_node, GF_XMLNode); if (!snap_node) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate snapshot\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate snapshot\n")); return; } snap_node->type = GF_XML_TEXT_TYPE; @@ -331,7 +331,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event GF_SAFEALLOC(evt_node, GF_XMLNode); if (!evt_node) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event\n")); return; } @@ -361,7 +361,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event time\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event time\n")); return; } att->name = gf_strdup("time"); @@ -380,7 +380,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->type == GF_EVENT_MOUSEDOWN || event->type == GF_EVENT_MOUSEUP) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("button"); @@ -399,7 +399,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event } att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("x"); @@ -409,7 +409,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("y"); @@ -419,7 +419,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->type == GF_EVENT_MOUSEWHEEL) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("wheel_pos"); @@ -430,7 +430,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->mouse.key_states & GF_KEY_MOD_SHIFT) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("shift"); @@ -440,7 +440,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->mouse.key_states & GF_KEY_MOD_CTRL) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("ctrl"); @@ -450,7 +450,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->mouse.key_states & GF_KEY_MOD_ALT) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("alt"); @@ -464,7 +464,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event case GF_EVENT_LONGKEYPRESS: att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("key_identifier"); @@ -475,7 +475,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->key.flags & GF_KEY_MOD_SHIFT) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("shift"); @@ -485,7 +485,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->key.flags & GF_KEY_MOD_CTRL) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("ctrl"); @@ -495,7 +495,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event if (event->key.flags & GF_KEY_MOD_ALT) { att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("alt"); @@ -506,7 +506,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event case GF_EVENT_TEXTINPUT: att = (GF_XMLAttribute *) gf_malloc(sizeof(GF_XMLAttribute)); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event info\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event info\n")); return; } att->name = gf_strdup("unicode-char"); @@ -519,7 +519,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event /* adding an extra text node for line break in serialization */ GF_SAFEALLOC(evt_node, GF_XMLNode); if (!evt_node) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate event\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate event\n")); return; } evt_node->type = GF_XML_TEXT_TYPE; @@ -632,7 +632,7 @@ static void validator_xvl_close(GF_Validator *validator) char *xvl_content; char result_filename[GF_MAX_PATH]; char *dot; - xvl_content = gf_xml_dom_serialize(validator->xvl_node, GF_FALSE); + xvl_content = gf_xml_dom_serialize(validator->xvl_node, GF_FALSE, GF_FALSE); dot = gf_file_ext_start(validator->xvl_filename); dot[0] = 0; sprintf(result_filename, "%s-result.xml", validator->xvl_filename); @@ -692,7 +692,7 @@ static Bool validator_xvs_open(GF_Validator *validator) if (validator->is_recording) { GF_SAFEALLOC(validator->xvs_node, GF_XMLNode); if (!validator->xvs_node) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate root node\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate root node\n")); return 0; } @@ -753,7 +753,7 @@ static Bool validator_xvs_open(GF_Validator *validator) /* adding an extra text node for line break in serialization */ GF_SAFEALLOC(node, GF_XMLNode); if (!node) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate node\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate node\n")); return GF_FALSE; } node->type = GF_XML_TEXT_TYPE; @@ -789,7 +789,7 @@ static void validator_xvs_close(GF_Validator *validator) if (!att_file) { GF_SAFEALLOC(att, GF_XMLAttribute); if (!att) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate file attribute\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate file attribute\n")); return; } att->name = gf_strdup("file"); @@ -806,7 +806,7 @@ static void validator_xvs_close(GF_Validator *validator) att->value = gf_strdup(validator->test_filename); } } - xvs_content = gf_xml_dom_serialize(validator->xvs_node, GF_FALSE); + xvs_content = gf_xml_dom_serialize(validator->xvs_node, GF_FALSE, GF_FALSE); xvs_fp = gf_fopen(validator->xvs_filename, "wt"); gf_fwrite(xvs_content, strlen(xvs_content), xvs_fp); gf_fclose(xvs_fp); @@ -831,7 +831,7 @@ static void validator_xvs_close(GF_Validator *validator) if (!att_result) { GF_SAFEALLOC(att_result, GF_XMLAttribute); if (!att_result) { - GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Validator] Failed to allocate result attribute\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Failed to allocate result attribute\n")); return; } att_result->name = gf_strdup("result"); diff --git a/modules/x11_out/x11_out.c b/modules/x11_out/x11_out.c index 5f0c60d..e641dd8 100644 --- a/modules/x11_out/x11_out.c +++ b/modules/x11_out/x11_out.c @@ -137,7 +137,7 @@ static int X11_GetXVideoPort(GF_VideoOutput *vout, u32 pixel_format, Bool check_ formats = XvListImageFormats(xwin->display, adaptors[i].base_id, &num_formats); for (j=0; jdisplay, port, CurrentTime) == Success) { @@ -235,7 +240,7 @@ GF_Err X11_Blit(struct _video_out *vout, GF_VideoSurface *video_src, GF_Window * } /*different size, recreate an image*/ - if ((xwin->overlay->width != video_src->width) || (xwin->overlay->height != video_src->height)) { + if (xwin->overlay && ((xwin->overlay->width != video_src->width) || (xwin->overlay->height != video_src->height))) { XFree(xwin->overlay); xwin->overlay = XvCreateImage(xwin->display, xwin->xvport, xwin->xv_pf_format, NULL, video_src->width, video_src->height); if (!xwin->overlay) return GF_IO_ERR; @@ -1022,6 +1027,13 @@ GF_Err X11_SetFullScreen (struct _video_out * vout, u32 bFullScreenOn, u32 * scr XSetInputFocus(xWindow->display, xWindow->full_wnd, RevertToNone, CurrentTime); XRaiseWindow(xWindow->display, xWindow->full_wnd); XGrabKeyboard(xWindow->display, xWindow->full_wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); + + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_SIZE; + evt.size.width = xWindow->w_width; + evt.size.height = xWindow->w_height; + vout->on_event(vout->evt_cbk_hdl, &evt); } else { *screen_width = xWindow->store_width; *screen_height = xWindow->store_height; @@ -1033,6 +1045,13 @@ GF_Err X11_SetFullScreen (struct _video_out * vout, u32 bFullScreenOn, u32 * scr /*looks like this makes osmozilla crash*/ //if (xWindow->par_wnd) XSetInputFocus(xWindow->display, xWindow->wnd, RevertToNone, CurrentTime); + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_SIZE; + evt.size.width = xWindow->w_width; + evt.size.height = xWindow->w_height; + vout->on_event(vout->evt_cbk_hdl, &evt); + /*backbuffer resize will be done right after this is called */ } #ifdef GPAC_HAS_OPENGL @@ -1159,12 +1178,12 @@ X11_SetupWindow (GF_VideoOutput * vout) break; case 24: #ifdef GPAC_BIG_ENDIAN - if (xWindow->visual->red_mask==0x00FF0000) + if (xWindow->visual->red_mask==0x00FF0000) xWindow->pixel_format = GF_PIXEL_RGB; else xWindow->pixel_format = GF_PIXEL_BGR; #else - if (xWindow->visual->red_mask==0x00FF0000) + if (xWindow->visual->red_mask==0x00FF0000) xWindow->pixel_format = GF_PIXEL_BGR; else xWindow->pixel_format = GF_PIXEL_RGB; diff --git a/packagers/win32_64/nsis/gpac_installer.nsi b/packagers/win32_64/nsis/gpac_installer.nsi index 37868f0..0be1d2b 100644 --- a/packagers/win32_64/nsis/gpac_installer.nsi +++ b/packagers/win32_64/nsis/gpac_installer.nsi @@ -1,6 +1,6 @@ ;-------------------------------- ;General -!define GPAC_VERSION 1.0.1 +!define GPAC_VERSION 2.0 !include default.out !define GPAC_ROOT ..\..\.. @@ -286,13 +286,13 @@ Section "GPAC Player" SecOsmo4 File "${GPAC_BIN}\gm_dx_hw.dll" - ;copy GUI + ;copy shared res SetOutPath $INSTDIR\share File "${GPAC_ROOT}\share\default.cfg" SetOutPath $INSTDIR\share\res - File "${GPAC_ROOT}\share\res\gpac.mp4" - File "${GPAC_ROOT}\share\res\gpac_cfg_test.mp4" - File "${GPAC_ROOT}\share\res\gpac.png" + File /r /x .git ${GPAC_ROOT}\share\res\* + + ;copy GUI SetOutPath $INSTDIR\share\gui File "${GPAC_ROOT}\share\gui\gui.bt" File "${GPAC_ROOT}\share\gui\gui.js" @@ -307,6 +307,10 @@ Section "GPAC Player" SecOsmo4 SetOutPath $INSTDIR\share\scripts File /r /x .git ${GPAC_ROOT}\share\scripts\* + ;copy python + SetOutPath $INSTDIR\share\python + File /r /x .git ${GPAC_ROOT}\share\python\* + ;copy shaders SetOutPath $INSTDIR\share\shaders File /r /x .git ${GPAC_ROOT}\share\shaders\* diff --git a/share/default.cfg b/share/default.cfg index 0f06378..49a3015 100644 --- a/share/default.cfg +++ b/share/default.cfg @@ -3,9 +3,10 @@ -plist=flist:srcs=@{-:N} vout aout -info=src=@{+1:N} inspect -mplay=src=@{+1:N} aout vout --bench=reframer:raw @ -o null -stats -i @{1} +-bench=reframer:raw=av @ -o null -stats -i @{1} -vbench=vout:!vsync -i @{1} -stats -gui=-noprog compositor:player=gui -xopt +-mp4c=-i @{1} compositor:player=base [gpac.aliasdoc] -play=play file. EX: gpac -play source.mp4 -plist=build seamless playlist of files. EX: gpac -plist s1.mp4 [... sN.mp4] @@ -14,3 +15,4 @@ -bench=check decoding speed of source. EX: gpac -bench source.mp4 -vbench=check decoding and display speed of source. EX: gpac -vbench source.mp4 -gui=launch GUI (see `gpac -gui -h` for GUI options and `gpac -h[x] compositor` for compositor options) +-mp4c=launch player without GUI (same as MP4Client) diff --git a/share/doc/CODING_STYLE b/share/doc/CODING_STYLE index fe807d0..06b8fed 100644 --- a/share/doc/CODING_STYLE +++ b/share/doc/CODING_STYLE @@ -32,8 +32,8 @@ For example, error code GF_BAD_PARAM. Enums names shall refer to the main module they are used in through a keyword right after the GF_ . For example, - * enums refering to file format (isomedia) will be prefixed by GF_ISOM_ - * enums refering to MPEG-4 OD tools (odf) will be prefixed by GF_ODF_ + * enums referring to file format (isomedia) will be prefixed by GF_ISOM_ + * enums referring to MPEG-4 OD tools (odf) will be prefixed by GF_ODF_ 1.3 functions diff --git a/share/doc/configuration.html b/share/doc/configuration.html index 547ac31..8251200 100644 --- a/share/doc/configuration.html +++ b/share/doc/configuration.html @@ -9,7 +9,7 @@


GPAC Configuration file documentation -
GPAC Version 1.0.1
+
GPAC Version 2.0



diff --git a/share/doc/doxyfile b/share/doc/doxyfile index d52f26e..9b66b4e 100644 --- a/share/doc/doxyfile +++ b/share/doc/doxyfile @@ -776,7 +776,7 @@ WARN_LOGFILE = doxygen_warnings.txt # Note: If this tag is empty the current directory is searched. #for some weird reason on OSX enumeration does not work properly, add IDL files by hand -INPUT=../../include/gpac/ ../../README.md ../../share/doc/idl/core.idl ../../share/doc/idl/jsf.idl ../../share/doc/idl/xhr.idl ../../share/doc/idl/evg.idl ../../share/doc/idl/scenejs.idl ../../share/doc/idl/storage.idl ../../share/doc/idl/webgl.idl ../../share/doc/idl/filtersession.idl +INPUT=../../include/gpac/ ../../README.md ../../share/doc/idl/core.idl ../../share/doc/idl/jsf.idl ../../share/doc/idl/xhr.idl ../../share/doc/idl/evg.idl ../../share/doc/idl/scenejs.idl ../../share/doc/idl/storage.idl ../../share/doc/idl/webgl.idl ../../share/doc/idl/filtersession.idl ../../share/doc/idl/dash_algo.idl ../../share/doc/idl/nodejs.idl ../../share/python/libgpac.py # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/share/doc/idl/core.idl b/share/doc/idl/core.idl index 9b0ed14..6453787 100644 --- a/share/doc/idl/core.idl +++ b/share/doc/idl/core.idl @@ -80,7 +80,7 @@ WinRect prompt_size(); \param filter the filter for file extensions. If "dir", only enumerate directories \param go_up if true, enumerate parent directory or root (/). \return array of FileInformation interface*/ -Array enum_directory(DOMString dir, optional DOMString filter=null, optional DOMString filter=null, optional bool go_up=false); +Array enum_directory(DOMString dir, optional DOMString filter=null, optional bool go_up=false); /*! get system clock in milliseconds - see \ref gf_sys_clock @@ -93,6 +93,16 @@ unsigned long clock_ms(); */ unsigned long long clock_us(); +/*! sleep for a given time - see \ref gf_sleep +\param sleep sleep value in milliseconds +*/ +void sleep(optional unsigned long sleep = 0); + +/*! exit gpac process +\param ret_code exit return code +*/ +void exit(optional unsigned long ret_code = 0); + /*! convert a 4CC code to its string representation - see \ref gf_4cc_to_str \param value the 4CC code to convert \return string representation @@ -143,12 +153,31 @@ unsigned long long get_utc(); */ unsigned long long get_utc(DOMString date); +/*! gets NTP 64-bit timestamp - see \ref gf_net_get_ntp_ts +\return NTP 64 bit timestamp as fraction, 'n' continaing seconds, 'd' containing fractional part +*/ +Fraction get_ntp(); + + +/*! shifts an NTP 64-bit timestamp by the given number of microseconds +\param ntp source NTP +\param microseconds number of microseconds to add (positive) or remove (negative) +\return adjusted NTP 64 bit timestamp as fraction, 'n' continaing seconds, 'd' containing fractional part +*/ +Fraction ntp_shift(Fraction ntp, long microseconds); + /*! gets CRC32 of an arraybuffer - see \ref gf_crc_32 \param abuf array buffer \return CRC32 of the data */ unsigned long crc32(ArrayBuffer abuf); +/*! gets CRC32 of a string - see \ref gf_crc_32 +\param str string buffer +\return CRC32 of the string +*/ +unsigned long crc32(DOMString str); + /*! gets SHA1 digest of an arraybuffer - see \ref gf_sha1_file \param fname name of file to hash \return ArrayBuffer containing SHA1 of the file data @@ -163,9 +192,10 @@ ArrayBuffer sha1(ArrayBuffer abuf); /*! loads file content into an array buffer - see \ref gf_file_load_data \param fname name of file to load -\return ArrayBuffer containing data of the file +\param as_utf8 load as UTF8 string +\return ArrayBuffer containing data of the file or UTF8 string */ -ArrayBuffer load_file(DOMString fname); +ArrayBuffer load_file(DOMString fname, optional boolean as_utf8=false); /*! compress using deflate() an array buffer \param in_data input data to compress @@ -196,7 +226,7 @@ void mkdir(DOMString dirname); */ boolean dir_exists(DOMString dirname); -/*! remove files in directory - cf \ref gf_cleanup_dir +/*! remove files in directory - cf \ref gf_dir_cleanup \param dirname name of directory */ void dir_clean(DOMString dirname); @@ -230,7 +260,7 @@ void del(DOMString filename); */ unsigned long long mod_time(DOMString filename); -/*! get file modification time - cf \ref gf_file_modification_time +/*! rename/move file - cf \ref gf_file_move \param filename name of file \param newname new name of the file */ @@ -298,6 +328,64 @@ unsigned long ntohl(unsigned long value); */ unsigned long ntohs(unsigned long value); +/*! gets size in bytes of an image of given size and pixel format +\param pix_fmt pixel format name +\param width image width in pixels +\param height image height in pixels +\return size in bytes +*/ +unsigned long pixfmt_size(DOMString pix_fmt, unsigned long width, unsigned long height); + +/*! checks if pixel format is potentially transparent (uses alpha) +\param pcm_fmt PCM format name +\return true if transparent, false otherwise +*/ +unsigned long pixfmt_transparent(DOMString pcm_fmt); + +/*! gets size in bytes of an audio sample in the given format +\param pcm_fmt PCM format name +\return size in bytes +*/ +unsigned long pcmfmt_depth(DOMString pcm_fmt); + + +/*! interpolates colors +\param interp interpolation fraction between 0 and 1 +\param color1 first color to use +\param color2 second color to use +\return component-wise interpolated color, i.e. \code color1.COMP * (1-interp) + color2.comp * interp \endcode +*/ +DOMString color_lerp(double interp, DOMString color1, DOMString color2); + +/*! gets color component +\param color color to use +\param comp_idx component idx, 0 for alpha, 1 for red, 2 for green 3 for blue +\return the component value normalized between 0 and 1 +*/ +double color_component(DOMString color, unsigned long comp_idx); + +/*! concatenates URLs +\param parent parent URL +\param URL URL to concatenate +\return the resolved URL +*/ +DOMString url_cat(DOMString parent, DOMString URL); + +/*! gets union of two rectangles +\param r1 first rectangle +\param r2 second rectangle +\return union rectangle +*/ +Rect rect_union(Rect r1, Rect r2); + +/*! gets intersection of two rectangles +\param r1 first rectangle +\param r2 second rectangle +\return intersection rectangle +*/ +Rect rect_intersect(Rect r1, Rect r2); + + /*! number of cores */ attribute readonly unsigned long nb_cores; @@ -437,7 +525,7 @@ interface FileInformation { boolean system; /*! file size in bytes*/ unsigned long long size; - /*! last modification UTC time*/ + /*! last modification UTC time in microseconds*/ unsigned long long last_modified; }; @@ -481,6 +569,14 @@ void close(); */ unsigned long read(ArrayBuffer buf, optional unsigned long nb_bytes=0); + +/*! seek into file - see \ref gf_fseek +\param offset offset in file +\param whence seek origin +\return -1 if error, 0 otherwise +*/ +long seek(unsigned long long offset, long whence); + /*! get a string from a file, stopping at first new line character found - see \ref gf_fgets \return string read */ @@ -755,6 +851,59 @@ attribute readonly unsigned long long refreshed_size; } +/*! fraction object*/ +interface Fraction { +/*! numerator*/ +long n; +/*! denumerator*/ +unsigned long d; +}; + + +/*! FileIO object + +A FileIO object wraps calls to file IO, allowing the script to feed GPAC files not present on disk, or have GPAC create files in JS memory. + +Whenever a file is opened, a new JS object of type FileIO is created and passed as "this" in the specified open, close, read, write, seek, tell, eof callbacks. + +Any URL relative to the reference URL provided will be solved against the parent FileIO, resulting in additionnals open() calls. + +Warning: this is work in progress +*/ +interface FileIO { + +/*! constructor for a FileIO +\param reference_url the base URL this FileIO wraps +\param open the open function callback, shall not be NULL. The callback is "boolean open(DOMString url, DOMString mode); ", with mode a fopen mode and the return value true indicates success +\param close the close function callback, shall not be NULL. The callback is "close();" +\param write the write function callback, shall not be NULL if read is NULL. The callback is "unsigned long write(ArrayBuffer ab);", where ab is the buffer to write and the return value the number of bytes written +\param read the read function callback, shall not be NULL if write is NULL. The callback is "unsigned long read(ArrayBuffer ab);", where ab is the buffer to fill and the return value the number of bytes read +\param seek the seek function callback, shall not be NULL. The callback is "unsigned long seek(unsigned long long pos, unsigned long whence);", as in \ref gf_fseek +\param tell the seek function callback, shall not be NULL. The callback is "unsigned long long tell();", as in \ref gf_ftell +\param eof the end of file function callback, shall not be NULL. The callback is "boolean eof();", as in \ref gf_feof +\param exists the file existence probing function callback, shall not be NULL. The callback is "boolean exists(DOMString URL);", returns true if file exists (for read access). The "this" object is the constructed FileIO on this callback. +*/ +File(DOMString reference_url, function open, function close, function write, function read, function seek, function tell, function eof, function exists); + +/*! protects the FileIO factory, preventing it to be deleted until destroy is called +This is needded in case a FileIO URL is used several time in a session (re-injecting a source), as libgpac will otherwise destroy the +underlying FileIO factory when no more files are associated with it +*/ +void protect(); + +/*! destroy the underlying FileIO, if not already destroyed. If \ref protect is used, this function MUST be called before exiting gpac*/ +void destroy(); + +/*! get the gfio:// URL associated with the fileIO object */ +attribute readonly DOMString url; + +/*! get the underlying resource URL associated with the fileIO object */ +attribute readonly DOMString resource_url; + +/*! the parent FileIO object (the one constructed by the script) for this FileIO instance*/ +attribute readonly FileIO parent; + +}; diff --git a/share/doc/idl/dash_algo.idl b/share/doc/idl/dash_algo.idl new file mode 100644 index 0000000..07ad1ed --- /dev/null +++ b/share/doc/idl/dash_algo.idl @@ -0,0 +1,252 @@ +/* +\file +\brief silence ! +*/ + +typedef char *DOMString; + +/*! + +\defgroup dash_grp JS DASH Adaptation API +\ingroup jsapi_grp +\brief JavaScript API for DASH client adaptation algorithm. + +This section documents the JavaScript API available for implementing your own adaptation logic in GPAC DASH client. + +The algorithm is chosen using the option `algo` of the dashin filter : +``` +gpac -i source.mpd:algo=myalgo.js vout +//or +gpac -i source.mpd --algo=myalgo.js vout +``` + +The loaded JavaScript context has all JS modules available in GPAC, except WebGL. + +It is also possible to bind the custom agorithm from a JSFilterSession using JSFSFilter.bind +@{ + +*/ + +/*! global context property representing the one and only JSDASHClient object attached to the loaded script*/ +attribute JSDASHClient dashin; + +/*!\brief JSDASHClient API + +The JSDASHClient interface has a single instance exposed to the script under the name "dashin". +It implements callbacks from the DASH client. +The object can also be bound to a running filter using JSFSFilter.bind +*/ +interface JSDASHClient { + +/*! indicate a new group is being created +\note this function is optional +\param group group being created, can be kept for future use +*/ +attribute void new_group(JSDASHGroup group); + +/*! indicate the period has changed +\note this function is optional +\param reset_type indicates the type of reset: + - 0: end of period, groups are no longer valid + - 1: start of a static period + - 2: start of a dynamic (live) period +*/ +attribute void period_reset(unsigned long reset_type); + +/*! perform rate adaptation on the given group (AdaptationSet in DASH, corresponds to one adaptable media) +\param group_idx index of group on which to perform adaptation +\param base_group_idx index of associated base group (usually same as group, differs in tiling mode), +\param force_lower_complexity set to true if the dash client would like a lower complexity +\param stats current statistics for the group JSDASHStats + +\return value can be: +- the index of the new quality to select (as listed in group.reps[]) +- -1 to not take decision now +- -2 to disable the group (debug, will drop segment) +- other negative values are handled as error +*/ +attribute int rate_adaptation(unsigned long group_idx, unsigned long base_group_idx, Boolean force_lower_complexity, JSDASHStats stats); + +/*! monitor download of the current segment in a group +\note this function is optional +\param group_idx index of group on which to perform adaptation +\param stats current download statistics for the group JSDASHDownloadStats + +\return integer value indicating the action to take. Return value can be: +- `-1` to continue download +- `-2` to abort download but without retrying to download the same segment at lower quality +- the index of the new quality to download for the same segment index (same time) +*/ +attribute int download_monitor(unsigned long group_idx, JSDASHDownloadStats stats); + +}; + + +/*!\brief JSDASHGroup API + +The JSDASHGroup object provides a description of a group (AdaptationSet in DASH), and its available qualities. +*/ +interface JSDASHGroup { + +/*! group index, as used in rate_adaptation callback*/ +attribute readonly unsigned long idx; + +/*! group duration in milliseconds, 0 if unknown (live) */ +attribute readonly unsigned long long duration; + + +/*! Spatial Relationship Description, or null if none*/ +attribute readonly JSDASHSRD SRD; + +/*! list of available qualites, array of JSDASHQuality objects*/ +attribute readonly Array qualities; + +}; + +/*!\brief JSDASHQuality Object + +The JSDASHQuality object provides a description of a quality (Representation in DASH). +*/ +interface JSDASHQuality { + +/*! ID (Representation ID) */ +attribute readonly DOMString ID; + +/*! MIME type */ +attribute readonly DOMString mime; + +/*! codec parameter */ +attribute readonly DOMString codec; + +/*! average bitrate in bits per second*/ +attribute readonly unsigned long bitrate; + +/*! if true, the quality is disabled (cannot be played)*/ +attribute readonly boolean disabled; + +/*! video width in pixels*/ +attribute readonly unsigned long width; + +/*! video height in pixels*/ +attribute readonly unsigned long height; + +/*! video frame rate*/ +attribute readonly Fraction fps; + +/*! video sample aspect ratio*/ +attribute readonly Fraction sar; + +/*! audio samplerate*/ +attribute readonly unsigned long samplerate; + +/*! audio number of channels*/ +attribute readonly unsigned long channels; + +/*! DASH AST offset for low-latency, 0 otherwise*/ +attribute readonly double ast_offset; + +/*! size of all segments in this quality for onDemand profiles. If unknown, set to null*/ +attribute readonly Array sizes; +}; + + + +/*!\brief JSDASHStats API + +The JSDASHStats object provides a description of current group state before adaptation logic +*/ +interface JSDASHStats { + +/*! last segment download rate in bits per second*/ +attribute readonly unsigned long rate; + +/*! last segment size in bytes*/ +attribute readonly unsigned long filesize; + +/*! current playback speed*/ +attribute readonly float speed; + +/*! max supported playback speed computed from associated decoder runtime statistics, 0 if unknown*/ +attribute readonly float max_speed; + +/*! display width of the object in pixels, 0 if no video in object*/ +attribute readonly unsigned long display_width; + +/*! display height of the object in pixels, 0 if no video in object*/ +attribute readonly unsigned long display_height; + +/*! index of active quality at the time the algo is run*/ +attribute readonly unsigned long active_quality; + +/*! minimum buffer level in milliseconds below witch rebuffer will happen*/ +attribute readonly unsigned long buffer_min; + +/*! maximum buffer level allowed in milliseconds. Packets won't get dropped if overflow, but the algorithm should try not to overflow this buffer*/ +attribute readonly unsigned long buffer_max; + +/*! current buffer level in milliseconds*/ +attribute readonly unsigned long buffer; +}; + + + +/*!\brief JSDASHDownloadStats API + +The JSDASHDownloadStats object provides a description of current segment download statistics for a group +*/ +interface JSDASHDownloadStats { + +/*! current estimated download speed in bits per second*/ +attribute readonly unsigned long bits_per_second; + +/*! total bytes to download*/ +attribute readonly unsigned long long total_bytes; + +/*! bytes downloaded*/ +attribute readonly unsigned long long bytes_done; + +/*! time in microsecond since segment was scheduled for download*/ +attribute readonly unsigned long long us_since_start; + +/*! buffer duration in milliseconds*/ +attribute readonly unsigned long buffer_duration; + +/*! duration of segment being downloaded, 0 if unknown*/ +attribute readonly unsigned long current_segment_duration; + +}; + + + +/*!\brief JSDASHSRD + +The JSDASHSRD object provides the SRD description of a group. +*/ +interface JSDASHSRD { + +/*! ID of SRD source - all SRD with same source describe the same video composition, possibly with different grid sizes*/ +attribute readonly unsigned long ID; + + +/*! X coordinate of SRD for this tile*/ +attribute readonly long x; + +/*! Y coordinate of SRD for this tile*/ +attribute readonly long y; + +/*! width of SRD for this tile - 0 for tile base track*/ +attribute readonly long w; + +/*! height of SRD for this tile - 0 for tile base track*/ +attribute readonly long h; + +/*! total width of SRD descriptor for this tile*/ +attribute readonly long fw; + +/*! total height of SRD descriptor for this tile*/ +attribute readonly long fh; +}; + + +/*! @} */ + diff --git a/share/doc/idl/evg.idl b/share/doc/idl/evg.idl index 6a26d30..2c5f6ee 100644 --- a/share/doc/idl/evg.idl +++ b/share/doc/idl/evg.idl @@ -36,6 +36,30 @@ Whenever pixel coordinates are indicated, 0,0 indicates: Whenever using an object as a parameter to a function, only the parameter names as listed in the corresponding interface object are checked. The name of the interface is not, and it usually does not define any constructor. \note Although 10-bit raster is supported for YUV formats (framebuffer and textures), colors are internally handled as 8-bits for solid brush and gradients. This will be updated in the near future. + + + + +The 3D extension of Canvas object can be used to draw vectorial 3D meshes and 2D paths. + +\warning The 3D rasterizer is much much slower than WebGL as it is only software and not realy optimized, do not use it for complex 3D scenes. + +\warning The 3D rasterizer is still an experimental project: it might not be completely stable and its API may change a lot in the near future. + + +The 3D rasterizer can however be useful when drawing simple 3D objects over an existing video, as it avoids GPU transfers of the frame data. + +The rasterizer supports: +- points, lines, triangles, quads, strips and fans +- 2D texturing using RGBA or YUVA colorspace +- perspective correct interpolation +- simple antialiasing +- depth buffer (float only) +- rasterizing in YUVA or RGBA space +- a simple shading language for both vertex and fragment processing + +The rasterizer does not claim compliancy to any GPU specification, and will likely produce different results than WebGL. + @{ @@ -73,13 +97,30 @@ writeonly Matrix2D matrix; \note A same path can be drawn several times with different clipper, null means no clipper. Clipper applies to both fill and clear functions*/ writeonly IRect clipper; +/*! true if cliper is active on canvas*/ +readonly boolean has_clipper; + /*! composite operation for alpha surfaces - see \ref gf_evg_surface_set_composite_mode*/ attribute unsigned long compositeOperation; + +/*! AA level of canvas - see \ref gf_evg_surface_get_raster_level and \ref gf_evg_surface_set_raster_level +\note This is always equal to GF_RASTER_HIGH_QUALITY when the path drawn is a text object*/ +attribute unsigned long level; + /*! alpha custom callback composite operation for alpha surfaces - see \ref gf_evg_surface_set_alpha_callback Default is undefined at creation time*/ attribute AlphaCallback on_alpha; + +/*! set to true of canvas is a YUV-based format, false if RGB-based format*/ +readonly attribute boolean is_yuv; + +/*! number of bits per component (8, 10, etc)*/ +readonly attribute unsigned long depth; + + + /*! clears the canvas with the given color - see \ref gf_evg_surface_clear \note Omitting the last values will assume 0xFF for alpha, and 0 for other values. \param rc the rectangle to clear, in pixel coordinates @@ -92,12 +133,12 @@ void clear(IRect rc, unsigned long r, unsigned long g, unsigned long b, unsigned /*! clears the canvas with the given color. See \ref gf_evg_surface_clear \param rc the rectangle to clear, in pixel coordinates -\param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ +\param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ void clear(IRect rc, DOMString color); /*! clears the canvas with the given color. See \ref gf_evg_surface_clear \param rc the rectangle to clear, in pixel coordinates -\param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ +\param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ void clear(IRect rc, DOMString color); /*! clears the canvas with the given color @@ -112,7 +153,7 @@ void clearf(IRect rc, double r, double g, double b, double a); /*! clears the canvas with the given color. See \ref gf_evg_surface_clear \param rc the rectangle to clear, in pixel coordinates -\param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ +\param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ void clearf(IRect rc, DOMString color); /*! fills the path with the given solid brush or gradient stencil - see \ref gf_evg_surface_fill @@ -123,11 +164,42 @@ void fill(Stencil stencil); \param texture the texture to use*/ void fill(Texture texture); +/*! fills the path with the given texture(s) - see \ref gf_evg_surface_multi_fill +\param operand multitexture operand to use +\param param float or float array used to control multitexture effect +\param texture1 the texture or stencil to use as main texture +\param texture2 the texture or stencil to use as secondary texture +\param texture3 the texture or stencil to use as third texture +*/ +void fill(GF_EVGMultiTextureMode operand, optional float param=0, Texture texture1, optional Texture texture2=null, optional Texture texture3=null); + /*! reassign internal data (typically at each new packet) \warning This assumes the data layout has not changed (width, height, pixel format, strides). If these are modified, create a new canvas. \param data the buffer to use*/ void reassign(ArrayBuffer data); + +/*! blits a texture pixel data onto the surface +\warning All texture properties (matrix, color matrix, ...) and canvas properties (path, matrix...) are ignored. +\warning This does not perform alpha blending. + +The blit operations are usually faster than path fill operations, but only operate on axis-aligned rectangles. + +\param texture the texture to use for pixel source +\param dst_wnd the destination rectangle in canvas, must be completely included in canvas. Point{0,0} is top-left and {width,height} is bottom right +\param src_wnd the source rectangle from the texture, must be completely included in texture. Point{0,0} is top-left and {width,height} is bottom right +\param params the blit operation parameters. If null, let FFMPEG decide +*/ +void blit(Texture texture, optional IRect dst_wnd=null, optional IRect src_wnd=null, optional BlitParameters params=null); + + +/*! enables threading in rasterizer - see \ref gf_evg_enable_threading +\param nb_threads the number of extra threads to use, negative values means all cores*/ +void enable_threading(optional int nb_threads=-1); + +/*! enables 3D extensions in rasterizer - see \ref gf_evg_surface_enable_3d*/ +void enable_3d(); + /*! converts YUV color to RGB \param as_array if true, the return object is an array of 4 components, otherwise it is a Vec4f object \param y Y component value @@ -162,6 +234,87 @@ Object toYUV(optional bool as_array=false, Float r, Float g, Float b, optional F */ Object toYUV(optional bool as_array=false, Vec4f color); + + +/*! fragment shader to use, set to NULL to disable pixel writing.*/ +Shader fragment; +/*! vertex shader to use, set to NULL to disable vertex shading, in which case the currently defined projection and modelview matrices will be used*/ +Shader vertex; +/*! set face orientation to counter-clockwise or clockwise (see \ref gf_evg_surface_set_ccw)*/ +writeonly boolean ccw; +/*! backface culling enabled (see \ref gf_evg_surface_set_backcull), default is true*/ +writeonly boolean backcull; +/*! antialiased enabled (see \ref gf_evg_surface_set_antialias), default is true*/ +writeonly boolean antialias; +/*! min depth (see \ref gf_evg_surface_set_min_depth), default is 0*/ +writeonly float min_depth; +/*! max depth (see \ref gf_evg_surface_set_max_depth), default is 1.0*/ +writeonly float max_depth; +/*! point size (see \ref gf_evg_surface_set_point_size), default is 1.0*/ +writeonly float point_size; +/*! point smoothing enabled (see \ref gf_evg_surface_set_point_smooth), default is false*/ +writeonly boolean point_smooth; +/*! line size (see \ref gf_evg_surface_set_line_size), default is 1.0*/ +writeonly float line_size; +/*! clip zero enabled (see \ref gf_evg_surface_set_clip_zero), default is false*/ +writeonly boolean clip_zero; +/*! depth test mode (see \ref gf_evg_set_depth_test), default is GF_EVGDEPTH_LESS*/ +writeonly GF_EVGDepthTest depth_test; +/*! write depth buffer enabled (see \ref gf_evg_surface_write_depth), default is true*/ +writeonly boolean write_depth; +/*! depth buffer (see \ref gf_evg_surface_set_depth_buffer). \warning Default is null*/ +Float32Buffer depth_buffer; + +/*! sets current projection matrix to use +\param projection_matrix the 16 float coeficients of the matrix, column-first. When using Matrix object, you can pass Matrix.m +*/ +void projection(Float32Buffer projection_matrix); +/*! sets current modelview matrix to use +\param modelview_matrix the 16 float coeficients of the matrix, column-first. When using Matrix object, you can pass Matrix.m +*/ +void modelview(Float32Buffer modelview_matrix); + +/*! draws a set of primitives (see \ref gf_evg_surface_draw_array) +\param indices array of indices in the vertex buffer for the primitives to draw +\param vertices the vertices to use +\param primitive_type the type of primitive to draw +\param nb_components the number of components per vertex (eg, 2, 3) +*/ +void draw_array(Int32Buffer indices, Float32Buffer vertices, optional GF_EVGPrimitiveType primitive_type=GF_EVG_TRIANGLES, optional long nb_components=3); + +/*! draws a path (see \ref gf_evg_surface_draw_path) +\param path the path to draw +\param z the z value to assign to points in the path +*/ +void draw_path(Path path, optional float z=0); +/*! draws a text (see \ref gf_evg_surface_draw_path) +\param text the text to draw +\param z the z value to assign to points in the text's path +*/ +void draw_path(Text text, optional float z=0); + +/*! clears the depth buffer (see \ref gf_evg_surface_clear_depth) +\param depth the depth value to set +*/ +void clear_depth(float depth); + +/*! sets the viewport (see \ref gf_evg_surface_viewport) +\param x the horizontal coordinate of the top-left corner of the viewport +\param y the vertical coordinate of the top-left corner of the viewport +\param width the width of the viewport +\param height the height of the viewport + +*/ +void viewport(long x, long y, long width, long height); + +/*! sets the viewport to full canvas {0,0,width,height} (see \ref gf_evg_surface_viewport)*/ +void viewport(); + +/*! creats a new shader +\return the new shader +\param shader_type the desired shader type*/ +Shader new_shader(ShaderType shader_type); + }; @@ -228,10 +381,17 @@ interface Path { readonly attribute boolean empty; /*! if true, path will use zero_non_zero fill rule otherwise odd/even rule*/ readonly attribute boolean zero_fill; + + /*! if true, path will use odd/even rule but fill only even parts*/ + readonly attribute boolean even_fill; + /*! bounds of path - see \ref gf_path_get_bounds*/ readonly attribute Rect bounds; /*! control bounds of path - see \ref gf_path_get_control_bounds*/ readonly attribute Rect ctrl_bounds; + /*! set to true if path is a rectangle/square*/ + readonly attribute boolean is_rectangle; + /*! checks if point is over a path - see \ref gf_path_point_over \param pt point to test @@ -252,8 +412,9 @@ interface Path { /*! adds a path to the path - see \ref gf_path_add_subpath \param subpath path to add + \param mx matrix to apply to path \return the path*/ - Path add_path(Path subpath); + Path add_path(Path subpath, optional Matrix2D mx=null); /*! adds an arc to the path - see \ref gf_path_add_arc \param radius radius of the arc @@ -381,6 +542,11 @@ interface Path { */ Path outline(PenSettings ps); + /*! transforms a path - see \ref gf_path_add_subpath + \param mx matrix to apply to path + \return the new transformed path*/ + Path transform(Matrix2D mx); + }; /*! Pen settings, see \ref GF_PenSettings*/ @@ -452,6 +618,8 @@ interface Matrix2D { attribute double tx; /*! matrix is identity*/ attribute boolean identity; + /*! indicates matrix is a 2D matrix*/ + attribute const boolean is3D = false; /*! get scale part of the matrix after decomposition - see \ref gf_mx2d_decompose \return {x, y} object, or null if matrix cannot be decomposed*/ @@ -466,20 +634,23 @@ interface Matrix2D { /*! inverse matrix - see \ref gf_mx2d_inverse \return the matrix*/ Matrix2D inverse(); - /*! copies the matrix + /*! copies the matrix \return the new copy matrix*/ Matrix2D copy(); + /*! copies from a matrix + \param from the matrix to copy from*/ + void copy(Matrix2D from); /*! adds a matrix - see \ref gf_mx2d_add_matrix and \ref gf_mx2d_pre_multiply \param mx the matrix to multiply \param premultiply if true, performs \code mx * this \endcode, otherwise \code this * mx \endcode \return the matrix*/ Matrix2D add(Matrix2D mx, optional boolean premultiply=false); - /*! add a translation - see \ref gf_mx2d_add_rotation + /*! add a translation - see \ref gf_mx2d_add_translation \param x horizontal translation \param y vertical translation \return the matrix*/ Matrix2D translate(double x, double y); - /*! add a translation - see \ref gf_mx2d_add_rotation + /*! add a translation - see \ref gf_mx2d_add_translation \param vec translation vector \return the matrix*/ Matrix2D translate(Point2D vec); @@ -588,7 +759,7 @@ interface ColorMatrix { ColorMatrix multiply(ColorWatrix with); /*! apply a color transformation as 8bit RGB - \param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB + \param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB \return transformed color*/ Color apply(DOMString color); @@ -598,7 +769,7 @@ interface ColorMatrix { Color apply(Color color); /*! apply a color transformation as float RGB - \param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB + \param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB \return transformed color*/ Colorf applyf(DOMString color); @@ -647,15 +818,20 @@ interface Stencil { writeonly unsigned long pad; /*! color matrix for gradient stencils. Setting to null resets the matrix*/ writeonly unsigned long cmx; - /*! matrix for gradient stencils. Setting to null resets the matrix*/ - writeonly unsigned long mx; + /*! matrix for gradient stencils. Setting to null resets the matrix + \warning this is a copy of the associated matrix, not a live object*/ + attribute Matrix2D mx; + /*! true if stencil is a solid color brush, false for gradient stencils*/ + attribute readonly boolean solid_brush; + /*! automatic matrix mode, see \ref gf_evg_stencil_set_auto_matrix*/ + attribute boolean auto_mx; /*! set color for solid brush stencil \param color the color to set*/ void set_color(Color color); /*! set color for solid brush stencil - \param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ + \param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ void set_color(DOMString color); /*! set color for solid brush stencil - see \ref gf_evg_stencil_set_brush_color. @@ -680,13 +856,21 @@ interface Stencil { */ void set_colorf(double r, double g, double b, double a); - /*! sets alpha value for stencil. The alpha is is multiplied with the alpha component of the solid brush or gradient color + /*! get color for solid brush stencil + \return color string*/ + DOMString get_color(); + + /*! sets alpha value for stencil. The alpha is multiplied with the alpha component of the solid brush or gradient color \param alpha the alpha to set, between 0 and 255*/ void set_alpha(unsigned long alpha); - /*! sets alpha value for stencil. The alpha is is multiplied with the alpha component of the solid brush or gradient color + /*! sets alpha value for stencil. The alpha is multiplied with the alpha component of the solid brush or gradient color \param alpha the alpha to set, between 0.0 and 1.0*/ - void set_alpha(double alpha); + void set_alphaf(double alpha); + + /*! gets alpha value for stencil + \return alpha value, between 0.0 and 1.0*/ + double get_alphaf(); /*! sets linear gradient start and end point. If end point is omitted, sets gradient line betwee {0,0} and start. Coordinates are given in surface coordinates, not object coordinates. See \ref gf_evg_stencil_set_linear_gradient \note Point2D can be replaced with 2 number x, y, i.e. these syntaxes are all equivalent: @@ -719,7 +903,7 @@ interface Stencil { /*! defines a new stop color for the gradient. Stops must be declared in order on the gradient. See \ref gf_evg_stencil_push_gradient_interpolation \param pos position between 0.0 and 1.0 - \param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB + \param color an HTML/SVG color name or an HTML color value formatted as \$RRGGBB, \#RRGGBB or 0xRRGGBB */ void set_stop(double pos, DOMString color); @@ -778,7 +962,9 @@ interface Texture { */ Texture(ArrayBuffer img_data); - /*! parametric texture constructor. A parametric texture gets its pixel values from a javascript callback function, the resulting value being blended according to the antialiasing level of the pixel. This allows creating rather complex custom textures, in a fashion similar to fragment shaders. + /*! parametric texture constructor. A parametric texture gets its pixel values from a javascript callback function, the resulting value being blended according to the antialiasing level of the pixel. This allows creating rather complex custom textures, in a fashion similar to fragment shaders. + \warning Parametric textures in JS cannot use multithreaded canvas, use 2D shaders for that. + \param width width of the texture \param height height of the texture \param pixfmt pixel format of the texture @@ -799,12 +985,17 @@ interface Texture { */ Texture(FilterPacket packet); + /*! Empty texture constructor. This is usually needed async texture load. + */ + Texture(); + /*! filtering mode - see \ref gf_evg_stencil_set_filter*/ writeonly unsigned long filtering; /*! color matrix - see \ref gf_evg_stencil_set_color_matrix. Setting to null resets the color matrix*/ writeonly ColorMatrix cmx; - /*! matrix - see \ref gf_evg_stencil_set_matrix. Setting to null resets the matrix*/ - writeonly Matrix2D mx; + /*! matrix - see \ref gf_evg_stencil_set_matrix. Setting to null resets the matrix + \warning: this is a copy of the associated matrix, not a live object*/ + attribute Matrix2D mx; /*! horizontal repeat flag*/ attribute boolean repeat_s; /*! vertical repeat flag*/ @@ -824,15 +1015,16 @@ interface Texture { readonly attribute ArrayBuffet data; - /*! sets alpha value for stencil. The alpha is is multiplied with the alpha component of the solid brush or gradient color + /*! sets alpha value for stencil. The alpha is multiplied with the alpha component of the solid brush or gradient color \param alpha the alpha to set, between 0 and 255*/ void set_alpha(unsigned long alpha); - /*! sets alpha value for stencil. The alpha is is multiplied with the alpha component of the solid brush or gradient color + /*! sets alpha value for stencil. The alpha is multiplied with the alpha component of the solid brush or gradient color \param alpha the alpha to set, between 0.0 and 1.0*/ - void set_alpha(double alpha); + void set_alphaf(double alpha); /*! converts texture from RGB/YUV to new HSV texture + \warning the texture format will still be RGB (or RGBA if the source has alpha), in packed format \warning experimental, slow \return new texture*/ Texture rgb2hsv(); @@ -842,23 +1034,17 @@ interface Texture { \return new texture*/ Texture hsv2rgb(); - /*! converts texture from HSV to new RGB texture - \warning experimental, slow - \return new texture*/ - Texture hsv2rgb(); - /*! converts texture from RGB to new YUV texture \warning experimental, slow This function can be used to convert an RGB texture to a YUV one, typically for rasterizing an RGB static texture over a YUV video (avoids performing the RGB to YUV conversion at each frame) - \warning the texture format will still be RGB (or RGBA if the source has alpha), in packed format - \param surf the target surface, can be a Canvas or a Canvas3D object + \param surf the target Canvas \return new texture*/ Texture rgb2yuv(Canvas surf); /*! converts texture from YUV to new RGB texture \warning experimental, slow This function can be used to convert a YUV texture to an RGB one, typically for rasterizing a YUV static texture over an RGB video (avoids performing the TYV to RGB conversion at each frame) - \param surf the target surface, can be a Canvas or a Canvas3D object + \param surf the target Canvas \return new texture*/ Texture yuv2rgb(Canvas surf); @@ -875,6 +1061,46 @@ interface Texture { \return new texture*/ Texture split(unsigned long idx); + /*! updates pixel data of texture using source packet + \param packet the new packet to use for the texture + */ + void update(FilterPacket packet); + + /*! load local file into texture. Only JPEG and PNG local files are supported. + \param filename file name on local drive + \param is_rel_script if true, indicates the file path is relative to the script location. Otherwise it is relative to the current directory + */ + load(DOMString filename, optional boolean is_rel_script=false); + + /*! load file data into texture. Only JPEG and PNG data are supported. + \param img_data image file data + */ + load(ArrayBuffer img_data); + + /*! Makes the texture a named texture for WebGL. + + If a texImage2D is done with a named EVG texture: + - the associated WebGL texture becomes a named texture + - any update() on the EVG texture will update the WebGL texture. + + \warning The shaders must be (re)compiled after the first update() on the texture. + + \param name the named texture to use. + */ + set_named(DOMString name); + + /*! Sets padding color for texture - see \ref gf_evg_stencil_set_pad_color + + The parameters can also be 4 doubles, an array of 4 doubles or an object with 'r', 'g', 'b', 'a' properties. In these cases, the component values must be between 0 and 1 + \param color the color to use. + */ + set_pad_color(DOMString color); + + /*! gets padding color associated for texture + \return the color used to pad or null if none. + */ + DOMString get_pad_color(); + /*! gets RGB pixel value in a texture \param s horizontal normalized texture coordinate of pixel, between 0 (left) and 1.0 (right) @@ -902,17 +1128,18 @@ interface ConvolutionKernel attribute unsigned long h; /*! kernel normalization. If 0 or undefined, no normalization is applied*/ attribute unsigned long norm; - /*! kernel coeficients. The coeficients are unsigned intergers, and there shall be at least w * h coefficients*/ + /*! kernel coeficients. The coeficients are unsigned integers, and there shall be at least w * h coefficients*/ attribute Array k; }; /*! Text object*/ interface Text { - /*! constructor. The default text is created with a font size of 12, horizontal drawing, start alignment and alphabetic baseline. - \param font font name to use*/ - Text(optional DOMString font=null); - /*! font name*/ - attribute DOMString font; + /*! constructor. The default text is created with a font size of 12, horizontal drawing, start alignment and alphabetic baseline.*/ + Text(); + /*! font name - array or single string value. If array, fonts in array will be checked until one is found + The text must be set again whenever the font is changing ! + */ + attribute Array font; /*! font name*/ attribute double fontsize; /*! align flag for horizontal positioning (see Canvas2D). Alignment is computed on maximum text line width after application of maxWidth if any/needed @@ -954,7 +1181,7 @@ interface Text { Each element is treated as follows: - transformed to string, whether it is a string, number, object / array - split in one or several text lines, scanning new line character 'CR' - - each line of text is then transformed into a graphicsl path with the current text settings. + - each line of text is then transformed into a graphics path with the current text settings. */ void set_text(...); @@ -991,6 +1218,8 @@ interface TextMeasure unsigned long max_advance_h; /*! max vertical advance of any glyphs in font*/ unsigned long max_advance_v; + /*! set to true if text is right to left, false otherwise*/ + boolean right_to_left; }; @@ -1022,6 +1251,9 @@ print(`transformed ${res.x} ${res.y} ${res.z});` interface Matrix { /*! indicates if matrix is identity. If set to true, resets matrix*/ attribute boolean identity; +/*! indicates matrix is a 3D matrix*/ +attribute const boolean is3D = true; + /*! float buffer of coeficients (typically use matrix.m to pass matrices uniforms)*/ attribute Array m; /*! yaw value of matrix*/ @@ -1121,7 +1353,7 @@ Matrix transpose(); \param z_far max depth coordinate of viewport \return the matrix object */ -Matrix ortho(float left, float right, float top, float bottom, float z_near, float z_far); +Matrix ortho(float left, float right, float bottom, float top, float z_near, float z_far); /*! loads a perspective projection matrix \param fov camera field of view angle in radian @@ -1199,203 +1431,6 @@ interface Vec4f { }; -/*! The Canvas3D object is used to draw vectorial 3D meshes and 2D paths. - -\warning The 3D rasterizer is much much slower than WebGL as it is only software and not realy optimized, do not use it for complex 3D scenes. - - -\warning The 3D rasterizer is still an experimental project: it might not be completely stable and its API may change a lot in the near future. - - -The 3D rasterizer can however be useful when drawing simple 3D objects over an existing video, as it avoids GPU transfers of the frame data. - -The rasterizer supports: -- points, lines, triangles, quads, strips and fans -- 2D texturing using RGBA or YUVA colorspace -- perspective correct interpolation -- simple antialiasing -- depth buffer (float only) -- rasterizing in YUVA or RGBA space -- a simple shading language for both vertex and fragment processing - -The rasterizer does not claim compliancy to any GPU specification, and will likely produce different results than WebGL. - - */ -interface Canvas3D { - /*! Canvas3D constructor. The canvas memory is owned by the canvas object - \param width the width in pixels of the canvas - \param height the height in pixels of the canvas - \param pixfmt the pixel fomat of the canvas - */ - Canvas3D(unsigned long width, unsigned long height, DOMString pixfmt); - /*! Canvas constructor - \param width the width in pixels of the canvas - \param height the height in pixels of the canvas - \param pixfmt the pixel fomat of the canvas - \param data the data buffer on which to write. The size shall be greater than the size required for the given size and pixel format. - \param stride horizontal stride in pixel of the data - \param stride_uv horizontal stride in pixel of the data for the U and V planes - */ - Canvas3D(unsigned long width, unsigned long height, DOMString pixfmt, ArrayBuffer data, optional unsigned long stride=0, optional unsigned long stride_uv=0); - -/*! clipper in pixel coordinates - see \ref gf_evg_surface_set_clipper -\note A same path can be drawn several times with different clipper, null means no clipper. Clipper applies to both fill and clear functions*/ -writeonly IRect clipper; -/*! fragment shader to use, set to NULL to disable pixel writing.*/ -Shader fragment; -/*! vertex shader to use, set to NULL to disable vertex shading, in which case the currently defined projection and modelview matrices will be used*/ -Shader vertex; -/*! set face orientation to counter-clockwise or clockwise (see \ref gf_evg_surface_set_ccw)*/ -writeonly boolean ccw; -/*! backface culling enabled (see \ref gf_evg_surface_set_backcull), default is true*/ -writeonly boolean backcull; -/*! antialiased enabled (see \ref gf_evg_surface_set_antialias), default is true*/ -writeonly boolean antialias; -/*! min depth (see \ref gf_evg_surface_set_min_depth), default is 0*/ -writeonly float min_depth; -/*! max depth (see \ref gf_evg_surface_set_max_depth), default is 1.0*/ -writeonly float max_depth; -/*! point size (see \ref gf_evg_surface_set_point_size), default is 1.0*/ -writeonly float point_size; -/*! point smoothing enabled (see \ref gf_evg_surface_set_point_smooth), default is false*/ -writeonly boolean point_smooth; -/*! line size (see \ref gf_evg_surface_set_line_size), default is 1.0*/ -writeonly float line_size; -/*! clip zero enabled (see \ref gf_evg_surface_set_clip_zero), default is false*/ -writeonly boolean clip_zero; -/*! depth test mode (see \ref gf_evg_set_depth_test), default is GF_EVGDEPTH_LESS*/ -writeonly GF_EVGDepthTest depth_test; -/*! write depth buffer enabled (see \ref gf_evg_surface_write_depth), default is true*/ -writeonly boolean write_depth; -/*! depth buffer (see \ref gf_evg_surface_set_depth_buffer). \warning Default is null*/ -Float32Buffer depth_buffer; - -/*! clears the canvas with the given color - see \ref gf_evg_surface_clear -\note Omitting the last values will assume 0xFF for alpha, and 0 for other values. -\param rc the rectangle to clear, in pixel coordinates -\param r red value, between 0 and 255 -\param g green value, between 0 and 255 -\param b blue value, between 0 and 255 -\param a alpha value, between 0 and 255 -*/ -void clear(IRect rc, unsigned long r, unsigned long g, unsigned long b, unsigned long a); - -/*! clears the canvas with the given color. See \ref gf_evg_surface_clear -\param rc the rectangle to clear, in pixel coordinates -\param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ -void clear(IRect rc, DOMString color); - -/*! clears the canvas with the given color. See \ref gf_evg_surface_clear -\param rc the rectangle to clear, in pixel coordinates -\param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ -void clear(IRect rc, DOMString color); - -/*! clears the canvas with the given color -\note Omitting the last values will assume 1.0 for alpha, and 0.0 for other values. See \ref gf_evg_surface_clear -\param rc the rectangle to clear, in pixel coordinates -\param r red value, between 0.0 and 1.0 -\param g green value, between 0.0 and 1.0 -\param b blue value, between 0.0 and 1.0 -\param a alpha value, between 0.0 and 1.0 -*/ -void clearf(IRect rc, double r, double g, double b, double a); - -/*! clears the canvas with the given color. See \ref gf_evg_surface_clear -\param rc the rectangle to clear, in pixel coordinates -\param color an HTML/SVG color name or an HTML color value formated as \$RRGGBB, \#RRGGBB or 0xRRGGBB*/ -void clearf(IRect rc, DOMString color); - -/*! reassign internal data (typically at each new packet) -\warning This assumes the data layout has not changed (width, height, pixel format, strides). If these are modified, create a new canvas. -\param data the buffer to use*/ -void reassign(ArrayBuffer data); - -/*! converts YUV color to RGB -\param as_array if true, the return object is an array of 4 components, otherwise it is a Vec4f object -\param y Y component value -\param u Cb/U component value -\param v Cr/V component value -\param a alpha value, not modified -\return the converted value -*/ -Object toRGB(optional bool as_array=false, Float y, Float u, Float v, optional Float a=1.0); - -/*! converts YUV color to RGB -\param as_array if true, the return object is an array of 4 components, otherwise it is a Vec4f object -\param color the YUV value to convert -\return the converted value -*/ -Object toRGB(optional bool as_array=false, Vec4f color); - -/*! converts RGB color to YUV -\param as_array if true, the return object is an array of 4 components, otherwise it is Vec4f object -\param r red component value -\param g green component value -\param b blue component value -\param a alpha value, not modified -\return the converted value -*/ -Object toYUV(optional bool as_array=false, Float r, Float g, Float b, optional Float a=1.0); - -/*! converts RGB color to YUV -\param as_array if true, the return object is an array of 4 components, otherwise it is a Vec4f object -\param color the RGB value to convert -\return the converted value -*/ -Object toYUV(optional bool as_array=false, Vec4f color); - - -/*! sets current projection matrix to use -\param projection_matrix the 16 float coeficients of the matrix, column-first. When using Matrix object, you can pass Matrix.m -*/ -void projection(Float32Buffer projection_matrix); -/*! sets current modelview matrix to use -\param modelview_matrix the 16 float coeficients of the matrix, column-first. When using Matrix object, you can pass Matrix.m -*/ -void modelview(Float32Buffer modelview_matrix); - -/*! draws a set of primitives (see \ref gf_evg_surface_draw_array) -\param indices array of indices in the vertex buffer for the primitives to draw -\param vertices the vertices to use -\param primitive_type the type of primitive to draw -\param nb_components the number of components per vertex (eg, 2, 3) -*/ -void draw_array(Int32Buffer indices, Float32Buffer vertices, optional GF_EVGPrimitiveType primitive_type=GF_EVG_TRIANGLES, optional long nb_components=3); - -/*! draws a path (see \ref gf_evg_surface_draw_path) -\param path the path to draw -\param z the z value to assign to points in the path -*/ -void draw_path(Path path, optional float z=0); -/*! draws a text (see \ref gf_evg_surface_draw_path) -\param text the text to draw -\param z the z value to assign to points in the text's path -*/ -void draw_path(Text text, optional float z=0); - -/*! clears the depth buffer (see \ref gf_evg_surface_clear_depth) -\param depth the depth value to set -*/ -void clear_depth(float depth); - -/*! sets the viewport (see \ref gf_evg_surface_viewport) -\param x the horizontal coordinate of the top-left corner of the viewport -\param y the vertical coordinate of the top-left corner of the viewport -\param width the width of the viewport -\param height the height of the viewport - -*/ -void viewport(long x, long y, long width, long height); - -/*! sets the viewport to full canvas {0,0,width,height} (see \ref gf_evg_surface_viewport)*/ -void viewport(); - -/*! creats a new shader -\return the new shader -\param shader_type the desired shader type*/ -Shader new_shader(ShaderType shader_type); -}; - /*! defined shader types*/ typedef enum { @@ -1468,7 +1503,7 @@ The working principles of the shader object is as follows: - variables can be defined as uniforms, and updated whenever needed - upon executing the shader, the instructions are processed in order -Local variables are untyped, except for reserved variables. The type is infered whenever the variable is assigned or modified, thus a same variable can change type during the execution of the shader. +Local variables are untyped, except for reserved variables. The type is inferred whenever the variable is assigned or modified, thus a same variable can change type during the execution of the shader. Upon assigning, the type of the source variable is inferred as follows: - Javascript bool and integer are converted to integer type - Javascript float is converted to float type @@ -1506,8 +1541,14 @@ fragY | float | the fragment Y coordinate fragDepth | float | the fragment depth value - can be overwritten by shader fragZ | float | the fragment Z coordinate fragW | float | the fragment W coordinate +txCoord | float | the texture coordinates for 2D shaders +txCoordi | ints | the integer texture coordinates for 2D shaders +fragOdd | boolean | the odd/even flag of 2D path for 2D shaders +\note +`txCoordi` is used to fetch the pixel value as int. This is quite experimental, and should only be used to assign fragRGBA or fragYUVA. + # Vertex shader reserved variables These variables names are reserved in a vertex shader, and their type cannot be modified: @@ -1601,7 +1642,7 @@ Name | rv1 | rv2 | Semantic 'sign' | any | none | assigns sign vector of rv1 to left value - cf GLSL 'floor' | any | none | assigns floor(rv1) to left value 'ceil' | any | none | assigns ceil(rv1) to left value -'fract' | any | none | assigns fractionnal part of rv1 to left value - cf GLSL +'fract' | any | none | assigns fractional part of rv1 to left value - cf GLSL 'mod' | any | any | assigns modulo of rv1 by rv2 to left value - cf GLSL 'min' | any | any | assigns minimum of rv1 and rv2 to left value - cf GLSL 'max' | any | any | assigns maximum of rv1 and rv2 to left value - cf GLSL @@ -1629,8 +1670,8 @@ Example # Conditions Conditions are expressed with the following keywords: -- 'if' : takes 3 additionnal parameters `left`, `operand`and `right` and evaluates the condition -- 'elseif' : takes 3 additionnal parameters `left`, `operand` and `right` and evaluates the condition +- 'if' : takes 3 additional parameters `left`, `operand`and `right` and evaluates the condition +- 'elseif' : takes 3 additional parameters `left`, `operand` and `right` and evaluates the condition - 'else': no additional parameters - 'end': no additional parameters @@ -1694,7 +1735,7 @@ shader.push('end'); shader.push('elseif', 'my_var.x', '<=', '.uniform'); shader.push('goto', '.label_start'); //go to the instruction at position label_start shader.push('else'); -shader.push('goto', 0); //go to begining of the instruction stack +shader.push('goto', 0); //go to beginning of the instruction stack shader.label_end = shader.push('end'); ... \endcode @@ -1768,7 +1809,7 @@ Texture sampling can also work on both RGB and YUV texture maps. - When a `samplerYUV` call is made on a RGB texture, conversion is performed - Otherwise, no conversion is done -The `toRGB` and `toYUV` operations can also be used to convert between color space, but precomputed values should be prefered. +The `toRGB` and `toYUV` operations can also be used to convert between color space, but precomputed values should be preferred. */ interface Shader { @@ -1825,4 +1866,55 @@ void update(); long PixelSize(DOMString pixel_format); +/*! Parameter object for canvas texture blit */ +interface BlitParameters +{ + /*! name of the scale mode - see `gpac -hx ffsws`. If undefined, let FFMPEG decide*/ + DOMString mode; + /*! first parameter of scale mode, if any*/ + double p1; + /*! second parameter of scale mode, if any*/ + double p2; +}; + + +/*! Mesh object to describe 3D graphics. +\warning This is a work in progress, API will likely change soon +*/ +interface Mesh { + /*! Constructs an empty mesh*/ + Mesh(); + + /*! Constructs a mesh from a path + \param path 2D path to use as source + */ + Mesh(Path path); + + /*! Updates underlying OpenGL vertex buffer objects*/ + void update_gl(); + /*! Draw mesh using current program + \param vertex_attrib_location uniform location of vertex buffer attribute in program + */ + void draw(unsigned long vertex_attrib_location); + /*! Draw mesh using current program + \param vertex_attrib_location uniform location of vertex buffer attribute in program + \param texture_attrib_location uniform location of texture coordinate buffer attribute in program + */ + void draw(unsigned long vertex_attrib_location, unsigned long texture_attrib_location); + /*! Draw mesh using current program + \param vertex_attrib_location uniform location of vertex buffer attribute in program + \param normal_attrib_location uniform location of normal buffer attribute in program + \param texture_attrib_location uniform location of texture coordinate buffer attribute in program + */ + void draw(unsigned long vertex_attrib_location, unsigned long normal_attrib_location, unsigned long texture_attrib_location); + /*! Draw mesh using current program + \param vertex_attrib_location uniform location of vertex buffer attribute in program + \param normal_attrib_location uniform location of normal buffer attribute in program + \param color_attrib_location uniform location of color buffer attribute in program + \param texture_attrib_location uniform location of texture coordinate buffer attribute in program + */ + void draw(unsigned long vertex_attrib_location, unsigned long normal_attrib_location, unsigned long color_attrib_location, unsigned long texture_attrib_location); + +}; + /*! @} */ diff --git a/share/doc/idl/filtersession.idl b/share/doc/idl/filtersession.idl index 0585f02..9b3d30c 100644 --- a/share/doc/idl/filtersession.idl +++ b/share/doc/idl/filtersession.idl @@ -48,9 +48,9 @@ interface JSFilterSession { void post_task(function task_callback, optional DOMString task_name=null); /*! aborts the filter session - see \ref gf_fs_abort -\param do_flush if true, wait for all packets currently pending to be processed before closing the session +\param flush_type if true, wait for all packets currently pending to be processed before closing the session */ -void abort(optional boolean do_flush=false); +void abort(optional unsigned long flush_type=0); /*! locks the filter session - see \ref gf_fs_lock_filters. When the session is locked, tasks are suspended and filters cannot be destroyed. The session only needs to be locked when enumerating filters @@ -64,11 +64,11 @@ void lock_filters(boolean do_lock); */ JSFSFilter get_filter(unsigned long index); -/*! returns the JSFSFilter object for a given filter \ref iname. +/*! returns the JSFSFilter object for a given filter iname. \param iname the iname of filter to query \return the filter object, null if none found */ -JSFSFilter get_filter(unsigned long index); +JSFSFilter get_filter(DOMString iname); /*! sends the given string to the remotery client(s) \param command the command to send @@ -80,24 +80,31 @@ void rmt_send(DOMString command); \param callback the callback function to call. This function takes one parameter which is the text being received \return error code if any */ -void rmt_set_fun(function callback); +void set_rmt_fun(function callback); /*! inserts a filter in graph + \param filter_to_add string describin the filter to add, can be in the form "src=" for sources, "dst=" for sinks or regular string for filters. \param link_from filter used as source for the created filters - see \ref gf_filter_set_source \param link_args arguments for the link (used to assign new filter SID - see \ref gf_filter_set_source +\param relative_to_script if false, URLs for source and sinks filters are relative to the current working directory, if true they are relative to the script path \return new filter created */ -JSFSFilter add_filter(DOMString filter_to_add, optional JSFSFilter link_from=null, optional DOMString link_args=null); +JSFSFilter add_filter(DOMString filter_to_add, optional JSFSFilter link_from=null, optional DOMString link_args=null, optional boolean relative_to_script=false); -/*! sets callback function to get notifications upon each new filter creation. The callback function is passed a single parameter, the filter object*/ +/*! sets callback function to get notifications upon each new filter creation. +\param callback callback function - it is passed a single parameter, the filter object +*/ void set_new_filter_fun(function callback); -/*! sets callback function to get notifications upon each filter destruction. The callback function is passed a single parameter, the filter object*/ +/*! sets callback function to get notifications upon each filter destruction. +\param callback the callback function - it is passed a single parameter, the filter object +*/ void set_del_filter_fun(function callback); -/*! sets callback function to get events being sent back to application (see \ref gf_fs_set_ui_callback). The callback function will have a single parameter set, an event instance of FilterEvent interface. The return value of the function should be as indicated for each event type*/ -boolean set_event_fun(function callback); +/*! sets callback function to get events being sent back to application (see \ref gf_fs_set_ui_callback). +\param callback callback function - it is passed a single parameter set, an event instance of FilterEvent interface. The return value of the function should be as indicated for each event type*/ +void set_event_fun(function callback); /*! fires a given event on all registered user event if no filter is specified, or on the filter \param evt the event to send @@ -110,6 +117,14 @@ boolean fire_event(FilterEvent evt, optional JSFSFilter *filter=null, optional b \param enable enables reporting if true*/ void reporting(boolean enable); +/*! creates a new custom JS filter. This filter will share the same script context as the filter session script - see \ref JSFilter +\note A custom filter cannot use default arguments, and will not have the initialize callback function called. + +\param name name for the filter +\return new filter +*/ +JSFilter new_filter(DOMString name=null); + /*! number of filters in the session - see \ref gf_fs_get_filters_count. This number is only valid when session is locked*/ attribute long nb_filters; @@ -117,12 +132,23 @@ attribute long nb_filters; /*! check if the calling task is the last task in the session - see \ref gf_fs_is_last_task*/ readonly attribute boolean last_task; -/*! max capped HTTP download rate - used for DASH simulations mostly*/ +/*! max capped HTTP download rate in bps - used for DASH simulations mostly*/ attribute unsigned long http_max_bitrate; -/*! current http download rate averaged on all active resources*/ +/*! current http download rate averaged on all active resources in bps*/ readonly attribute unsigned long http_bitrate; +/*! set to true if no PID initialization task (connections) is pending*/ +readonly attribute boolean connected; + +/*! last process error, cf gf_fs_get_last_process_error*/ +readonly attribute boolean last_process_error; +/*! last connection error, cf gf_fs_get_last_connect_error*/ +readonly attribute boolean last_connect_error; + +/*! File path of source script*/ +readonly attribute DOMString jspath; + }; @@ -148,7 +174,7 @@ attribute readonly DOMString status; attribute readonly boolean alias; /*! set to the arguments passed to the filter, null if none*/ attribute readonly DOMString args; -/*! set to true if filter was dynamically loaded during graph resolution, false if filter was explicetly loaded by user/app*/ +/*! set to true if filter was dynamically loaded during graph resolution, false if filter was explicitly loaded by user/app*/ attribute readonly boolean dynamic; /*! set to true if filter is done processing and will soon be removed*/ attribute readonly boolean done; @@ -182,16 +208,22 @@ attribute DOMString iname; attribute boolean event_target; /*! set to max timestamp of last packet sent by the filter, or null if not available*/ -attribute boolean last_ts_sent; +attribute Fraction last_ts_sent; /*! set to max timestamp of last packet dropped by the filter, or null if not available*/ -attribute boolean last_ts_drop; +attribute Fraction last_ts_drop; /*! Checks if a filter is valid or if it has been destroyed. Any query on a destroyed filter will raise an exception. \return true if the filter has been destroyed, false otherwise*/ boolean is_destroyed(); /*! Gets properties on input pid +This function accepts the following extra names (not property names) to query PID status: +- buffer: return the PID buffer level in microsecond +- buffer_total: return the cumulated buffer from source to PID level in microsecond +- name: return the PID name +- eos: return true if PID is in EOS state + \param idx the index of the input pid to query \param name name of the property to query \return property value, or null if not found @@ -235,9 +267,15 @@ Array opid_sinks(unsigned long idx); */ Array all_args(optional boolean value_only=true); +/*! Gets value of a given argument of the filter +\param arg_name argument name +\return property value, or null +*/ +FilterProperty get_arg(DOMString arg_name); + /*! sends argument update to filter \param arg_name name of argument to update -\param arg_val value of argument to update +\param arg_val value of argument to update. Can be a string or a native type which will be serialized based on the argument type */ void update(DOMString arg_name, DOMString arg_val); @@ -248,7 +286,18 @@ void remove(); \param filter_to_add string describing the filter to add, can be in the form "src=" for sources, "dst=" for sinks or regular string for filters. \param link_args specify any additional arguments to pass to the SID option of the new filter - see \ref gf_filter_set_source */ -void insert(DOMString filter_to_add, optional DOMString link_args=NULL); +void insert(DOMString filter_to_add, optional DOMString link_args=null); + +/*! binds a JSObject with underlying filter javascript extensions, if any. Currently only dashin filter has such an extension (see \ref JSDASHClient). +This will throw an exception if failure or no JS binding available +\param obj the JS object to use as interface for the underlying filter script +*/ +void bind(Object obj); + +/*! locks a filter. This should only be used when updating sync arguments of the filter - see \ref gf_filter_lock. +\param do_lock if true, locks the filter global mutex, otherwise unlocks it. +*/ +void lock(boolean do_lock); }; @@ -267,6 +316,8 @@ optional attribute DOMString min_max_enum; optional attribute DOMString default; /*! argument can be updated*/ optional attribute boolean update; +/*! argument can be updated in synchronous way only, and filter must be locked whenever shared data is modified*/ +optional attribute boolean update_sync; /*! indicate the UI level of the argument - string can be undefined, "advanced" or "expert"*/ optional attribute DOMString hint; diff --git a/share/doc/idl/jsf.idl b/share/doc/idl/jsf.idl index 77b09aa..c4f0f15 100644 --- a/share/doc/idl/jsf.idl +++ b/share/doc/idl/jsf.idl @@ -134,9 +134,13 @@ readonly attribute unsigned long long clock_hint_mediatime; readonly attribute unsigned long long connections_pending; /*! internal name - this can only be set and modified by JS API and allows for filter identification from JS*/ attribute DOMString iname; +/*! requires source ID for the filter - see \ref gf_filter_require_source_id*/ +writeonly unsigned boolean require_source_id; +/*! gets JS path*/ +readonly attribute DOMString jspath; -/*! sets filter desciption as visible when checking filter info +/*! sets filter description as visible when checking filter info \param description description of filter*/ void set_desc(DOMString description); /*! sets filter author as visible when checking filter info @@ -164,11 +168,13 @@ void set_cap(optional JSCapDesc cap_desc = null); /*! sets the name of the filter, used for logs \param name the filter name */ -void set_name(DOMString name) +void set_name(DOMString name); + /*! creates a new PID - see \ref gf_filter_pid_new \return the new PID object */ FilterPid new_pid(); + /*! sends an event on the filter - see \ref gf_filter_send_event \param evt the event to send \param upstream sends the evnet upstream @@ -187,13 +193,7 @@ FilterProperty get_info(DOMString info_name, optional boolean is_string = false) \param mime the mime type to query \return true if supported */ -boolean is_supported_mime(DOMStrin mime); - -/*! disables data probing if a MIME type is supported - see \ref gf_filter_is_supported_mime -\param mime the mime type to query -\return true if supported -*/ -boolean is_supported_mime(DOMStrin mime); +boolean is_supported_mime(DOMString mime); /*! update filter status string - see \ref gf_filter_update_status \param status the status string, may be null to reset the status string @@ -241,6 +241,16 @@ void hint_clock(unsigned long long time_in_microseconds, double media_time_sec); */ void send_update(DOMString filter_id, DOMString arg_name, DOMString arg_value, long propagate_mask); +/*! locks filter session - see \ref gf_filter_lock_all +\param do_lock if true locks filter +*/ +void lock_all(boolean do_lock); + +/*! locks a filter - see \ref gf_filter_lock +\param do_lock if true locks filter +*/ +void lock(boolean do_lock); + /*! adds a source filter in the media session - see \ref gf_filter_connect_source \param source URL of source to load \param parent URL of parent, used as baseURL for the source. May be NULL @@ -275,6 +285,25 @@ void prevent_blocking(boolean do_prevent); */ void block_eos(boolean do_block); +/*! aborts the filter - see \ref gf_filter_abort*/ +void abort(); + + +/*! assigns source name to a filter - see \ref gf_filter_set_source +\param from a Filter or a FilterInstance object to set a a source for this filter +\param source_id the source ID to assign +*/ +void set_source(Filter from, optional DOMString source_id=null); + +/*! assigns restricted source name to a filter - see \ref gf_filter_set_source_restricted +\param from a Filter or a FilterInstance object to set a a source for this filter +\param source_id the source ID to assign +*/ +void set_source_restricted(Filter from, optional DOMString source_id=null); + +/*! reset source identifier for the filter - see \ref gf_filter_reset_source*/ +void reset_source(); + }; /*! FilterInstance wraps the set of functions available for filters loaded by the script*/ @@ -313,6 +342,12 @@ void send_update(DOMString filter_id, DOMString arg_name, DOMString arg_value, l */ void set_source(Filter from, optional DOMString source_id=null); +/*! assigns restricted source name to a filter - see \ref gf_filter_set_source_restricted +\param from a Filter or a FilterInstance object to set a a source for this filter +\param source_id the source ID to assign +*/ +void set_source_restricted(Filter from, optional DOMString source_id=null); + /*! removes a source filter - see \ref gf_filter_remove_src*/ void remove(); @@ -336,6 +371,20 @@ void disable_inputs(); /*! reset source identifier for the filter - see \ref gf_filter_reset_source*/ void reset_source(); + +/*! indicates if filter is likely blocking or not - see \ref gf_filter_set_blocking +\param is_blocking if true, indicates the filter is likely to block upon process*/ +void set_blocking(boolean is_blocking); + +/*! filter name*/ +attribute readonly DOMString name; + +/*! filter type (registry name)*/ +attribute readonly DOMString type; + +/*! internal name - this can only be set and modified by JS API and allows for filter identification from JS*/ +attribute DOMString iname; + }; /*! The FilterPid object is a binding for \ref GF_FilterPid*/ @@ -347,6 +396,8 @@ attribute DOMString name; attribute boolean eos; /*! end of stream pending state - see \ref gf_filter_pid_has_seen_eos*/ readonly attribute boolean eos_seen; +/*! end of stream pending state - see \ref gf_filter_pid_eos_received*/ +readonly attribute boolean eos_received; /*! blocking state - see \ref gf_filter_pid_would_block*/ readonly attribute boolean would_block; /*! name of parent filter*/ @@ -357,6 +408,8 @@ readonly attribute DOMString src_name; readonly attribute DOMString args; /*! argument of source filter*/ readonly attribute DOMString src_args; +/*! argument of source filter or first filter responsible for a fan-out*/ +readonly attribute DOMString unicity_args; /*! max buffer requirement of the pid - see \ref gf_filter_pid_get_max_buffer and \ref gf_filter_pid_set_max_buffer*/ attribute long max_buffer; /*! enables loose connect of the pid - see \ref gf_filter_pid_set_loose_connect*/ @@ -391,6 +444,8 @@ writeonly unsigned boolean recompute_dts; readonly attribute unsigned long min_pck_dur; /*! playing state - see \ref gf_filter_pid_is_playing*/ readonly attribute unsigned long playing; +/*! next estimated timestamp, or null if not computable - see \ref gf_filter_pid_get_next_ts*/ +readonly attribute boolean next_ts; /*! sends an event on the pid - see \ref gf_filter_pid_send_event \param evt the event to send*/ @@ -432,12 +487,12 @@ FilterPaquet get_packet(); */ void drop_packet(); -/*! checks if a filter is in parent chain of pid - see \ref gf_filter_pid_get_buffer_occupancy +/*! checks if a filter is in parent chain of pid - see \ref gf_filter_pid_is_filter_in_parents \param filter filter to check \return true if in parent chain*/ boolean is_filter_in_parents(GF_Filter filter); -/*! gets buffer occupancy - see \ref gf_filter_pid_is_filter_in_parents +/*! gets buffer occupancy - see \ref gf_filter_pid_get_buffer_occupancy \param filter the Filter or FilterInstance object to check \return a buffer occupancy object: \code @@ -450,7 +505,7 @@ boolean is_filter_in_parents(GF_Filter filter); } \endcode */ -boolean is_filter_in_parents(GF_Filter filter); +boolean get_buffer_occupancy(GF_Filter filter); /*! clears EOS on pid - see \ref gf_filter_pid_clear_eos*/ void clear_eos(); @@ -516,8 +571,13 @@ unsigned long long value; Object get_clock_info(); /*! sets property on a pid - see \ref gf_filter_pid_set_property and \ref gf_filter_pid_set_property_str + +\note if the name identifies the SenderNTP or ReceiverNTP properties: +- if the value is 'true', the property is set to the current NTP timestamp +- if the value is an object with properties 'n' and 'd', NTP timestamp is computed using 'n' as seconds and 'd' as fractional part + \param name the ID or name of the builtin property -\param prop the property to set +\param prop the property to set. If not set, removes the property. \param is_user if set, indicates the queried property is a user-defined property rather than a built-in property */ void set_prop(DOMString name, FilterProperty prop, optional boolean is_user=false); @@ -546,6 +606,12 @@ void reset_props(); */ void copy_props(FilterPid from); + +/*! ignore this pid in blocking computations - see gf_filter_pid_ignore_blocking* +\param do_ignore if true, pid is not used in blocking mode evaluation +*/ +void ignore_blocking(optional boolean do_ignore=true); + /*! creates a new output packet with no associated data \return new packet or null*/ FilterPacket new_packet(); @@ -648,9 +714,13 @@ readonly attribute unsigned long size; \warning This arraybuffer will be detached whenever the packet data is modified for a destination packet */ readonly attribute ArrayBuffer data; + /*! set to true if data of the packet is available through a GF_FilterFrameInterface object*/ readonly attribute boolean frame_ifce; +/*! set to true if packet has properties other than default ones - see gf_filter_pck_has_properties*/ +readonly attribute boolean has_properties; + /*! sets packet readonly - see gf_filter_pck_set_readonly*/ void set_readonly(); @@ -729,6 +799,17 @@ void truncate(unsigned long size); */ void copy_props(FilterPacket from); +/*! creates a new packet cloning a source packet - see \ref gf_filter_pck_dangling_copy. + +The resulting packet is in read/write mode and may have its own memory allocated. +This is typically used by sink filters wishing to access underling GPU data of a packet using frame interface. +The resulting packet can be explicitly discarded using \ref discard, otherwise will be garrbage collected. + +\param cached_pck if set, will be reuse for creation of new packet. This can greatly reduce memory allocations +\return the new FilterPacket or None if failure or None if failure ( if grabbing the frame into a local copy failed) +*/ +void clone(optional FilterPacket cached_pck = null); + }; /*! FilterEvent expose a filter event object, either for processing a received event or triggering a new event. @@ -801,15 +882,15 @@ attribute unsigned long set_tile_mode_plus_one; /*! quality switch - see \ref GF_FEVT_QualitySwitch*/ attribute unsigned long quality_degradation; -/*! visibility hint - see \ref GF_FEVT_VisibililityHint*/ +/*! visibility hint - see \ref GF_FEVT_VisibilityHint*/ attribute unsigned long min_x; -/*! visibility hint - see \ref GF_FEVT_VisibililityHint*/ +/*! visibility hint - see \ref GF_FEVT_VisibilityHint*/ attribute unsigned long min_y; -/*! visibility hint - see \ref GF_FEVT_VisibililityHint*/ +/*! visibility hint - see \ref GF_FEVT_VisibilityHint*/ attribute unsigned long max_x; -/*! visibility hint - see \ref GF_FEVT_VisibililityHint*/ +/*! visibility hint - see \ref GF_FEVT_VisibilityHint*/ attribute unsigned long max_y; -/*! visibility hint - see \ref GF_FEVT_VisibililityHint*/ +/*! visibility hint - see \ref GF_FEVT_VisibilityHint*/ attribute boolean is_gaze; /*! buffer reqs - see \ref GF_FEVT_BufferRequirement*/ @@ -886,9 +967,11 @@ interface JSArgDesc { /*! type of the argument*/ attribute unsigned long type; /*! default value of the argument*/ - optional attribute DOMString default=null; + optional attribute DOMString def=null; /*! min/max or enum values of the argument*/ optional attribute DOMString minmax_enum=null; + /*! argument hint type: "advanced", "expert", "hide" or null*/ + optional attribute DOMString hint=null; }; /*! interface used to describe filter capability*/ @@ -915,12 +998,11 @@ interface JSCapDesc { GF_PROP_PID_CODECID: string containing the codec name\n GF_PROP_PID_STREAM_TYPE: string containing the stream type name\n -GF_PROP_PID_AUDIO_FORMAT: string containing the audio format name\n -GF_PROP_PID_PIXFMT: string containing the pixel format name\n \n Other properties are mapped by property type:\n GF_PROP_BOOL: boolean\n GF_PROP_UINT: integer\n +GF_PROP_4CC: string\n GF_PROP_SINT: integer\n GF_PROP_LUINT: large integer\n GF_PROP_LSINT: large integer\n @@ -930,14 +1012,14 @@ GF_PROP_STRING: string\n GF_PROP_STRING_NO_COPY: string\n GF_PROP_VEC2: object with number properties "x" and "y"\n GF_PROP_VEC2I: object with integer properties "x" and "y"\n -GF_PROP_VEC3: object with number properties "x", "y" and "z"\n GF_PROP_VEC3I: object with integer properties "x", "y" and "z"\n -GF_PROP_VEC4: object with number properties "x", "y", "z" and "w"\n GF_PROP_VEC4I: object with integer properties "x", "y", "z" and "w"\n GF_PROP_FRACTION: object with integer properties "n" and "d", representing fraction n/d\n GF_PROP_FRACTION64: object with large integer properties "n" and "d", representing fraction n/d\n GF_PROP_UINT_LIST: array of integers\n +GF_PROP_4CC_LIST: array of strings\n GF_PROP_STRING_LIST: array of strings\n +All enumeration properties (pixel format, audio format, etc): string\n */ typedef Object FilterProperty; diff --git a/share/doc/idl/nodejs.idl b/share/doc/idl/nodejs.idl new file mode 100644 index 0000000..a5735ea --- /dev/null +++ b/share/doc/idl/nodejs.idl @@ -0,0 +1,1492 @@ +/* +\file +\brief silence ! +*/ + +typedef char *DOMString; + +/*! + +\defgroup nodegpac_grp GPAC module exports +\ingroup nodejs_grp +\brief Exported symbols for GPAC NodeJS. + +This section documents the JavaScript API used to query the filter session. + +Unless explictly stated, errors are handled through exceptions. + +All constants from GPAC are exported in the module object (e.g. use gpac.GF_Err ...) + + +The API is very close to the GPAC python bindings. + + +@{ + +*/ + + +/*! initialize libgpac - see \ref gf_sys_init + +When loading the module, libgpac is innitialized with no memory tracking and the default profile. Use this function only if you need to change these settings. This must be called before any other calls to gpac. + +\param mem_track mem tracker mode +\param profile profile name, null for default +\return +*/ +void init(unsigned long mem_track=0, DOMString profile=null); + +/*! convert error value to string message +\param err gpac error code (int) +\return string +*/ +DOMString e2s(long err); + +/*! set log tools and levels - see \ref gf_log_set_tools_levels +\note Make sure you have destroyed all associated gpac resources before calling this ! + +\param logs +\param reset if true, resets all logs to default +\return +*/ +void set_logs(DOMString logs, boolean reset=false); + +/*! get clock - see \ref gf_sys_clock +\return clock in milliseconds +*/ +unsigned long sys_clock(); + +/*! get high res clock - see \ref gf_sys_clock_high_res +\return clock in microseconds +*/ +unsigned long long sys_clock_high_res(); + +/*! set libgpac arguments - see \ref gf_sys_set_args +\param args Array of strings, the first string is ignored (considered to be the executable name) +*/ +void set_args(Array args); + +/*! set profiler (Remotery) callback - see \ref gf_sys_profiler_set_callback +\param callback function for Remotery message, takes a single string parameter and no return values +*/ +void set_rmt_fun(function callback); + +/*! send message to profiler (Remotery) - see \ref gf_sys_profiler_send +\param text text to send +*/ +void rmt_send(DOMString text); + +/*! check if profiler (Remotery) sampling is enabled - see \ref gf_sys_profiler_sampling_enabled +\return true if enabled, false otherwise +*/ +boolean rmt_on(); + +/*! enable or disable sampling in profiler (Remotery) - see \ref gf_sys_profiler_enable_sampling +\param do_enable enable or disable sampling +*/ +void rmt_enable(boolean do_enable); + +/*! GPAC event proc callback, initially set to null +\param evt the user event being dispatched +\return true to cancel the event +*/ +boolean on_event(_FilterEvent evt); + +/*! libgpac version */ +attribute readonly DOMString version; + +/*! libgpac copyright notice */ +attribute readonly DOMString copyright; + +/*! libgpac full copyright notice*/ +attribute readonly DOMString copyright_cite; + +/*! libgpac major ABI - see \ref gf_gpac_abi_major */ +attribute readonly unsigned long abi_major; + +/*! libgpac minor ABI - see \ref gf_gpac_abi_minor */ +attribute readonly unsigned long abi_minor; + +/*! libgpac micro ABI - see \ref gf_gpac_abi_micro */ +attribute readonly unsigned long abi_micro; + +/*! filter session constructor*/ +attribute _FilterSession FilterSession; + +/*! filter session constructor*/ +attribute _FilterEvent FilterEvent; + +/*! FileIO constructor*/ +attribute _FileIO FileIO; + +/*! @} */ + + + +/*! + +\defgroup nodefs_grp FilterSession class +\ingroup nodejs_grp +\brief FilterSession management + +See \ref GF_FilterSession + +The default behaviour is to run the session in blocking mode, which will prevent executing anything until the end of a session. +While this may be OK for workers or simple applications, it is obviously problematic if you have async tasks to be performed by your node app. + +An example approach for by-passing this is to create the session in non-blocking mode and use a recursive promise to run the session: +\code + +//create session in non-blocking mode: +let fs = new gpac.FilterSession(gpac.GF_FS_FLAG_NON_BLOCKING); + +//setup your filters + + +//Run session as Promise +const FilterSessionPromise = (fs_run_task) => { + var fsrun_promise = () => { + return (fs.last_task==false) ? fs_run_task().then(fsrun_promise) : Promise.resolve(); + } + return fsrun_promise(); +}; + +const run_task = () => { + return new Promise((resolve, reject) => { + resolve( fs.run_step() ); + }); +} +FilterSessionPromise(run_task).then( ).finally( ()=> { console.log('session is done'); } ) ); + +console.log('Entering NodeJS EventLoop'); + +\endcode + + +The filter session supports multithreaded mode, using e.g. +\code gpac.set_args(["", "-threads=N"]); +\endcode +However it is currently not capable of running asynchronous callbacks into Node. + +The consequences are: +- any custom JS filter will run on the main thread (EventLoop or worker thread) +- any packet dispatched by a custom filter and requiring a JS callback upon packet destruction (shared data dispatch) will force filters consuming these packets to run on the main thread as well. +- any filter assigned with a JS binding (only `dashin` for now) will be scheduled on the main thread + +For better multithreaded usage, it is therefore not recommended to use packets with shared JS data. + + +By default the filter session will run with implicit linking. + +@{ + +*/ + +/*! FilterSession object*/ +interface _FilterSession { + +/*! constructor for filter session - see \ref gf_fs_new_defaults. Other options MUST be passed as libgpac options using \ref set_args +\param flags session flags +*/ +FilterSession(unsigned long flags=0); + +/*! set to true if this is the last task running, readonly - see \ref gf_fs_is_last_task*/ +attribute readonly boolean last_task; + +/*! number of filters in session, readonly - see \ref gf_fs_get_filters_count*/ +attribute readonly unsigned long nb_filters; + +/*! current HTTP cumulated download rate, readonly - see \ref gf_fs_get_http_rate*/ +attribute readonly unsigned long http_bitrate; + +/*! HTTP max download rate - see \ref gf_fs_get_http_max_rate and \ref gf_fs_set_http_max_rate*/ +attribute unsigned long http_max_bitrate; + +/*! callback used whenever a new filter is added, initially set to null +\param filter _Filter object being added +*/ +void on_filter_new(_Filter filter); + +/*! callback used whenever a filter is destroyed, typically used by classes deriving from _FilterSession, initially set to null +\param filter _Filter object being removed +*/ +void on_filter_del(_Filter filter); + +/*! run the session - see \ref gf_fs_run */ +void run(); + +/*! load source filter - see \ref gf_fs_load_source +\param URL source URL to load +\param parentURL URL of parent resource for relative path resolution +\return new _Filter object +*/ +_Filter load_src(DOMString URL, DOMString parentURL=null); + +/*! load destination filter - see \ref gf_fs_load_destination +\param URL source URL to load +\param parentURL URL of parent resource for relative path resolution +\return new _Filter object +*/ +_Filter load_dst(DOMString URL, DOMString parentURL=null); + +/*! load a filter - see \ref gf_fs_load_filter +\param fname filter name and options +\return new _Filter object +*/ +_Filter load(DOMString fname); + +/*! post a user task to the filter sesison - see \ref gf_fs_post_user_task + +The task object must have an execute callback with no parameter and returning false to cancel the task or the reschedule time in milliseconds + +\param task task object to post +*/ +void post_task(Object task); + +/*! abort the session - see \ref gf_fs_abort +\param flush pipeline flush mode before abort +*/ +void abort(unsigned long flush=GF_FS_FLUSH_NONE); + +/*! get a filter by index - see \ref gf_fs_get_filter +\param index index of filter +\return _Filter object +*/ +_Filter get_filter(unsigned long index); + +/*! lock the session - see \ref gf_fs_lock_filters +\param lock if True, locks otherwise unlocks +*/ +void lock(boolean lock); + +/*! enable status reporting by filters - see \ref gf_fs_enable_reporting +\param do_report if True, enables reporting +*/ +void reporting(boolean do_report); + +/*! print statistics on stderr - see \ref gf_fs_print_stats*/ +void print_stats(); + +/*! print graph on stderr - see \ref gf_fs_print_connections*/ +void print_graph(); + + +/*! fire an event on the given filter if any, or on any filter accepting user events +\param evt FilterEvent to fire +\param filter _Filter to use as target +\param upstream if true, walks the chain towards the sink, otehrwise towards the source +*/ +void fire_event(FilterEvent evt, _Filter filter=null, boolean upstream=false); + +/*! checks if a given mime is supported - see \ref gf_fs_is_supported_mime +\param mime mime type to check +\return true or false +*/ +boolean is_supported_mime(DOMString mime); + +/*! checks if a given source URL is supported - see \ref gf_fs_is_supported_source +\param url URL to check +\param parent parent URL for relative URLs +\return true or false +*/ +boolean is_supported_source(DOMString url, DOMString parent=null); + +/*! creates a new custom filter to be filled by JS code - see \ref gf_fs_new_filter + +\note Custom filters are always created with the flag GF_FS_REG_MAIN_THREAD set, so that they always run in the main thread + +\param name name for the filter +\param flags filter flags +\return new custom filter +*/ +CustomFilter new_filter(DOMString name="Custom", unsigend long flags=0); + +}; + +/*! @} */ + +/*! + +\defgroup nodefilter_grp Filter class +\ingroup nodejs_grp +\brief Filter management + +See \ref GF_Filter + +@{ +*/ +/*! Filter object*/ +interface _Filter { + +/*! name of the filter, readonly - see \ref gf_filter_get_name*/ +attribute readonly DOMString name; + +/*! ID of the filter, readonly - see \ref gf_filter_get_id*/ +attribute readonly DOMString ID; + +/*! number of input pids for that filter, readonly - see \ref gf_filter_get_ipid_count*/ +attribute readonly unsigned long nb_ipid; + +/*! number of output pids for that filter, readonly - see \ref gf_filter_get_opid_count*/ +attribute readonly unsigned long nb_opid; + + +/*! remove this filter - see \ref gf_filter_remove*/ +void remove(); + +/*! send option update to this filter - see \ref gf_fs_send_update +\param name name of option +\param value value of option +*/ +void update(DOMString name, DOMString value); + + +/*! set a given filter as source for this filter - see \ref gf_filter_set_source +\note Setting a source will force the filter session linker to run in explicit linking mode. +\param src source filter +\param link_args link options +*/ +void set_source(_Filter src, DOMString link_args=null); + +/*! set a given filter as restricted source for this filter - see \ref gf_filter_set_source_restricted +\note Setting a source will force the filter session linker to run in explicit linking mode. +\param src source filter +\param link_args link options +*/ +void set_source_restricted(_Filter src, DOMString link_args=null); + +/*! insert a given filter after this filter - see \ref gf_filter_set_source and \ref gf_filter_reconnect_output +\param f _Filter to insert +\param link_args link options +*/ +void insert(_Filter f, DOMString link_args=null); + +/*! get an input pid property by name +\param idx index of input pid +\param prop_name name of property +\return property value or None if not found +*/ +PropertyValue ipid_prop(unsigned long idx, DOMStreing prop_name); + +/*! enumerate an input pid properties +\param idx index of input pid +\param callback_fun callback function taking three parameters, prop_name (string), propval (PropertyValue) and proptype (int, GPAC property data type) +*/ +void ipid_enum_props(unsigned long idx, function callback_fun); + +/*! get an output pid property by name +\param idx index of output pid +\param prop_name name of property +\return property value or null if not found +*/ +PropertyValue opid_prop(unsigned long idx, DOMString prop_name); + +/*! enumerate an output pid properties +\param idx index of output pid +\param callback_fun callback function taking three parameters, prop_name (string), propval (PPropertyValue) and proptype (int, GPAC property data type) +*/ +void opid_enum_props(unsigned long idx, function callback_fun); + +/*! gets the filter at the source of an input pid +\param idx index of input PID +\return filter or null if error +*/ +_Filter ipid_source(unsigned long idx); + +/*! gets the list of destination filters of an output pid +\param idx index of output PID +\return list of _Filter +*/ +Array opid_sinks(unsigned long idx); + +/*! gets all defined options / arguments for a filter +\return list of FilterArg +*/ +Array all_args(); + +/*! gets a property info on a filter - see \ref gf_filter_get_info and \ref gf_filter_get_info_str +\param info_name property to query +\return property value or None if not found +*/ +PropertyValue get_info(DOMString info_name); + +/*! gets the statistics of a filter - see \ref gf_filter_get_stats +\return stats object*/ +FilterStatistics get_statistics(); + +/*! enforces sourceID to be present for output pids of this filter - see \ref gf_filter_require_source_id*/ +void require_source_id(); + +/*! Binds the given object to the underlying filter for callbacks override - only supported by DASH demuxer for the current time + +For DASH, the object must derive implement the methods of the \ref _DASHCustomAlgorithm interface + +\param interf interface object to bind +*/ +void bind(object interf); + +}; + +/*! Statistics object for filter as defined in libgpac. + +Fields have the same types, names and semantics as \ref GF_FilterStats, except: +- filter which is not present, +- filter_alias which is exposed as a boolean. +*/ +interface FilterStatistics { + +}; + + +/*! PropertyValue for filter, PIDs and packets are passed as +: +- native JS types for integers and strings +- nFraction for 32 and 64 bit fractions +- Vec2 for 2D float and interger vectors +- Vec3 for 3D interger vectors +- Vec4 for 4D interger vectors +- ArrayBuffer for data, with data being copied +- Array of above types for list properties + +Pointer properties are passed back as "INTERNAL_POINTER" string and cannot be set. + +Properties corresponding to constants are usually passed as strings, for example `StreamType`, `CodecID`, `PixelFormat`, `AudioFormat`. +*/ +interface PropertyValue { + +}; + +/*! fraction object */ +interface nFraction { + /*! integer or long long numerator*/ + number num; + /*! unsigned integer or unsigned long long denominator*/ + number den; +}; + +/*! 2D vector object */ +interface Vec2 { + /*! integer or float X value*/ + number x; + /*! integer or float Y value*/ + number y; +}; + +/*! 3D vector object */ +interface Vec3 { + /*! X value */ + long x; + /*! Y value */ + long y; + /*! Z value */ + long z; +}; + +/*! 4D vector object */ +interface Vec4 { + /*! X value */ + long x; + /*! Y value */ + long y; + /*! Z value */ + long z; + /*! W value */ + long w; +}; + + +/*! @} */ + +/*! + +\defgroup nodefiltercust_grp CustomFilter class +\ingroup nodejs_grp +\brief User-defined filters + +A custom filter allows your application to interact closely with the media pipeline, but cannot be used in graph resolution. +Custom filters can be sources, sinks, or intermediate filters. The following limitations however exist: +- custom filters will not be cloned +- custom filters cannot be used as sources of filters loading a source filter graph dynamically, such as the dashin filter. +- custom filters cannot be used as destination of filters loading a destination filter graph dynamically, such as the dasher filters. + +A custom filter must implement the \ref CustomFilter class, and optionally provide the following methods +- configure_pid: callback for PID configuration, mandatory if your filter is not a source +- process: callback for processing +- process_event: callback for processing and event +- reconfigure_output: callback for output reconfiguration (PID capability negociation) + +A custom filter must also declare its capabilities, input and output, using push_cap method +\code + +let fs = new gpac.FilterSession(); +let cust = fs.new_filter("NodeJS_Test"); + +//we accept any number of input pids +cust.set_max_pids(-1); +cust.pids = []; + +cust.push_cap('StreamType', 'Visual', gpac.GF_CAPS_INPUT); +cust.push_cap('StreamType', 'Audio', gpac.GF_CAPS_INPUT); + +cust.configure_pid = function(pid, is_remove) +{ + if (this.pids.indexOf(pid) < 0) { + this.pids.push(pid); + console.log('New PID !'); + } else if (is_remove) { + console.log('PID remove !'); + } else { + console.log('PID reconfigure !'); + } + return gpac.GF_OK; +} + +cust.process = function() { + let nb_eos=0; + + this.pids.forEach(pid =>{ + if (pid.eos) { + nb_eos++; + return; + } + let pck = pid.get_packet(); + if (!pck) return; + //do something + + //done + pid.drop_packet(); + return; + } + if (nb_eos == this.pids.length) + return gpac.GF_EOS; + + return gpac.GF_OK; +} +cust.process_event = function(evt) +{ + //do something, return true to cancel event + + return false; +} +\endcode + + +See \ref GF_Filter + +@{ +*/ + +/*! Custom filter object*/ +interface CustomFilter { + +/*! filter blocking is enabled - see \ref gf_filter_block_enabled*/ +attribute readonly boolean block_enabled; + +/*! maximum output buffer time - see \ref gf_filter_get_output_buffer_max*/ +attribute readonly unsigned long output_buffer; + +/*! maximum plyaout buffer time - see \ref gf_filter_get_output_buffer_max*/ +attribute readonly unsigned long playout_buffer; + +/*! all sinks are done for this filter - see \ref gf_filter_all_sinks_done*/ +attribute readonly boolean sinks_done; + +/*! number of queued events on the filter - see \ref gf_filter_get_num_events_queued*/ +attribute readonly unsigned long nb_evts_queued; + +/*! clock hint value in microseconds - see \ref gf_filter_get_clock_hint*/ +attribute readonly unsigned long long clock_hint_time; + +/*! clock hint media time as fraction - see \ref gf_filter_get_clock_hint*/ +attribute readonly nFraction clock_hint_mediatime; + +/*! indicating connections are pending on the filter, readonly - see \ref gf_filter_connections_pending*/ +attribute readonly boolean connections_pending; + + + +/*! callback used whenever a new filter pid is configured, initially set to null +\param pid the PID to configure +\param is_remove set to true if PID is being removed +\return error code + +\warning the return value SHALL be set +*/ +GF_Err configure_pid(_FilterPid pid, boolean is_remove); + +/*! callback used by the filter to process data, initially set to null +\return error code + +\warning the return value SHALL be set +*/ +GF_Err process(); + +/*! callback used whenever a new filter is added, initially set to null +\param event the event being processed (read-only) +\return true to cancel the event, false otherwise + +\warning the return value SHALL be set +*/ +boolean process_event(_FilterEvent event); + +/*! callback used whenever an output pid is to be reconfigured (capability negotiation), initially set to null +\param opid the filter output pid to reconfigure +\return error if any, usualy GF_NOT_SUPPORTED if capability cannot be changed + +\warning the return value SHALL be set +*/ +GF_Err reconfigure_output(_FilterPid *opid); + + + +/*! push a capability in the current capability bundle - see \ref gf_filter_push_caps +\param pcode capability name +\param prop capability value +\param flag capability flags (input, output, etc) +\param priority capability priority +\param custom_type type of property if user-defined property. If not set and user-defined, property is a string +*/ +void push_cap(DOMString pcode, PropertyValue prop, unsigned long flag, unsigned long priority=0, unsigned long custom_type=0); + +/*! create a new output pid for this filter - see \ref gf_filter_pid_new +\return _FilterPid object +*/ +_FilterPid new_pid(); + +/*! update filter status - see \ref gf_filter_update_status +\param status status +\param percent progress in per 10000 +*/ +void update_status(DOMString status, unsigned long percent=0); + +/*! reschedule the filter after a given delay - see \ref gf_filter_ask_rt_reschedule and \ref gf_filter_post_process_task +\param when delay in microseconds +*/ +void reschedule(unsigned long when=0); + +/*! notify an internal failure of the filter has happend - see \ref gf_filter_notification_failure and \ref gf_filter_setup_failure +\param err the failure reason (gpac error code, int) +\param error_type the failure notification type. Can be one of: + - GF_SETUP_ERROR: notification is a setup error, the filter chain was never connected + - GF_NOTIF_ERROR: notification is an error but keep the filter chain connected + - GF_NOTIF_ERROR_AND_DISCONNECT: notification is an error and disconnect the filter chain +*/ +void notify_failure(GF_Err err, unsigned long error_type=GF_SETUP_ERROR); + +/*! make the filter sticky - see \ref gf_filter_make_sticky*/ +void make_sticky(); + +/*! prevent blocking on the filter - see \ref gf_filter_prevent_blocking +\param enable if true, blocking prevention is enabled +*/ +void prevent_blocking(boolean enable); + +/*! block eos signaling on the filter - see \ref gf_filter_block_eos +\param enable if true, eos blocking is enabled +*/ +void block_eos(boolean enable); + +/*! set maximum number of extra pids accepted by this filter - see \ref gf_filter_set_max_extra_input_pids +\param max_pids number of extra pids, -1 for no limits +*/ +void set_max_pids(long max_pids); + +/*! set clock hint - see \ref gf_filter_hint_single_clock +\param clock_us clock in microseconds +\param media_time media time as nFraction +*/ +void hint_clock(unsigned long long clock_us, nFraction media_time); + + +}; + + +/*! Custom filter PID object*/ +interface _FilterPid { + + +/*! name of the PID - see \ref gf_filter_pid_get_name and \ref gf_filter_pid_set_name*/ +attribute DOMString name; + +/*! name of the parent filter - see \ref gf_filter_pid_get_filter_name*/ +attribute readonly DOMString filter_name; + +/*! end of stream property of PID - see \ref gf_filter_pid_is_eos and \ref gf_filter_pid_set_eos*/ +attribute boolean eos; + +/*! True if end of stream was seen in the chain but has not yet reached the filter - see \ref gf_filter_pid_has_seen_eos*/ +attribute readonly boolean has_seen_eos; + +/*! True if end of stream was seen on the input PID but some packets are still to be processed - see \ref gf_filter_pid_eos_received*/ +attribute readonly boolean eos_received; + +/*! True if PID would block - see \ref gf_filter_pid_would_block*/ +attribute readonly boolean would_block; + +/*! maximum buffer of PID in microseconds - see \ref gf_filter_pid_get_max_buffer and \ref gf_filter_pid_set_max_buffer*/ +attribute unsigned long long max_buffer; + +/*! buffer of PID in microseconds - see \ref gf_filter_pid_query_buffer_duration*/ +attribute readonly unsigned long long buffer; + +/*! True if buffer is full - see \ref gf_filter_pid_query_buffer_duration*/ +attribute readonly boolean buffer_full; + +/*! True if no pending packet - see \ref gf_filter_pid_first_packet_is_empty*/ +attribute readonly boolean first_empty; + +/*! value of CTS of first pending packet, null if none - see \ref gf_filter_pid_get_first_packet_cts*/ +attribute readonly unsigned long long first_cts; + +/*! number of queued packets for input pid - see \ref gf_filter_pid_get_packet_count*/ +attribute readonly unsigned long self.nb_pck_queued; + +/*! timescale of pid - see \ref gf_filter_pid_get_timescale*/ +attribute readonly unsigned long timescale; + +/*! minimum packet duration (in timescale) of pid - see \ref gf_filter_pid_get_min_pck_duration*/ +attribute readonly unsigned long min_pck_dur; + +/*! True if PID is playing - see \ref gf_filter_pid_is_playing*/ +attribute readonly boolean playing; + +/*! Next estimated timestamp on pid - see \ref gf_filter_pid_get_next_ts*/ +attribute readonly unsigned long long next_ts; + + + +/*! send an event on the pid - see \ref gf_filter_pid_send_event +\param evt filter event to send +*/ +void send_event(_FilterEvent evt); + +/*! removes this output pid - see \ref gf_filter_pid_remove*/ +void remove(); + +/*! enumerates property on pid +\param callback_obj callback object to use, must have a 'on_prop_enum' method defined taking three parameters, prop_name (string), propval (PropertyValue) and ptype (int, GPAC property data type) +*/ +void enum_props(function callback_obj); + +/*! get a PID property +\param pname property name +\return property value or null if not found +*/ +PropertyValue get_prop(DOMString pname); + +/*! get a PID info +\param pname property name +\return property value or null if not found +*/ +PropertyValue get_info(DOMString pname); + +/*! get first packet of input PID - see gf_filter_pid_get_packet +\return packet or null if no packet available +*/ +_FilterPacket get_packet(); + +/*! drops (removes) the first packet of input PID - see \ref gf_filter_pid_drop_packet +*/ +void drop_packet(); + +/*! copy property of given PID to the current pid - see \ref gf_filter_pid_copy_properties +\param ipid filter pid to copy from +*/ +void copy_props(_FilterPid ipid); + +/*! removes all properties of the current pid - see \ref gf_filter_pid_reset_properties*/ +void reset_props(self); + +/*! forward a packet on the current pid - see \ref gf_filter_pck_forward +\param ipck packet to forward +*/ +void forward(_FilterPacket ipck); + +/*! set a property the current pid - see \ref gf_filter_pid_set_property and \ref gf_filter_pid_set_property_str +\param pcode property type +\param prop property value to set, or null to remove property +\param custom_type type of property if user-defined property. If not set and user-defined, property is a string +*/ +void set_prop(DOMString pcode, PropertyValue prop, unsigend long custom_type); + +/*! set a info property the current pid - see \ref gf_filter_pid_set_info and \ref gf_filter_pid_set_info_str +\param pcode property type +\param prop property value to set, or null to remove property +\param custom_type type of property if user-defined property. If not set and user-defined, property is a string +*/ +void set_info(DOMString pcode, PropertyValue prop, unsigned long custom_type=0); + +/*! clears EOS on the current PID - see \ref gf_filter_pid_clear_eos +\param all_pids if true, clears eos on all input pids +*/ +void clear_eos(boolean all_pids); + +/*! check PID properties match capability of filter - see \ref gf_filter_pid_check_caps*/ +void check_caps(); + +/*! discard blocking mode on PID - see \ref gf_filter_pid_discard_block*/ +void discard_block(); + +/*! allow direct dispatch of output to destinations - see \ref gf_filter_pid_allow_direct_dispatch*/ +void allow_direct_dispatch(); + +/*! get current clock type info - see \ref gf_filter_pid_get_clock_info +\return clock type +*/ +unsigned long get_clock_type(); + +/*! get current clock time stamp - see \ref gf_filter_pid_get_clock_info +\return clock timestamp +*/ +_Fraction get_clock_timestamp(); + +/*! check if a filter is in the parent filter chain of the pid - see \ref gf_filter_pid_is_filter_in_parents +\param filter filter to check +\return true or false +*/ +boolean is_filter_in_parents(_Filter filter); + +/*! get buffer occupancy - see \ref gf_filter_pid_get_buffer_occupancy +\return buffer occupancy object +*/ +_BufferOccupancy get_buffer_occupancy(); + +/*! sets loose connect mode - see \ref gf_filter_pid_set_loose_connect*/ +void loose_connect(); + +/*! sets framing mode - see \ref gf_filter_pid_set_framing_mode +\param framed if true, complete frames only will be delivered on the pid +*/ +void set_framing(boolean framed); + +/*! sets clock mode - see \ref gf_filter_pid_set_clock_mode +#\param cmode clock mode operation of filter +*/ +void set_clock_mode(boolean cmode); + +/*! sets discard mode - see \ref gf_filter_pid_set_discard +\param do_discard if True, discard is on +*/ +void set_discard(boolean do_discard); + +/*! enforces sourceID to be present for output pids of this filter - see \ref gf_filter_pid_require_source_id*/ +void require_source_id(); + +/*! sets DTS recomputing mode - see \ref gf_filter_pid_recompute_dts +\param do_compute if True, DTS are recomputed +*/ +void recompute_dts(boolean do_compute); + +/*! queries a capability property on output PID - see \ref gf_filter_pid_caps_query and \ref gf_filter_pid_caps_query_str +\param pcode property to check +\return property value if found, null otherwise +*/ +PropertyValue query_cap(DOMString pcode); + +/*! negociates a capability property on input PID - see \ref gf_filter_pid_negociate_property and \ref gf_filter_pid_negociate_property_dyn +\param pcode property to negotiate +\param prop property to negotiate +\param custom_type type of property if user-defined property. If not set and user-defined, property is a string +*/ +void negociate_cap(DOMString pcode, PropertyValue prop, unsigned long custom_type=0); + +/*! resolves a template string - see \ref gf_filter_pid_resolve_file_template +\param template the template string +\param file_idx the file index +\param suffix the file suffix +\return the resolved template string +*/ +DOMString resolve_template(DOMString template, unsigned long file_idx=0, DOMString suffix=null); + +/*! creates a new packet referring to an existing packet - see \ref gf_filter_pck_new_ref +\param ipck the input (referenced) packet +\param size the data size of the new packet +\param offset the offset in the original data +\return the new FilterPacket or None if failure +*/ +_FilterPacket new_pck_ref(_FilterPacket ipck, unsigned long size=0, unsigned long offset=0); + + +/*! creates a new packet of the given size, allocating memory in libgpac - see \ref gf_filter_pck_new_alloc +\param size the data size of the new packet +\return the new FilterPacket or None if failure +*/ +_FilterPacket new_pck(unsigned long size=0); + +/*! creates a new packet sharing memory of the filter - see \ref gf_filter_pck_new_shared +The filter object must have a `packet_release` method with arguments [ FilterPid, FilterPacket ] +\param data the data to use +\return the new FilterPacket or None if failure +*/ +_FilterPacket new_pck_shared(ArrayBuffer data); + +/*! creates a new packet copying a source packet - see \ref gf_filter_pck_new_copy +\param ipck the FilterPacket to copy +\return the new FilterPacket or None if failure +*/ +_FilterPacket new_pck_copy(_FilterPacket ipck); + +/*! creates a new packet cloning a source packet - see \ref gf_filter_pck_new_clone +\param ipck the FilterPacket to clone +\return the new FilterPacket or None if failure +*/ +_FilterPacket new_pck_clone(_FilterPacket ipck); + +}; + +/*! buffer occupancy descriptor*/ +interface _BufferOccupancy +{ +/*! maximum number of packets (partial or full AU) allowed in buffer*/ +unsigned long max_units; + +/*! number of block allowed in buffer*/ +unsigned long nb_pck; + +/*! maximum buffer duration in microseconds*/ +unsigned long max_dur; + +/*! buffer duration in microseconds*/ +unsigned long dur; + +/*! if true, the session has been aborted and this is the final flush for this buffer*/ +boolean is_final_flush; + +}; + +/*! filter packet for custom filters + +Unless specified, properties are all read-only for input packets, and read/write for output packets. +*/ +interface _FilterPacket +{ + +/*! Decode Timestamp, or null not set - see \ref gf_filter_pck_get_dts and \ref gf_filter_pck_set_dts*/ +attribute unsigned long long dts; + +/*! Compose Timestamp or null if not set - see \ref gf_filter_pck_get_cts and \ref gf_filter_pck_set_cts*/ +attribute unsigned long long cts; + +/*! SAP type - see \ref gf_filter_pck_get_sap and \ref gf_filter_pck_set_sap*/ +attribute unsigned long sap; + +/*! Duration - see \ref gf_filter_pck_get_duration and \ref gf_filter_pck_set_duration*/ +attribute unsigned long dur; + +/*! Size of packet data, readonly*/ +attribute unsigned long size; + +/*! Packet data - see \ref gf_filter_pck_get_data +The property MUST be treated as readonly (shall not be set). For non-refs output packets, content of the array buffer can be modified + +\warning The array buffer is not tracked and is live to avoid doing a memory copy. This means you SHALL NOT access this ArrayBuffer once the packet is discarded (drop without ref, final unref, send) +*/ +attribute ArrayBuffer data; + +/*! frame start - see \ref gf_filter_pck_get_framing and \ref gf_filter_pck_set_framing*/ +attribute boolean start; + +#/*! frame end - see \ref gf_filter_pck_get_framing and \ref gf_filter_pck_set_framing*/ +attribute boolean end; + +/*! associated timescale, readonly - see \ref gf_filter_pck_get_timescale*/ +attribute unsigned long timescale; + +/*! Interlaced flags - see \ref gf_filter_pck_get_interlaced and \ref gf_filter_pck_set_interlaced*/ +attribute unsigned long interlaced; + +/*! Corrupted flag - see \ref gf_filter_pck_get_corrupted and \ref gf_filter_pck_set_corrupted*/ +attribute boolean corrupted; + +#/*! Seek flag - see \ref gf_filter_pck_get_seek_flag and \ref gf_filter_pck_set_seek_flag*/ +attribute boolean seek; + +/*! Byte offset or null if not set - see \ref gf_filter_pck_get_byte_offset and \ref gf_filter_pck_set_byte_offset*/ +attribute unsigned long long byte_offset; + +/*! Roll info - see \ref gf_filter_pck_get_roll_info and \ref gf_filter_pck_set_roll_info*/ +attribute long roll; + +/*! Encryption flags - see \ref gf_filter_pck_get_crypt_flags and \ref gf_filter_pck_set_crypt_flags*/ +attribute unsigned long crypt; + +/*! Clock reference flag - see \ref gf_filter_pck_get_clock_type and \ref gf_filter_pck_set_clock_type*/ +attribute unsigned long clock; + +/*! Carousel version - see \ref gf_filter_pck_get_carousel_version and \ref gf_filter_pck_set_carousel_version*/ +attribute unsigned long carousel; + +/*! Sequence number - see \ref gf_filter_pck_get_seq_num and \ref gf_filter_pck_set_seq_num*/ +attribute unsigned long seqnum; + +/*! Dependency flags - see \ref gf_filter_pck_get_dependency_flags and \ref gf_filter_pck_set_dependency_flags*/ +attribute unsigned long deps; + +/*! true if packet holds a GF_FrameInterface object and not a data packet - always readonly*/ +attribute readonly boolean frame_ifce; + +/*! true if packet is a blocking reference - see \ref gf_filter_pck_is_blocking_ref - always readonly*/ +attribute readonly boolean blocking_ref; + + +/*! enumerate an packet properties +\param callback_obj callback object to use, must have a 'on_prop_enum' method defined taking three parameters, prop_name (string), propval (PropertyValue) and ptype (int, GPAC property data type) +*/ +void enum_props(function callback_obj); + +/*! get a packet property - see \ref gf_filter_pck_get_property and \ref gf_filter_pck_get_property_str +\param prop_name name of property to get +\return property value, or None if not found +*/ +PropertyValue get_prop(DOMString prop_name); + +/*! increase packet reference count - see \ref gf_filter_pck_ref_ex*/ +void ref(); + +/*! decrease packet reference count - see \ref gf_filter_pck_unref*/ +void unref(); + +/*! discard an output packet instead of sending it - see \ref gf_filter_pck_discard*/ +void discard(); + +/*! creates a new packet cloning a source packet - see \ref gf_filter_pck_dangling_copy. +The resulting packet is read/write mode and may have its own memory allocated. +This is typically used by sink filters wishing to access underling GPU data of a packet using frame interface. +the resulting packet can be explicitly discarded using \ref discard, otherwise will be garrbage collected. +\param cached_pck if set, will be reuse for creation of new packet. This can greatly reduce memory allocations +\return the new FilterPacket or None if failure or None if failure ( if grabbing the frame into a local copy failed) +*/ +_FilterPacket clone(_FilterPacket cached_pck=null); + +/*! mark an output packet as readonly - see \ref gf_filter_pck_set_readonly*/ +void readonly(); + +/*! send the packet - see \ref gf_filter_pck_send*/ +void send(); + +/*! copy properties of source packet in this packet - see \ref gf_filter_pck_merge_properties +\param ipck source packet*/ +void copy_props(_FilterPacket ipck); + +/*! set property in this packet - see \ref gf_filter_pck_set_property and \ref gf_filter_pck_set_property_str +\param pcode name of property +\param prop property value to set, or null to remove property +\param custom_type type of property if user-defined property. If not set and user-defined, property is a string +*/ +void set_prop(DOMString pcode, PropertyValue prop, unsigned long custom_type=0); + +/*! truncates an output packet to the given size - see \ref gf_filter_pck_truncate +\param size new size of packet +*/ +void truncate(unsigned long size); +}; + + +/*! event object for filters and GPAC event proc. + +The variables defined have the same names as the fields in the various unions of \ref __gf_filter_event. + +The variables are defined depending on the event type. + +Additional variables are defined: +- name: string decribing the event type +- ui_type: integer giving the UI event type (see \ref GF_Event) +- ui_name: string decribing the UI event type + +Events properties are read-only for input events and read/write for events created by the JS code. +*/ +interface _FilterEvent +{ + +}; + + +/*! @} */ + + + +/*! + +\defgroup nodedash_grp DASHAlgorithm interface +\ingroup nodejs_grp +\brief DASH and HLS user-defined rate adaptation algorithms + + +The DASH demuxer can be provided with a custom JS algorithm, provided as an object implementing the the DASHAlgorithm interface. + +When running the session in multithreaded mode, the dash demuxer will always be scheduled on the main thread if a custom algorithm is bound. + +@{ + +*/ + +/*! interface for custom DASH algorithms + +Callbacks may be changed at runtime, however if the object passed to initialize the binding has no on_download_monitor function, rate monitoring will be disabled for the binding*/ +interface _DASHCustomAlgorithm +{ + +/*! Callback (optional) called upon a period reset. +\param reset_type indicate the type of period reset. Values can be: + - 0: end of period (groups are no longer valid) + - 1: start of a static period + - 2: start of a dynamic (live) period +*/ +void on_period_reset(unsigned long reset_type); + + +/*! Callback (optional) called when a new group (adaptation set) is created +\param group the newly created dash group +*/ +void on_new_group(_DASHGroup group); + +/*! Callback (mandatory) called at the end of the segment download to perform rate adaptation +\param group the group on which to perform adaptation +\param base_group the associated base group (tiling only), or None if no base group +\param force_low_complexity indicates that the client would like a lower complexity (typically because it is dropping frames) +\param stats the statistics for the downloaded segment +\return value can be: + - new quality index, + - -1 to take no decision + - -2 to disable quality (debug, will drop segment) + - other negative values are handled as error +*/ +long on_rate_adaptation(_DASHGroup group, _DASHGroup base_group, boolean force_low_complexity, _DASHGroupStatistics stats); + +/*! Callback (optional) called on regular basis during a segment download +\param group the group associated with the current download +\param stats the current statistics for the download +\return value can be: + - `-1` to continue download + - `-2` to abort download but without retrying to downloading the same segment at lower quality + - the index of the new quality to download for the same segment index (same time) +*/ +long on_download_monitor(_DASHGroup group, _DASHGroupDownloadStatistics stats); + + +}; + + +/*! interface for custom DASH groups*/ +interface _DASHGroup +{ + +/*! Index of group, as used in callbacks */ +attribute readonly idx; + +/*! List of _DASHQualityInfo for group*/ +attribute readonly Array qualities; + +/*! period duration in milliseconds, 0 if unknwon*/ +attribute readonly unsigned long duration; + +/*! SRD object or null if no SRD defined*/ +_DASHSRD SRD; +}; + +/*! interface for custom DASH groups*/ +interface _DASHQualityInfo +{ + +/*! bandwidth in bits per second*/ +attribute readonly unsigned long bandwidth; + +/*! ID (representation ID in DASH)*/ +attribute readonly DOMString ID; + +/*! MIME type*/ +attribute readonly DOMString mime; + +/*! codec parameter string*/ +attribute readonly DOMString codec; + +/*! width in pixels, 0 if not visual*/ +attribute readonly unsigned long width; + +/*! height in pixels, 0 if not visual*/ +attribute readonly unsigned long height; + +/*! interlaced flag, false 0 if not visual*/ +attribute readonly boolean interlaced; + +/*! Frame Rate (Fraction), 0/0 if not visual*/ +attribute readonly _Fraction fps; + +/*! Sample Aspect Ration (Fraction), 0/0 if not visual*/ +attribute readonly _Fraction sar; + +/*! Samplerate, 0 if not audio*/ +attribute readonly unsigned long sample_rate; + +/*! Number of channels, 0 if not audio*/ +attribute readonly unsigned long nb_channels; + +/*! set to true if quality is disabled (no playback support)*/ +attribute readonly disabled disabled; + +/*! set to true if quality is selected*/ +attribute readonly boolean is_selected; + +/*! AST offset for DASH low latency mode, 0 otherwise*/ +attribute readonly double ast_offset; + +/*! Average segment duration in seconds, 0 if unknown*/ +attribute readonly double avg_duration; + +/*! list of segment _DASHSegmentInfo for onDemand profiles or empty otherwise*/ +attribute readonly Array sizes; + +}; + +/*! segemnt size info*/ +interface _DASHSegmentInfo +{ +/*! segemnt size*/ +attribute readonly unsigned long long size; +/*! segemnt duration*/ +attribute readonly unsigned long duration; +}; + +/*! statistics for rate adaptation*/ +interface _DASHGroupStatistics +{ +/*! download rate of last segment in bits per second, divided by current playback speed*/ +attribute readonly unsigned long download_rate; + +/*! size of last segment in bytes*/ +attribute readonly unsigned long file_size; + +/*! current playback speed*/ +attribute readonly double speed; + +/*! max playback speed based on associated codec runtime statistics*/ +attribute readonly double max_available_speed; + +/*! display width in pixels of object*/ +attribute readonly unsigned long display_width; + +/*! display height in pixels of object*/ +attribute readonly unsigned long display_height; + +/*! index of current quality*/ +attribute readonly unsigned long active_quality_idx; + +/*! minimum buffer in milliseconds, below witch rebuffer occurs*/ +attribute readonly unsigned long buffer_min; + +/*! maximum buffer in milliseconds, algorithm should not fill more than this*/ +attribute readonly unsigned long self.buffer_max; + +/*! current buffer in milliseconds*/ +attribute readonly unsigned long self.buffer; + +/*! degradation hint, 0 means no degradation, 100 means tile completely hidden*/ +attribute readonly unsigned long self.quality_degradation_hint; + +/*! cumulated download rate of all active groups - 0 means all files are local*/ +attribute readonly unsigned long self.total_rate; + +}; + +/*! statistics for download monitoring*/ +interface _DASHGroupStatistics +{ + +/*! download rate of last segment in bits per second*/ +attribute readonly unsigned long bits_per_sec; + +/*! total number of bytes in segment*/ +attribute readonly unsigned long total_bytes; + +/*! number of downloaded bytes from segment (starting from first byte)*/ +attribute readonly unsigned long long bytes_done; + +/*! number of microseconds elapsed since segment was scheduled for download*/ +attribute readonly unsigned longlong time_since_start; + +/*! current buffer length in milliseconds*/ +attribute readonly unsigned long buffer_dur; + +/*! duration of segment being downloaded, in milliseconds - 0 if unknown*/ +attribute readonly unsigned long current_seg_dur; + +}; + +/*! Spacial Relationship Descriptor for DASH group*/ +interface _DASHSRD +{ +/*! X coordinate of SRD for this tile*/ +attribute readonly unsigned long x; + +/*! Y coordinate of SRD for this tile*/ +attribute readonly unsigned long y; + +/*! width of SRD for this tile - 0 for tile base track*/ +attribute readonly unsigned long w; + +/*! height of SRD for this tile - 0 for tile base track*/ +attribute readonly unsigned long h; + +/*! total width of SRD descriptor for this tile*/ +attribute readonly unsigned long fw; + +/*! total height of SRD descriptor for this tile*/ +attribute readonly unsigned long fh; + +}; + + +/*! @} */ + + + +/*! + +\defgroup fileio_grp FileIO interface +\ingroup nodejs_grp +\brief File IO wrapper + + +FileIO allows redirecting calls to file access (open, close, read, write) to NodeJS rather than using system calls. + +This allows generating content in NodeJS without any disk IO, or passing NodeJS data as input to GPAC without intermediate file. + +See \ref GF_FileIO for more details + +A FileIO object is constructed from the URL to wrap and a factory object with callbacks used to access the file. +For example, to wrap a file for input: +\code +//create the FileIO factory +let factory = { +open: function(url, mode) { ... }, +close: function() { ... }, +read: function(buffer) { ... }, +seek: function(position, whence) { ... }, +tell: function() { ... }, +eof: function() { ... } +}; + +//create the FileIO +let fio = new FileIO("somefile.mp4", factory_obj); + +//load a source filter using this FileIO +let src = filter_sess.load_src(fio.url); + +\endcode + +\warning All callbacks of the factory object MUST perform synchronously + +The URL passed to the constructor indentifies the file name wrapped. + + +Some file types, such as HLS or DASH manifest, may imply reading or writing several files. +To handle these cases, a new JS object is created for each call to open(). + +\warning This object is an empty JS object, not a clone of the factory object (difference with Python bindings). + +All FileIO callbacks will be done in the main thread. + + +@{ + +*/ + +/*! interface for customFileIO object +*/ +interface _FileIO +{ + +/*! constructor for FileIO object - see \ref gf_fileio_new + +\param url URL to wrap, either source or destination +\param factory factory for object creation +\param direct_mem if true, the buffer passed to read and write callbacks is only a wrapper around GPAC internal mem and is no longer valid at the end of the call (detached). If false, the buffer passed is a copy (slower). + +\note For NAPI less than 7, direct_mem is forced to false. +*/ +FileIO(DOMString url, _FileIOFactory factory, boolean direct_mem=true); + +/*! gfio:// url corresponding to the fileIO object. This is the URL that must be passed to filter arguments*/ +attribute readonly DOMString url; +}; + + +/*! interface object for file IO*/ +interface _FileIOFactory +{ + +/*! open a URL +\param URL the final URL to open +\param mode the open mode as in \ref gf_fopen +\param parent the parent _FileIO object +\return true if success, false if error + +\note When opening a file, a new empty object is created and open is called with `this` being the new object. The object will be kept live until the file is closed. + +\note There is no guarantee that the URL is checked for existence before calling open + +\note There is no guarantee that the first call to open is on the URL provided for the constructor (e.g. for DASH generation, this will depend on the DASH profile used which may require to write the manifest after one or more segments) + +\warning This callback MUST be provided in the factory object +*/ +boolean open(DOMString URL, DOMString mode, _FileIO parent); + +/*! close the file object + +\warning This callback MUST be provided in the factory object +*/ +void close(); + + +/*! read the file object from its current position +\param buffer the buffer to read +\return the number of bytes read into the buffer + +This callback can be omitted for write-only files +*/ +unsigned long read(Uint8Array buffer); + +/*! write the file object from its current position +\param buffer the buffer to read +\return the number of bytes written to file + +This callback can be omitted for read-only files +*/ +unsigned long write(Uint8Array buffer); + +/*! seek the file object - see \ref gf_fseek +\param position the position in the file +\param whence the offset in the file (0: begin, 1: current position, 2: end) +\return 0 if no error, error code otherwise + +\warning This callback MUST be provided in the factory object +*/ +unsigned long seek(unsigned long long position, unsigned long whence); + +/*! get position in the file object - see \ref gf_ftell +\return position in the file + +\warning This callback MUST be provided in the factory object +*/ +unsigned long long tell(); + + +/*! check if file position is at end of file - see \ref gf_feof +\return true if end of file is reached, false otherwise + +\warning This callback MUST be provided in the factory object +*/ +boolean eof(); + +/*! check if the given file exists - see \ref gf_file_exists +\param URL the final URL to open +\return true if file exists, false otherwise +*/ +boolean exists(DOMString URL); + +}; + + +/*! @} */ + + diff --git a/share/doc/idl/webgl.idl b/share/doc/idl/webgl.idl index ef39c92..2e8be1e 100644 --- a/share/doc/idl/webgl.idl +++ b/share/doc/idl/webgl.idl @@ -30,7 +30,6 @@ import {WebGLContext} from 'webgl' The API implements most of WebGL 1.0 context calls. What is not supported: - premultiplied alpha (gl.GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL & co) -- flip (gl.UNPACK_FLIP_Y_WEBGL), this must be done in the shader - WebGL extensions (gl.getExtension) # WebGL Context @@ -46,11 +45,11 @@ A filter is responsible for deciding when to issue GL calls: this can be in a pr The WebGL API in GPAC work by default on offscreen framebuffer objects: - the color attachment is always a texture object, RGBA 32 bits or RGB 24 bits (see WebGLContextAttributes) -- the depth attachment is a renderbuffer by default and cannot be exported; this behaviour can be changed by setting the "depth" attribute of the WebGLContextAttributes object to "texture" before creation, thereby creating a depth texture attachment; the format is 24 bit precision integer (desktop) or 16 bit precision integer (iOS, Android). +- the depth attachment is a renderbuffer by default and cannot be exported; this behavior can be changed by setting the "depth" attribute of the WebGLContextAttributes object to "texture" before creation, thereby creating a depth texture attachment; the format is 24 bit precision integer (desktop) or 16 bit precision integer (iOS, Android). The underlying framebuffer color texture attachment and if enabled, depth texture attachment, can be dispatched as a GPAC packet using \ref FilterPid.new_packet; this allows forwarding a framebuffer data to other filters without having to copy to system memory the framebuffer content. -When forwarding a framebuffer, it is recommended not to draw anything nor activate GL context until all references of the packet holding the framebuffer are consummed. A callback function is used for that, see example below. +When forwarding a framebuffer, it is recommended not to draw anything nor activate GL context until all references of the packet holding the framebuffer are consumed. A callback function is used for that, see example below. \note you can always use glReadPixels to read back the framebuffer and send packets using the usual FilterPacket tools. @@ -395,10 +394,11 @@ interface WebGLContext : implements WebGLRenderingContextBase { void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, FilterPacket source); /*! creates a named texture - \param name the name of the texture + \param name the name of the texture - if `null`, generates name + \param vcfg video config options - if null, default are assumed (everything unspecified, no full range) \return a new named texture */ - NamedTexture createTexture(DOMString name); + NamedTexture createTexture(DOMString name, optional VideoColorConfig vcfg = null); /*! \param target ignored, default to gl.TEXTURE_2D @@ -406,9 +406,15 @@ interface WebGLContext : implements WebGLRenderingContextBase { */ void bindTexture(GLenum target, NamedTexture texture); + /*! get the name of a named texture + \param texture target named texture + \return name of texture + */ + DOMString textureName(NamedTexture texture); + /*! - \param use_gl_exts if true, queries all extensions supported by the underlying openGL implementation. Otherwise, queries only supported WebGL extensions (none at the moment) + \param use_gl_exts if true, queries all extensions supported by the underlying OpenGL implementation. Otherwise, queries only supported WebGL extensions (none at the moment) \return an array of strings, each entry being the name of a supported extension */ sequence? getSupportedExtensions(optional boolean use_gl_exts=false); @@ -416,7 +422,7 @@ interface WebGLContext : implements WebGLRenderingContextBase { /*! Named texture object, see \ref webgl_grp*/ interface NamedTexture { -/*! number of underlying textures. This can be usefull when doing multi-texturing to get the next texture unit slot: +/*! number of underlying textures. This can be useful when doing multi-texturing to get the next texture unit slot: \code nextActiveTexture = gl.TEXTURE0 + named_tx.nb_textures; \endcode @@ -441,13 +447,23 @@ void upload(Texture tx); }; + +/*! Video color space config for named textures*/ +interface VideoColorConfig { +/*! fullrange video flag*/ +attribute boolean fullrange; +/*! GPAC name for CICP MatrixCoeficients, or interger value*/ +attribute DOMString matrix; +}; + + /*! The FilterPid object is extended as follows*/ interface FilterPid { /*! creates a new output packet using the underlying texture attachement of the context as a texture source (see GF_FilterFrameInterface). \warning This will throw an error if called more than once on a given context but the associated packet has not been consumed yet! \param gl the WebGL context used to create the packet. -\param on_frame_consumed a callback function notified when the associated packet has been consummed +\param on_frame_consumed a callback function notified when the associated packet has been consumed \param use_depth if set, uses the depth framebuffer attachment if enabled rather than the texture. See \ref WebGLContext \return new packet or null with exception*/ FilterPacket new_packet(WebGLContext gl, function on_frame_consumed, optional boolean use_depth); diff --git a/share/doc/man/gpac-filters.1 b/share/doc/man/gpac-filters.1 index a12ed60..42f5452 100644 --- a/share/doc/man/gpac-filters.1 +++ b/share/doc/man/gpac-filters.1 @@ -22,7 +22,19 @@ Description: Inspect packets .br .br -The inspect filter can be used to dump pid and packets. It may also be used to check parts of payload of the packets. The default options inspect only pid changes. +The inspect filter can be used to dump PID and packets. It may also be used to check parts of payload of the packets. +.br + +.br +The default options inspect only PID changes. +.br +If .I full is not set, .I mode=frame is forced and PID properties are formatted in human-readable form, one PID per line. +.br +Otherwise, all properties are dumped. +.br +Note: specifying .I xml, .I analyze, .I fmt or using -for-test will force .I full to true. +.br + .br The packet inspector can be configured to dump specific properties of packets using .I fmt. .br @@ -48,11 +60,11 @@ When the option is not present, all properties are dumped. Otherwise, only prope .br * frame_full: complete AU .br - * frame_start: begining of frame + * frame_start: beginning of frame .br * frame_end: end of frame .br - * frame_cont: frame continuation (not begining, not end) + * frame_cont: frame continuation (not beginning, not end) .br * sap or rap: SAP type of the frame .br @@ -68,19 +80,19 @@ When the option is not present, all properties are dumped. Otherwise, only prope .br * crypt: crypt flag .br -* vers: carrousel version number +* vers: carousel version number .br * size: size of packet .br -* crc: 32 bit CRC of packet +* csize: total size of packets received so far .br -* lf: insert linefeed +* crc: 32 bit CRC of packet .br -* cr: insert carriage return +* lf or n: insert new line .br * t: insert tab .br -* data: hex dump of packet ( WARNING, BIG OUTPUT !! ) +* data: hex dump of packet (big output!) .br * lp: leading picture flag .br @@ -92,6 +104,12 @@ When the option is not present, all properties are dumped. Otherwise, only prope .br * ck: clock type used for PCR discontinuities .br +* pcr: MPEG-2 TS last PCR, n/a if not available +.br +* pcrd: difference between last PCR and decoding time, n/a if no PCR available +.br +* pcrc: difference between last PCR and composition time, n/a if no PCR available +.br * P4CC: 4CC of packet property .br * PropName: Name of packet property @@ -112,20 +130,18 @@ This dumps packet number, cts and dts as follows: PID 1 packet 10 DTS 100 CTS 10 .br .br -An unrecognized keywork or missing property will resolve to an empty string. +An unrecognized keyword or missing property will resolve to an empty string. .br .br Note: when dumping in interleaved mode, there is no guarantee that the packets will be dumped in their original sequence order since the inspector fetches one packet at a time on each PID. .br -.br - .br .SH Options (expert): .LP .br -log (str, default: stderr, minmax: fileName, stderr, stdout or null): set inspect log filename +log (str, default: stdout, minmax: fileName, stderr, stdout or null): set inspect log filename .br mode (enum, default: pck): dump mode .br @@ -135,47 +151,63 @@ mode (enum, default: pck): dump mode .br * frame: force reframer .br -* raw: dump source packets without demuxing +* raw: dump source packets without demultiplexing .br .br -interleave (bool, default: true): dump packets as they are received on each pid. If false, report per pid is generated +interleave (bool, default: true): dump packets as they are received on each PID. If false, logs are reported for each PID at end of session .br deep (bool, default: false, updatable): dump packets along with PID state change, implied when .I fmt is set .br -props (bool, default: true, updatable): dump packet properties, ignored when .I fmt is set (see filter help) +props (bool, default: true, updatable): dump packet properties, ignored when .I fmt is set .br -dump_data (bool, default: false, updatable): enable full data dump (WARNING heavy!), ignored when .I fmt is set (see filter help) +dump_data (bool, default: false, updatable): enable full data dump (very large output), ignored when .I fmt is set .br -fmt (str, updatable): set packet dump format (see filter help) +fmt (str, updatable): set packet dump format .br -hdr (bool, default: true): print a header corresponding to fmt string without '$ 'or "pid." +hdr (bool, default: true): print a header corresponding to fmt string without '$' or "pid" .br -allp (bool, default: false): analyse for the entire duration, rather than stoping when all pids are found +allp (bool, default: false): analyse for the entire duration, rather than stopping when all PIDs are found .br info (bool, default: false, updatable): monitor PID info changes .br +full (bool, default: false, updatable): full dump of PID properties (always on if XML) +.br pcr (bool, default: false, updatable): dump M2TS PCR info .br -speed (dbl, default: 1.0): set playback command speed. If speed is negative and start is 0, start is set to -1 +speed (dbl, default: 1.0): set playback command speed. If negative and start is 0, start is set to -1 .br -start (dbl, default: 0.0): set playback start offset. Negative value means percent of media dur with -1 <=> dur +start (dbl, default: 0.0): set playback start offset. A negative value means percent of media duration with -1 equal to duration .br dur (frac, default: 0/0): set inspect duration .br -analyze (bool, default: false, updatable): analyze sample content (NALU, OBU) +analyze (enum, default: off, updatable): analyze sample content (NALU, OBU) +.br +* off: no analyzing +.br +* on: simple analyzing +.br +* bs: log bitstream syntax (all elements read from bitstream) +.br +* full: log bitstream syntax and bit sizes signaled as (N) after field value, except 1-bit fields (omitted) +.br + .br xml (bool, default: false, updatable): use xml formatting (implied if (-analyze]() is set) and disable .I fmt .br +crc (bool, default: false, updatable): dump crc of samples of subsamples (NALU or OBU) when analyzing +.br fftmcd (bool, default: false, updatable): consider timecodes use ffmpeg-compatible signaling rather than QT compliant one .br dtype (bool, default: false, updatable): dump property type .br +buffer (uint, default: 0): set buffer in ms (mostly used for testing DASH algo) +.br test (enum, default: no, updatable): skip predefined set of properties, used for test mode .br * no: no properties skipped .br -* noprop: all properties/info changes on pid are skipped, only packets are dumped +* noprop: all properties/info changes on PID are skipped, only packets are dumped .br * network: URL/path dump, cache state, file size properties skipped (used for hashing network results) .br @@ -185,6 +217,10 @@ test (enum, default: no, updatable): skip predefined set of properties, used for .br * encx: same as encode and skip bitrates, media data size and co .br +* nocrc: disable packet CRC dump +.br +* nobr: skip bitrate +.br .br @@ -196,76 +232,20 @@ Description: Probe source .br .br -The Probe filter is used by applications (typically MP4Box) to query demuxed pids available in a source chain. -.br -The filter does not produce any output nor feedback, it is up to the app developper to query input pids of the prober and take appropriated decisions. +The Probe filter is used by applications (typically MP4Box) to query demultiplexed PIDs (audio, video, ...) available in a source chain. .br .br -.SH Options (expert): -.LP -.br -log (str, default: stderr, minmax: fileName, stderr, stdout or null): set inspect log filename -.br -mode (enum, default: pck): dump mode -.br -* pck: dump full packet -.br -* blk: dump packets before reconstruction -.br -* frame: force reframer +The filter outputs the number of input PIDs in the file specified by .I log. .br -* raw: dump source packets without demuxing +It is up to the app developer to query input PIDs of the prober and take appropriated decisions. .br .br -interleave (bool, default: true): dump packets as they are received on each pid. If false, report per pid is generated -.br -deep (bool, default: false, updatable): dump packets along with PID state change, implied when .I fmt is set -.br -props (bool, default: true, updatable): dump packet properties, ignored when .I fmt is set (see filter help) -.br -dump_data (bool, default: false, updatable): enable full data dump (WARNING heavy!), ignored when .I fmt is set (see filter help) -.br -fmt (str, updatable): set packet dump format (see filter help) -.br -hdr (bool, default: true): print a header corresponding to fmt string without '$ 'or "pid." -.br -allp (bool, default: false): analyse for the entire duration, rather than stoping when all pids are found -.br -info (bool, default: false, updatable): monitor PID info changes -.br -pcr (bool, default: false, updatable): dump M2TS PCR info -.br -speed (dbl, default: 1.0): set playback command speed. If speed is negative and start is 0, start is set to -1 -.br -start (dbl, default: 0.0): set playback start offset. Negative value means percent of media dur with -1 <=> dur -.br -dur (frac, default: 0/0): set inspect duration -.br -analyze (bool, default: false, updatable): analyze sample content (NALU, OBU) -.br -xml (bool, default: false, updatable): use xml formatting (implied if (-analyze]() is set) and disable .I fmt -.br -fftmcd (bool, default: false, updatable): consider timecodes use ffmpeg-compatible signaling rather than QT compliant one -.br -dtype (bool, default: false, updatable): dump property type -.br -test (enum, default: no, updatable): skip predefined set of properties, used for test mode -.br -* no: no properties skipped -.br -* noprop: all properties/info changes on pid are skipped, only packets are dumped -.br -* network: URL/path dump, cache state, file size properties skipped (used for hashing network results) -.br -* netx: same as network but skip track duration and templates (used for hashing progressive load of fmp4) -.br -* encode: same as network plus skip decoder config (used for hashing encoding results) -.br -* encx: same as encode and skip bitrates, media data size and co +.SH Options (expert): +.LP .br - +log (str, default: stdout, minmax: fileName, stderr, stdout or null): set probe log filename to print number of streams .br .br @@ -287,7 +267,7 @@ The compositor operates either in media-client or filter-only mode. .br In this mode, the compositor acts as a pseudo-sink for the video side and creates its own output window. .br -The video frames are dispatched to the output video pid in the form of frame pointers requiring later GPU read if used. +The video frames are dispatched to the output video PID in the form of frame pointers requiring later GPU read if used. .br The audio part acts as a regular filter, potentially mixing and resampling the audio inputs to generate its output. .br @@ -300,19 +280,19 @@ User events are directly processed by the filter in this mode. .br In this mode, the compositor acts as a regular filter generating frames based on the loaded scene. .br -It will generate its outputs based on the input video frames and will not process any user event. +It will generate its outputs based on the input video frames, and will process user event sent by consuming filter(s). .br If no input video frames (e.g. pure BIFS / SVG / VRML), the filter will generate frames based on the .I fps, at constant or variable frame rate. .br It will stop generating frames as soon as all input streams are done, unless extended/reduced by .I dur. .br -If audio streams are loaded, an audio output pid is created. +If audio streams are loaded, an audio output PID is created. .br .br The default output pixel format in filter mode is: .br -- rgb when the filter is explictly loaded by the application +- rgb when the filter is explicitly loaded by the application .br - rgba when the filter is loaded during a link resolution .br @@ -322,9 +302,9 @@ This can be changed by assigning the .I opfmt option. .br In filter-only mode, the special URL gpid:// is used to locate PIDs in the scene description, in order to design scenes independently from source media. .br -When such a pid is associated to a Background2D node in BIFS (no SVG mapping yet), the compositor operates in passthrough mode. +When such a PID is associated to a Background2D node in BIFS (no SVG mapping yet), the compositor operates in pass-through mode. .br -In this mode, only new input frames on the passthrough pid will generate new frames, and the scene clock matches the input packet time. +In this mode, only new input frames on the pass-through PID will generate new frames, and the scene clock matches the input packet time. .br The output size and pixel format will be set to the input size and pixel format, unless specified otherwise in the filter options. .br @@ -332,7 +312,7 @@ The output size and pixel format will be set to the input size and pixel format, .br If only 2D graphics are used and display driver is not forced, 2D rasterizer will happen in the output pixel format (including YUV pixel formats). .br -In this case, inplace processing (rasterizing over the input frame data) will be used whenever allowed by input data. +In this case, in-place processing (rasterizing over the input frame data) will be used whenever allowed by input data. .br .br @@ -343,11 +323,39 @@ If 3D graphics are used or display driver is forced, OpenGL will be used on offs .SH Specific URL syntaxes .LP .br -The compositor accepts any URL type supported by GPAC. It also accepts the following syntaxes for URLs: +The compositor accepts any URL type supported by GPAC. It also accepts the following schemes for URLs: +.br +* views:// : creates an auto-stereo scene of N views from views://v1::.::vN +.br +* mosaic:// : creates a mosaic of N views from mosaic://v1::.::vN +.br + +.br +For both syntaxes, vN can be any type of URL supported by GPAC. +.br +For views:// syntax, the number of rendered views is set by .I nbviews: +.br +- If the URL gives less views than rendered, the views will be repeated +.br +- If the URL gives more views than rendered, the extra views will be ignored +.br + +.br +The compositor can act as a source filter when the .I src option is explicitly set, independently from the operating mode: +.br +Example +.br +gpac compositor:src=source.mp4 vout +.br + .br -* views: creates an auto-stereo scene of N views from views://v1:.:vN. vN can be any type of URL supported by GPAC. + +.br +The compositor can act as a source filter when the source url uses one of the compositor built-in protocol schemes: +.br +Example .br -* mosaic: creates a mosaic of N views from mosaic://v1:.:vN. vN can be any type of URL supported by GPAC. +gpac -i mosaic://URL1:URL2 vout .br .br @@ -376,9 +384,9 @@ sz (bool, default: true, updatable): enable scalable zoom. When scalable zoom is .br bc (uint, default: 0, updatable): default background color to use when displaying transparent images or video with no scene composition instructions .br -yuvhw (bool, default: true, updatable): enable YUV hardware for 2D blits +yuvhw (bool, default: true, updatable): enable YUV hardware for 2D blit .br -blitp (bool, default: true, updatable): partial hardware blits (if not set, will force more redraw) +blitp (bool, default: true, updatable): partial hardware blit. If not set, will force more redraw .br softblt (bool, default: true): enable software blit/stretch in 2D. If disabled, vector graphics rasterizer will always be used .br @@ -390,9 +398,9 @@ bvol (enum, default: no, updatable): draw bounding volume of objects .br * no: disable bounding box .br -* box: draws a rectangle (2D) or box (3D mode) +* box: draws a rectangle (2D) or box (3D) .br -* aabb: draws axis-aligned bounding-box tree (3D only) +* aabb: draws axis-aligned bounding-box tree (3D) or rectangle (2D) .br .br @@ -408,7 +416,7 @@ textxt (enum, default: default, updatable): specify whether text shall be drawn .br out8b (bool, default: false, updatable): convert 10-bit video to 8 bit texture before GPU upload .br -drop (bool, default: false, updatable): drop late frame when drawing. By default frames are not droped until a heavy desync of 1 sec is observed +drop (bool, default: false, updatable): drop late frame when drawing. If not set, frames are not dropped until a desynchronization of 1 second or more is observed .br sclock (bool, default: false, updatable): force synchronizing all streams on a single clock .br @@ -416,15 +424,15 @@ sgaze (bool, default: false, updatable): simulate gaze events through mouse .br ckey (uint, default: 0, updatable): color key to use in windowless mode (0xFFRRGGBB). GPAC currently does not support true alpha blitting to desktop due to limitations in most windowing toolkit, it therefore uses color keying mechanism. The alpha part of the key is used for global transparency of the output, if supported .br -timeout (uint, default: 10000, updatable): timeout in ms after which a source is considered dead +timeout (uint, default: 10000, updatable): timeout in ms after which a source is considered dead (0 disable timeout) .br fps (frac, default: 30/1, updatable): simulation frame rate when animation-only sources are played (ignored when video is present) .br -timescale (uint, default: 0, updatable): timescale used for output packets when no input video pid. A value of 0 means fps numerator +timescale (uint, default: 0, updatable): timescale used for output packets when no input video PID. A value of 0 means fps numerator .br -autofps (bool, default: true): use video input fps for output. If no video or not set, uses .I fps. Ignored in player mode +autofps (bool, default: true): use video input fps for output, ignored in player mode. If no video or not set, uses .I fps .br -vfr (bool, default: false): only emit frames when changes are detected. Always true in player mode and when filter is dynamically loaded +vfr (bool, default: false): only emit frames when changes are detected. (always true in player mode and when filter is dynamically loaded) .br dur (dbl, default: 0, updatable): duration of generation. Mostly used when no video input is present. Negative values mean number of frames, positive values duration in second, 0 stops as soon as all streams are done .br @@ -432,29 +440,29 @@ fsize (bool, default: false, updatable): force the scene to resize to the bigges .br mode2d (enum, default: defer, updatable): specify whether immediate drawing should be used or not .br -* immediate: the screen is completely redrawn at each frame (always on if passthrough mode is detected) +* immediate: the screen is completely redrawn at each frame (always on if pass-through mode is detected) .br * defer: object positioning is tracked from frame to frame and dirty rectangles info is collected in order to redraw the minimal amount of the screen buffer .br -* debug: only renders changed areas, reseting other areas +* debug: only renders changed areas, resetting other areas .br Whether the setting is applied or not depends on the graphics module and player mode .br .br -amc (bool, default: true): audio multichannel support; if disabled always downmix to stereo. Useful if the multichannel output does not work properly +amc (bool, default: true): audio multichannel support; if disabled always down-mix to stereo. Useful if the multichannel output does not work properly .br -asr (uint, default: 0): force output sample rate - 0 for auto +asr (uint, default: 0): force output sample rate (0 for auto) .br -ach (uint, default: 0): force output channels - 0 for auto +ach (uint, default: 0): force output channels (0 for auto) .br -alayout (uint, default: 0): force output channel layout - 0 for auto +alayout (uint, default: 0): force output channel layout (0 for auto) .br -afmt (afmt, default: s16, minmax: none,u8,s16,s24,s32,flt,dbl,u8p,s16p,s24p,s32p,fltp,dblp): force output channel format - 0 for auto +afmt (afmt, default: s16, minmax: none,u8,s16,s16b,s24,s32,flt,dbl,u8p,s16p,s24p,s32p,fltp,dblp): force output channel format (0 for auto) .br asize (uint, default: 1024): audio output packet size in samples .br -abuf (uint, default: 100): audio output buffer duration in ms - the audio renderer fills the output pid up to this value. A too low value will lower latency but can have real-time playback issues +abuf (uint, default: 100): audio output buffer duration in ms - the audio renderer fills the output PID up to this value. A too low value will lower latency but can have real-time playback issues .br avol (uint, default: 100, updatable): audio volume in percent .br @@ -462,25 +470,25 @@ apan (uint, default: 50, updatable): audio pan in percent, 50 is no pan .br async (bool, default: true, updatable): audio resynchronization; if disabled, audio data is never dropped but may get out of sync .br -max_aspeed (dbl, default: 2.0, updatable): silence audio if playback speed is greater than sepcified value +max_aspeed (dbl, default: 2.0, updatable): silence audio if playback speed is greater than specified value .br -max_vspeed (dbl, default: 4.0, updatable): move to i-frame only decoding if playback speed is greater than sepcified value +max_vspeed (dbl, default: 4.0, updatable): move to i-frame only decoding if playback speed is greater than specified value .br -buf (uint, default: 3000, updatable): playout buffer in ms. overridden by BufferLenth property of input pid +buffer (uint, default: 3000, updatable): playout buffer in ms (overridden by BufferLength property of input PID) .br -rbuf (uint, default: 1000, updatable): rebuffer trigger in ms. overridden by RebufferLenth property of input pid +rbuffer (uint, default: 1000, updatable): rebuffer trigger in ms (overridden by RebufferLength property of input PID) .br -mbuf (uint, default: 3000, updatable): max buffer in ms (must be greater than playout buffer). overridden by BufferMaxOccupancy property of input pid +mbuffer (uint, default: 3000, updatable): max buffer in ms, must be greater than playout buffer (overridden by BufferMaxOccupancy property of input PID) .br ntpsync (uint, default: 0, updatable): ntp resync threshold in ms (drops frame if their NTP is more than the given threshold above local ntp), 0 disables ntp drop .br nojs (bool, default: false): disable javascript .br -noback (bool, default: false): ignore background nodes and viewport fill (usefull when dumping to PNG) +noback (bool, default: false): ignore background nodes and viewport fill (useful when dumping to PNG) .br ogl (enum, default: auto, updatable): specify 2D rendering mode .br -* auto: automatically decides betwwen on, off and hybrid based on content +* auto: automatically decides between on, off and hybrid based on content .br * off: disables OpenGL; 3D will not be rendered .br @@ -500,7 +508,7 @@ nav (enum, default: none, updatable): override the default navigation mode of MP .br * fly: 3D world fly (no ground detection) .br -* pan: 2D/3D world zomm/pan +* pan: 2D/3D world zoom/pan .br * game: 3D world game (mouse gives walk direction) .br @@ -516,11 +524,13 @@ nav (enum, default: none, updatable): override the default navigation mode of MP .br linegl (bool, default: false, updatable): indicate that outlining shall be done through OpenGL pen width rather than vectorial outlining .br -epow2 (bool, default: true, updatable): emulate power-of-2 textures for openGL (old hardware). Ignored if OpenGL rectangular texture extension is enabled +epow2 (bool, default: true, updatable): emulate power-of-2 textures for OpenGL (old hardware). Ignored if OpenGL rectangular texture extension is enabled .br * yes: video texture is not resized but emulated with padding. This usually speeds up video mapping on shapes but disables texture transformations .br * no: video is resized to a power of 2 texture when mapping to a shape +.br + .br paa (bool, default: false, updatable): indicate whether polygon antialiasing should be used in full antialiasing mode. If not set, only lines and points antialiasing are used .br @@ -574,6 +584,8 @@ nbviews (uint, default: 0, updatable): number of views to use in stereo mode .br stereo (enum, default: none, updatable): stereo output type. If your graphic card does not support OpenGL shaders, only top and side modes will be available .br +* none: no stereo +.br * side: images are displayed side by side from left to right .br * top: images are displayed from top (laft view) to bottom (right view) @@ -618,15 +630,25 @@ camlay (enum, default: offaxis, updatable): camera layout in multiview modes .br .br -iod (flt, default: 6.4, updatable): inter-occular distance (eye separation) in cm (distance between the cameras). +iod (flt, default: 6.4, updatable): inter-ocular distance (eye separation) in cm (distance between the cameras). .br rview (bool, default: false, updatable): reverse view order .br -tvtn (uint, default: 30, updatable): number of point sampling for tile visibility algo +dbgpack (bool, default: false, updatable): view packed stereo video as single image (show all) +.br +tvtn (uint, default: 30, updatable): number of point sampling for tile visibility algorithm +.br +tvtt (uint, default: 8, updatable): number of points above which the tile is considered visible +.br +tvtd (enum, default: off, updatable): debug tiles and full coverage SRD +.br +* off: regular draw +.br +* partial: only displaying partial tiles, not the full sphere video .br -tvtt (uint, default: 0, updatable): number of points above which the tile is considered visible +* full: only display the full sphere video .br -tvtd (bool, default: false, updatable): disable the tile having full coverage of the SRD, only displaying partial tiles + .br tvtf (bool, default: false, updatable): force all tiles to be considered visible, regardless of viewpoint .br @@ -636,7 +658,7 @@ vertshader (str): path to vertex shader file .br fragshader (str): path to fragment shader file .br -autocal (bool, default: false, updatable): auto callibration of znear/zfar in depth rendering mode +autocal (bool, default: false, updatable): auto calibration of znear/zfar in depth rendering mode .br dispdepth (sint, default: -1, updatable): display depth, negative value uses default screen height .br @@ -650,7 +672,7 @@ dpi (v2di, default: 96x96, updatable): default dpi if not indicated by video out .br dbgpvr (flt, default: 0, updatable): debug scene used by PVR addon .br -player (enum, default: no): set compositor in player mode, see filter help +player (enum, default: no): set compositor in player mode .br * no: regular mode .br @@ -662,28 +684,38 @@ player (enum, default: no): set compositor in player mode, see filter help .br noaudio (bool, default: false): disable audio output .br -opfmt (pfmt, default: none, minmax: none,yuv420,yuv420_10,yuv422,yuv422_10,yuv444,yuv444_10,uyvy,vyuy,yuyv,yvyu,nv12,nv21,nv1l,nv2l,yuva,yuvd,yuv444a,grey,algr,gral,rgb4,rgb5,rgb6,rgba,argb,bgra,abgr,rgb,bgr,xrgb,rgbx,xbgr,bgrx,rgbd,rgbds,rgbs,rgbas): pixel format to use for output. Ignored in .I player mode +opfmt (pfmt, default: none, minmax: none,yuv420,yvu420,yuv420_10,yuv422,yuv422_10,yuv444,yuv444_10,uyvy,vyuy,yuyv,yvyu,uyvl,vyul,yuyl,yvyl,nv12,nv21,nv1l,nv2l,yuva,yuvd,yuv444a,yuv444p,yuv444ap,yuv444p_10,grey,algr,gral,rgb4,rgb5,rgb6,rgba,argb,bgra,abgr,rgb,bgr,xrgb,rgbx,xbgr,bgrx,rgbd,rgbds,rgbs,rgbas): pixel format to use for output. Ignored in .I player mode .br -drv (enum, default: auto): indicate if graphics driver should be used. Ignored in player mode +drv (enum, default: auto): indicate if graphics driver should be used .br -* no: never loads a graphics driver (software blitting used, no 3D possible) +* no: never loads a graphics driver, software blit is used, no 3D possible (in player mode, disables OpenGL) .br -* yes: always loads a graphics driver. Output pixel format will be RGB +* yes: always loads a graphics driver, output pixel format will be RGB (in player mode, same as auto) .br * auto: decides based on the loaded content .br +.br +src (cstr): URL of source content +.br +gaze_x (sint, default: 0, updatable): horizontal gaze coordinate (0=left, width=right) +.br +gaze_y (sint, default: 0, updatable): vertical gaze coordinate (0=top, height=bottom) +.br +gazer_enabled (bool, default: false, updatable): enable gaze event dispatch .br .br .SH mp4dmx .LP .br -Description: ISOBMFF/QT demuxer +Description: ISOBMFF/QT demultiplexer .br .br -This filter demultiplexes ISOBMF and QT files (regular or fragmented). +This filter demultiplexes ISOBMF and QT files. +.br +Input ISOBMFF/QT can be regular or fragmented, and available as files or as raw bytestream. .br .SH Track Selection .LP @@ -715,7 +747,7 @@ When scalable tracks are present in a file, the reader can operate in 3 modes us .br * smode=single: resolves all extractors to extract a single bitstream from a scalable set. The highest level is used .br -In this mode, there is no enhancement decoder config, only a base one resulting from the merge of the configs +In this mode, there is no enhancement decoder config, only a base one resulting from the merge of the layers configurations .br * smode=split: all extractors are removed and every track of the scalable set is declared. In this mode, each enhancement track has no base decoder config .br @@ -728,15 +760,13 @@ and an enhancement decoder config. Warning: smode=splitx will result in extractor NAL units still present in the output bitstream, which shall only be true if the output is ISOBMFF based .br -.br - .br .SH Options (expert): .LP .br -src (cstr): location of source content +src (cstr): local file name of source content (only used when explicitly loading the filter) .br -allt (bool, default: false): load all tracks even if unknown +allt (bool, default: false): load all tracks even if unknown media type .br noedit (bool, default: false): do not use edit lists .br @@ -754,15 +784,17 @@ smode (enum, default: split): load mode for scalable/tile tracks .br .br -alltk (bool, default: false): declare all tracks even disabled ones +alltk (bool, default: false): declare disabled tracks .br frame_size (uint, default: 1024): frame size for raw audio samples (dispatches frame_size samples per packet) .br -expart (bool, default: false): expose cover art as a dedicated video pid +expart (bool, default: false): expose cover art as a dedicated video PID .br sigfrag (bool, default: false): signal fragment and segment boundaries of source on output packets .br -tkid (str): declare only track based on given param- integer value: declares track with the given ID +tkid (str): declare only track based on given param +.br +* integer value: declares track with the given ID .br * audio: declares first audio track .br @@ -770,18 +802,32 @@ tkid (str): declare only track based on given param- integer .br * 4CC: declares first track with matching 4CC for handler type .br -stsd (uint, default: 0): only extract sample mapped to the given sample desciption index. 0 means no filter + +.br +stsd (uint, default: 0): only extract sample mapped to the given sample description index (0 means extract all) .br nocrypt (bool): signal encrypted tracks as non encrypted (mostly used for export) .br -mstore_size (uint, default: 1000000): target buffer size in bytes +mstore_size (uint, default: 1000000): target buffer size in bytes when reading from memory stream (pipe etc...) .br -mstore_purge (uint, default: 50000): minimum size in bytes between memory purges when reading from memory stream (pipe etc...), 0 means purge as soon as possible +mstore_purge (uint, default: 50000): minimum size in bytes between memory purges when reading from memory stream, 0 means purge as soon as possible .br mstore_samples (uint, default: 50): minimum number of samples to be present before purging sample tables when reading from memory stream (pipe etc...), 0 means purge as soon as possible .br strtxt (bool, default: false): load text tracks (apple/tx3g) as MPEG-4 streaming text tracks .br +xps_check (enum, default: auto): parameter sets extraction mode from AVC/HEVC/VVC samples +.br +* keep: do not inspect sample (assumes input file is compliant when generating DASH/HLS/CMAF) +.br +* rem: removes all inband xPS and notify configuration changes accordingly +.br +* auto: resolves to keep for smode=splix (dasher mode), rem otherwise +.br + +.br +nodata (bool, default: false): do not load sample data +.br .br .SH bifsdec @@ -791,7 +837,9 @@ Description: MPEG-4 BIFS decoder .br .br -This filter decodes MPEG-4 BIFS frames directly into the scene graph of the compositor. It cannot be used to dump BIFS content. +This filter decodes MPEG-4 BIFS binary frames directly into the scene graph of the compositor. +.br +Note: This filter cannot be used to dump BIFS content to text or xml, use MP4Box for that. .br .br @@ -806,7 +854,9 @@ Description: MPEG-4 OD decoder .br .br -This filter decodes MPEG-4 OD frames directly into the scene manager of the compositor. It cannot be used to dump OD content. +This filter decodes MPEG-4 OD binary frames directly into the scene manager of the compositor. +.br +Note: This filter cannot be used to dump OD content to text or xml, use MP4Box for that. .br .br @@ -833,20 +883,18 @@ The special file name null is used for creating a file with no data, needed by s .br The special file name rand is used to generate random data. .br -The special file name randsc is used to generate random data with fake startcodes (0x000001). +The special file name randsc is used to generate random data with 0x000001 start-code prefix. .br .br The filter handles both files and GF_FileIO objects as input URL. .br -.br - .br .SH Options (expert): .LP .br -src (cstr): location of source content +src (cstr): location of source file .br block_size (uint, default: 0): block size used to read file. 0 means 5000 if file less than 500m, 1M otherwise .br @@ -865,16 +913,18 @@ Description: BT/XMT/X3D loader .br .br -This filter parses MPEG-4 BIFS (BT and XMT), VRML97 and X3D (wrl and XML) files directly into the scene graph of the compositor. It cannot be used to dump content. +This filter parses MPEG-4 BIFS (BT and XMT), VRML97 and X3D (wrl and XML) files directly into the scene graph of the compositor. +.br + +.br +When .I sax_dur=N is set, the filter will do a progressive load of the source and cancel current loading when processing time is higher than N. .br .br .SH Options (expert): .LP .br -progressive (bool, default: false): enable progressive loading -.br -sax_dur (uint, default: 1000): loading duration for SAX parsing (XMT), 0 disables SAX parsing +sax_dur (uint, default: 0): duration for SAX parsing (XMT), 0 disables SAX parsing .br .br @@ -898,7 +948,7 @@ Note: Unless disabled at session level (see .I -no-probe ), file extensions are .SH Options (expert): .LP .br -src (cstr): location of source content +src (cstr): URL of source content .br block_size (uint, default: 100000): block size used to read file .br @@ -910,8 +960,12 @@ cache (enum, default: disk): set cache mode .br * mem: stores to memory, discard once session is no longer used .br +* mem_keep: stores to memory, keep after session is reassigned but move to mem after first download +.br * none: no cache .br +* none_keep: stores to memory, keep after session is reassigned but move to none after first download +.br .br range (lfrac, default: 0-0): set byte range, as fraction @@ -929,7 +983,11 @@ Description: SVG loader .br .br -This filter parses SVG files directly into the scene graph of the compositor. It cannot be used to dump content. +This filter parses SVG files directly into the scene graph of the compositor. +.br + +.br +When .I sax_dur=N is set, the filter will do a progressive load of the source and cancel current loading when processing time is higher than N. .br .br @@ -951,8 +1009,7 @@ This filter parses JPG/J2K/PNG/BMP files/data and outputs corresponding visual P .br .br -.SH Options (expert): -.LP +No options .br .br @@ -1011,7 +1068,9 @@ ps (enum, default: no): set PS signaling .br .br -expart (bool, default: false): expose pictures as a dedicated video pid +expart (bool, default: false): expose pictures as a dedicated video PID +.br +aacchcfg (sint, default: 0): set AAC channel configuration to this value if missing from ADTS header, use negative value to always override .br .br @@ -1051,7 +1110,9 @@ This filter parses MPEG-1/2 audio files/data and outputs corresponding audio PID .br index (dbl, default: 1.0): indexing window length .br -expart (bool, default: false): expose pictures as a dedicated video pid +expart (bool, default: false): expose pictures as a dedicated video PID +.br +forcemp3 (bool, default: true): force mp3 signaling for MPEG-2 Audio layer 3 .br .br @@ -1182,7 +1243,7 @@ index (dbl, default: 1.0): indexing window length .SH oggdmx .LP .br -Description: OGG demuxer +Description: OGG demultiplexer .br .br @@ -1193,7 +1254,9 @@ This filter demultiplexes OGG files/data into a set of media PIDs and frames. .SH Options (expert): .LP .br -index (dbl, default: 1.0): indexing window length (unimplemented, only 0 disables stream probing for duration), +index (dbl, default: 1.0): indexing window length (not implemented), use 0 to disable stream probing for duration), +.br +expart (bool, default: false): expose pictures as a dedicated video PID .br .br @@ -1230,7 +1293,7 @@ No options .SH m2tsdmx .LP .br -Description: MPEG-2 TS demuxer +Description: MPEG-2 TS demultiplexer .br .br @@ -1247,6 +1310,8 @@ dsmcc (bool, default: no): enable DSMCC receiver .br seeksrc (bool, default: true): seek local source file back to origin once all programs are setup .br +sigfrag (bool, default: false): signal segment boundaries on output packets for DASH or HLS sources +.br .br .SH sockin @@ -1274,18 +1339,24 @@ Data format can be specified by setting either .I ext or .I mime options. If not .br .br -On OSX with VM packet replay you will need to force multicast routing, eg: route add -net 239.255.1.4/32 -interface vboxnet0 +When ports are specified in the URL and the default option separators are used (see gpac -h doc), the URL must either: +.br +- have a trailing '/', e.g. udp://localhost:1234/[:opts] +.br +- use gpac separator, e.g. udp://localhost:1234[:gpac:opts] +.br + +.br +On OSX with VM packet replay you will need to force multicast routing, e.g. route add -net 239.255.1.4/32 -interface vboxnet0 .br .br .SH Options (expert): .LP .br -src (cstr): location of source content -.br -block_size (uint, default: 10000): block size used to read socket +src (cstr): address of source content .br -sockbuf (uint, default: 65536): socket max buffer size +block_size (uint, default: 0x60000): block size used to read socket .br port (uint, default: 1234): default port if not specified .br @@ -1305,7 +1376,7 @@ mime (str): indicate mime type of udp data .br block (bool, default: false): set blocking mode for socket(s) .br -timeout (uint, default: 5000): set timeout in ms for UDP socket(s) +timeout (uint, default: 10000): set timeout in ms for UDP socket(s), 0 to disable timeout .br reorder_pck (uint, default: 100): number of packets delay for RTP reordering (M2TS over RTP) .br @@ -1322,12 +1393,20 @@ Description: DVB for Linux .br Experimental DVB support for linux, requires a channel config file through .I chcfg .br + +.br +The URL syntax is dvb://CHANNAME[@FRONTEND], with: +.br + * CHANNAME: the channel name as listed in the channel config file +.br + * frontend: the index of the DVB adapter to use (optional, default is 0) +.br .br .SH Options (expert): .LP .br -src (cstr): location of source content +src (cstr): URL of source content .br block_size (uint, default: 65536): block size used to read file .br @@ -1357,7 +1436,7 @@ Description: VideoToolBox decoder .br .br -This filter decodes MPEG-2, H263, AVC|H264 and HEVC streams through VideoToolBox. It allows GPU frame dispatch or direct frame copy. +This filter decodes video streams through OSX/iOS VideoToolBox (MPEG-2, H263, AVC|H264, HEVC, ProRes). It allows GPU frame dispatch or direct frame copy. .br .br @@ -1366,9 +1445,9 @@ This filter decodes MPEG-2, H263, AVC|H264 and HEVC streams through VideoToolBox .br reorder (uint, default: 6): number of frames to wait for temporal re-ordering .br -no_copy (bool, default: true): dispatch VTB frames into filter chain (no copy) +no_copy (bool, default: true): dispatch decoded frames as OpenGL textures (true) or as copied packets (false) .br -ofmt (pfmt, default: nv12): set default pixel format for decoded video. If not matched default to nv12 +ofmt (pfmt, default: nv12): set default pixel format for decoded video. If not found, fall back to nv12 .br disable_hw (bool, default: false): disable hardware decoding .br @@ -1399,7 +1478,9 @@ Description: MPEG-4 LASeR decoder .br .br -This filter decodes MPEG-4 LASeR frames directly into the scene graph of the compositor. It cannot be used to dump LASeR content. +This filter decodes MPEG-4 LASeR binary frames directly into the scene graph of the compositor. +.br +Note: This filter cannot be used to dump LASeR content to text or xml, use MP4Box for that. .br .br @@ -1410,7 +1491,7 @@ No options .SH safdmx .LP .br -Description: SAF demuxer +Description: SAF demultiplexer .br .br @@ -1429,218 +1510,433 @@ Description: MPEG-DASH and HLS client .br .br -This filter reads MPEG-DASH, HLS and MS Smooth (on demand only for now) manifests and produces media PIDs and frames. +This filter reads MPEG-DASH, HLS and MS Smooth manifests. .br .br -.SH Options (expert): +.SH Regular mode .LP .br -auto_switch (uint, default: 0): switch quality every N segments, disabled if 0 +This is the default mode, in which the filter produces media PIDs and frames from sources indicated in the manifest. .br -segstore (enum, default: mem): enable file caching +The default behavior is to perform adaptation according to .I algo, but the filter can: .br -* mem: all files are stored in memory, no disk IO +- run with no adaptation, to grab maximum quality. .br -* file: files are stored to disk but discarded once played +Example .br -* cache: all files are stored to disk and kept +gpac -i MANIFEST_URL:algo=none:start_with=max_bw -o dest.mp4 .br .br -algo (enum, default: gbuf): adaptation algorithm to use +- run with no adaptation, fetching all qualities. .br -* none: no adaptation logic +Example .br -* grate: GAPC legacy algo based on available rate +gpac -i MANIFEST_URL:split_as -o dst=$File$.mp4:clone .br -* gbuf: GAPC legacy algo based on buffer occupancy + .br -* bba0: BBA-0 + .br -* bolaf: BOLA Finite +.SH File mode +.LP .br -* bolab: BOLA Basic +When .I forward is set to file, the client forwards media files without demultiplexing them. .br -* bolau: BOLA-U +This is mostly used to expose the DASH session to a file server such as ROUTE or HTTP. .br -* bolao: BOLA-O +In this mode, the manifest is forwarded as an output PID. +.br +Warning: This mode cannot be set through inheritance as it changes the link capabilities of the filter. The filter MUST be explicitly declared. .br .br -start_with (enum, default: max_bw): initial selection criteria +To expose a live DASH session to route: .br -* min_q: start with lowest quality +Example .br -* max_q: start with highest quality +gpac -i MANIFEST_URL dashin:forward=file -o route://225.0.0.1:8000/ .br -* min_bw: start with lowest bitrate + .br -* max_bw: start with highest bitrate; for tiles are used, all low priority tiles will have the lower (below max) bandwidth selected + .br -* max_bw_tiles: start with highest bitrate; for tiles all low priority tiles will have their lowest bandwidth selected +Note: This mode used to be trigger by .I filemode option, still recognized. .br .br -max_res (bool, default: true): use max media resolution to configure display -.br -immediate (bool, default: false): when interactive switching is requested and immediate is set, the buffer segments are trashed +If the source has dependent media streams (scalability) and all qualities and initialization segments need to be forwarded, add .I split_as. .br -abort (bool, default: false): allow abort during a segment download + .br -use_bmin (bool, default: false): use the indicated min buffer time of the MPD if true, otherwise uses default player settings +.SH Segment bound modes +.LP .br -shift_utc (sint, default: 0): shift DASH UTC clock in ms +When .I forward is set to segb or mani, the client forwards media frames (after demultiplexing) together with segment and fragment boundaries of source files. .br -atsc_shift (sint, default: 0): shift ATSC requests time by given ms + .br -server_utc (bool, default: yes): use ServerUTC: or Date: http headers instead of local UTC +This mode can be used to process media data and regenerate the same manifest/segmentation. .br -screen_res (bool, default: yes): use screen resolution in selection phase + .br -init_timeshift (uint, default: 0): set initial timshift in ms (if >0) or in per-cent of timeshift buffer (if <0) +Example .br -tile_mode (enum, default: none): tile adaptation mode +gpac -i MANIFEST_URL:forward=mani cecrypt:cfile=DRM.xml -o encrypted/live.mpd:pssh=mv .br -* none: bitrate is shared equaly accross all tiles + .br -* rows: bitrate decreases for each row of tiles starting from the top, same rate for each tile on the row +This will encrypt an existing DASH session, inject PSSH in manifest and segments. .br -* rrows: bitrate decreases for each row of tiles starting from the bottom, same rate for each tile on the row + .br -* mrows: bitrate decreased for top and bottom rows only, same rate for each tile on the row +Example .br -* cols: bitrate decreases for each columns of tiles starting from the left, same rate for each tile on the columns +gpac -i MANIFEST_URL:forward=segb cecrypt:cfile=DRM.xml -o encrypted/live.m3u8 .br -* rcols: bitrate decreases for each columns of tiles starting from the right, same rate for each tile on the columns + .br -* mcols: bitrate decreased for left and right columns only, same rate for each tile on the columns +This will encrypt an existing DASH session and republish it as HLS, using same segment names and boundaries. .br -* center: bitrate decreased for all tiles on the edge of the picture + .br -* edges: bitrate decreased for all tiles on the center of the picture +This mode will force .I noseek=true to ensure the first segment fetched is complete, and .I split_as=true to fetch all qualities. .br .br -tiles_rate (uint, default: 100): indicate the amount of bandwidth to use at each quality level. The rate is recursively applied at each level, e.g. if 50%, Level1 gets 50%, level2 gets 25%, ... If 100, automatic rate allocation will be done by maximizing the quality in order of priority. If 0, bitstream will not be smoothed across tiles/qualities, and concurrency may happen between different media +Each first packet of a segment will have the following properties attached: .br -delay40X (uint, default: 500): delay in millisconds to wait between two 40X on the same segment +* `CueStart`: indicate this is a segment start .br -exp_threshold (uint, default: 100): delay in millisconds to wait after the segment AvailabilityEndDate before considering the segment lost +* `FileNumber`: current segment number .br -switch_count (uint, default: 1): indicate how many segments the client shall wait before switching up bandwidth. If 0, switch will happen as soon as the bandwidth is enough, but this is more prone to network variations +* `FileName`: current segment file name without manifest base url .br -aggressive (bool, default: no): if enabled, switching algo targets the closest bandwidth fitting the available download rate. If no, switching algo targets the lowest bitrate representation that is above the currently played (eg does not try to switch to max bandwidth) +* `DFPStart`: set with value 0 if this is the first packet in the period, absent otherwise .br -debug_as (uint, default: -1): play only the adaptation set indicated by its index in the MPD; if negative, all sets are used + .br -speedadapt (bool, default: no): enable adaptation based on playback speed +If .I forward is set to mani, the first packet of a segment dispatched after a manifest update will also carry the manifest payload as a property: .br -noxlink (bool, default: no): disable xlink if period has both xlink and adaptation sets +* `DFManifest`: contains main manifest (MPD, M3U8 master) .br -query (str): set query string (without initial '?') to append to xlink of periods +* `DFVariant`: contains list of HLS child playlists as strings for the given quality .br -split_as (bool, default: no): separate all qualities into different adaptation sets and stream all qualities +* `DFVariantName`: contains list of associated HLS child playlists name, in same order as manifests in DFVariant .br -noseek (bool, default: no): disable seeking of initial segment(s) in dynamic mode (useful when UTC clocks do not match) + .br -lowlat (enum, default: early): segment scheduling policy in low latency mode +Each output PID will have the following properties assigned: .br -* no: disable low latency +* `DFMode`: set to 1 for segb or 2 for mani .br -* strict: strict respect of AST offset in low latency +* `DCue`: set to inband .br -* early: allow fetching segments earlier than their AST in low latency when input demux is empty +* `DFPStart`: set to current period start value .br - +* `FileName`: set to associated init segment if any .br - +* `Representation`: set to the associated representation ID in the manifest .br -.SH cdcrypt -.LP +* `DashDur`: set to the average segment duration as indicated in the manifest .br -Description: CENC decryptor +* `source_template`: set to true to indicate the source template is known .br - +* `stl_timescale`: timescale used by SegmentTimeline, or 0 if no SegmentTimeline .br -The CENC decryptor supports decrypting CENC, ISMA and Adobe streams. It uses a configuration file for retrieving keys. +* `init_url`: unresolved intialization URL (as it appears in the manifest) .br -The syntax is available at https://wiki.gpac.io/Common-Encryption +* `manifest_url`: manifest URL .br -The file can be set per PID using the property DecryptInfo (highest priority), CryptInfo (lower priority) or set at the filter level using .I cfile (lowest priority). + .br -When the file is set per PID, the first CryptInfo with the same ID is used, otherwise the first CryptInfo is used. +When the dasher is used together with this mode, this will force all generated segments to have the same name, duration and fragmentation properties as the input ones. It is therefore not recommended for sessions stored/generated on local storage to generate the output in the same directory. .br .br .SH Options (expert): .LP .br -cfile (str): crypt file location - see filter help +auto_switch (sint, default: 0): switch quality every N segments .br - +* positive: go to higher quality or loop to lowest .br -.SH cecrypt -.LP +* negative: go to lower quality or loop to highest .br -Description: CENC encryptor +* 0: disabled .br .br -The CENC encryptor supports CENC, ISMA and Adobe encryption. It uses a DRM config file for declaring keys. -.br -The syntax is available at https://wiki.gpac.io/Common-Encryption +segstore (enum, default: mem): enable file caching .br -The DRM config file can be set per PID using the property CryptInfo, or set at the filter level using .I cfile. +* mem: all files are stored in memory, no disk IO .br -When the DRM config file is set per PID, the first CrypTrack in the DRM config file with the same ID is used, otherwise the first CrypTrack is used. +* disk: files are stored to disk but discarded once played .br -If no DRM config file is defined for a given PID, this PID will not be encrypted, or an error will be thrown if .I allc is specified. +* cache: all files are stored to disk and kept .br .br - +algo (str, default: gbuf, minmax: none|grate|gbuf|bba0|bolaf|bolab|bolau|bolao|JS): adaptation algorithm to use .br -.SH Options (expert): -.LP +* none: no adaptation logic .br -cfile (str): crypt file location - see filter help +* grate: GPAC legacy algo based on available rate .br -allc (str): throw error if no DRM config file is found for a PID - see filter help +* gbuf: GPAC legacy algo based on buffer occupancy .br - +* bba0: BBA-0 .br -.SH mp4mx -.LP +* bolaf: BOLA Finite .br -Description: ISOBMFF/QT muxer +* bolab: BOLA Basic .br - +* bolau: BOLA-U .br -Muxes file according to ISOBMFF (14496-12 and derived specifications) or QuickTime +* bolao: BOLA-O .br - +* JS: use file JS (either with specified path or in $GSHARE/scripts/) for algo (.js extension may be omitted) .br -.SH Tracks and Items -.LP + .br -By default all input PIDs with ItemID property set are muxed as items, otherwise they are muxed as tracks. +start_with (enum, default: max_bw): initial selection criteria .br -To prevent source items to be muxed as items, use .I -itemid option from ISOBMF demuxer. +* min_q: start with lowest quality .br -Example +* max_q: start with highest quality .br --i source.mp4:itemid=false -o file.mp4 +* min_bw: start with lowest bitrate .br - +* max_bw: start with highest bitrate; if tiles are used, all low priority tiles will have the lower (below max) bandwidth selected .br - +* max_bw_tiles: start with highest bitrate; if tiles are used, all low priority tiles will have their lowest bandwidth selected .br -To force non-item streams to be muxed as items, use #ItemID option on that PID: + +.br +max_res (bool, default: true): use max media resolution to configure display +.br +abort (bool, default: false): allow abort during a segment download +.br +use_bmin (enum, default: auto): playout buffer handling +.br +* no: use default player settings +.br +* auto: notify player of segment duration if not low latency +.br +* mpd: use the indicated min buffer time of the MPD +.br + +.br +shift_utc (sint, default: 0): shift DASH UTC clock in ms +.br +route_shift (sint, default: 0): shift ROUTE requests time by given ms +.br +server_utc (bool, default: yes): use ServerUTC or Date HTTP headers instead of local UTC +.br +screen_res (bool, default: yes): use screen resolution in selection phase +.br +init_timeshift (sint, default: 0): set initial timeshift in ms (if >0) or in per-cent of timeshift buffer (if <0) +.br +tile_mode (enum, default: none): tile adaptation mode +.br +* none: bitrate is shared equally across all tiles +.br +* rows: bitrate decreases for each row of tiles starting from the top, same rate for each tile on the row +.br +* rrows: bitrate decreases for each row of tiles starting from the bottom, same rate for each tile on the row +.br +* mrows: bitrate decreased for top and bottom rows only, same rate for each tile on the row +.br +* cols: bitrate decreases for each columns of tiles starting from the left, same rate for each tile on the columns +.br +* rcols: bitrate decreases for each columns of tiles starting from the right, same rate for each tile on the columns +.br +* mcols: bitrate decreased for left and right columns only, same rate for each tile on the columns +.br +* center: bitrate decreased for all tiles on the edge of the picture +.br +* edges: bitrate decreased for all tiles on the center of the picture +.br + +.br +tiles_rate (uint, default: 100): indicate the amount of bandwidth to use at each quality level. The rate is recursively applied at each level, e.g. if 50%, Level1 gets 50%, level2 gets 25%, ... If 100, automatic rate allocation will be done by maximizing the quality in order of priority. If 0, bitstream will not be smoothed across tiles/qualities, and concurrency may happen between different media +.br +delay40X (uint, default: 500): delay in milliseconds to wait between two 40X on the same segment +.br +exp_threshold (uint, default: 100): delay in milliseconds to wait after the segment AvailabilityEndDate before considering the segment lost +.br +switch_count (uint, default: 1): indicate how many segments the client shall wait before switching up bandwidth. If 0, switch will happen as soon as the bandwidth is enough, but this is more prone to network variations +.br +aggressive (bool, default: no): if enabled, switching algo targets the closest bandwidth fitting the available download rate. If no, switching algo targets the lowest bitrate representation that is above the currently played (e.g. does not try to switch to max bandwidth) +.br +debug_as (uintl): play only the adaptation sets indicated by their indices (0-based) in the MPD +.br +speedadapt (bool, default: no): enable adaptation based on playback speed +.br +noxlink (bool, default: no): disable xlink if period has both xlink and adaptation sets +.br +query (str): set query string (without initial '?') to append to xlink of periods +.br +split_as (bool, default: no): separate all qualities into different adaptation sets and stream all qualities. Dependent representations (scalable) are treated as independent +.br +noseek (bool, default: no): disable seeking of initial segment(s) in dynamic mode (useful when UTC clocks do not match) +.br +bwcheck (uint, default: 5): minimum time in milliseconds between two bandwidth checks when allowing segment download abort +.br +lowlat (enum, default: early): segment scheduling policy in low latency mode +.br +* no: disable low latency +.br +* strict: strict respect of AST offset in low latency +.br +* early: allow fetching segments earlier than their AST in low latency when input PID is empty +.br + +.br +forward (enum, default: none): segment forwarding mode +.br +* none: regular DASH read +.br +* file: do not demultiplex files and forward them as file PIDs (imply segstore=mem) +.br +* segb: turn on .I split_as, segment and fragment bounds signaling (sigfrag) in sources and DASH cue insertion +.br +* mani: same as segb and also forward manifests +.br + +.br +fmodefwd (bool, default: yes): forward packet rather than copy them in file forward mode. Packet copy might improve performances in low latency mode +.br +skip_lqt (bool, default: no): disable decoding of tiles with highest degradation hints (not visible, not gazed at) for debug purposes +.br +llhls_merge (bool, default: yes): merge LL-HLS byte range parts into a single open byte range request +.br +groupsel (bool, default: no): select groups based on language (by default all playable groups are exposed) +.br +chain_mode (enum, default: on): MPD chaining mode +.br +* off: do not use MPD chaining +.br +* on: use MPD chaining once over, fallback if MPD load failure +.br +* error: use MPD chaining once over or if error (MPD or segment download) +.br + +.br +asloop (bool, default: false): when auto switch is enabled, iterates back and forth from highest to lowest qualities +.br + +.br +.SH cdcrypt +.LP +.br +Description: CENC decryptor +.br + +.br +The CENC decryptor supports decrypting CENC, ISMA, HLS Sample-AES (MPEG2 ts) and Adobe streams. +.br + +.br +For HLS, key is retrieved according to the key URI in the manifest. +.br +Otherwise, the filter uses a configuration file. +.br +The syntax is available at https://wiki.gpac.io/Common-Encryption +.br +The DRM config file can be set per PID using the property DecryptInfo (highest priority), CryptInfo (lower priority) or set at the filter level using .I cfile (lowest priority). +.br +When the file is set per PID, the first CryptInfo with the same ID is used, otherwise the first CryptInfo is used.When the file is set globally (not per PID), the first CrypTrack in the DRM config file with the same ID is used, otherwise the first CrypTrack with ID 0 or not set is used. +.br + +.br +.SH Options (expert): +.LP +.br +cfile (str): crypt file location +.br +decrypt (enum, default: full): decrypt mode (CENC only) +.br +* full: decrypt everything, throwing error if keys are not found +.br +* nokey: decrypt everything for which a key is found, skip decryption otherwise +.br +* skip: decrypt nothing +.br + +.br +drop_keys (uintl): consider keys with given 1-based indexes as not available (multi-key debug) +.br +kids (strl): define KIDs. If keys is empty, consider keys with given KID (as hex string) as not available (debug) +.br +keys (strl): define key values for each of the specified KID +.br +hls_cenc_patch_iv (bool, default: false): ignore IV updates in some broken HLS+CENC streams +.br + +.br +.SH cecrypt +.LP +.br +Description: CENC encryptor +.br + +.br +The CENC encryptor supports CENC, ISMA and Adobe encryption. It uses a DRM config file for declaring keys. +.br +The syntax is available at https://wiki.gpac.io/Common-Encryption +.br +The DRM config file can be set per PID using the property CryptInfo, or set at the filter level using .I cfile. +.br +When the DRM config file is set per PID, the first CrypTrack in the DRM config file with the same ID is used, otherwise the first CrypTrack is used (regardless of the CrypTrack ID). +.br +When the DRM config file is set globally (not per PID), the first CrypTrack in the DRM config file with the same ID is used, otherwise the first CrypTrack with ID 0 or not set is used. +.br +If no DRM config file is defined for a given PID, this PID will not be encrypted, or an error will be thrown if .I allc is specified. +.br + +.br +.SH Options (expert): +.LP +.br +cfile (str): crypt file location +.br +allc (bool): throw error if no DRM config file is found for a PID +.br + +.br +.SH mp4mx +.LP +.br +Description: ISOBMFF/QT multiplexer +.br + +.br +This filter multiplexes streams to ISOBMFF (14496-12 and derived specifications) or QuickTime +.br + +.br +.SH Tracks and Items +.LP +.br +By default all input PIDs with ItemID property set are multiplexed as items, otherwise they are multiplexed as tracks. +.br +To prevent source items to be multiplexed as items, use .I -itemid option from ISOBMFF demultiplexer. .br Example .br --i source.jpg:#ItemID=1 -o file.mp4 +gpac -i source.mp4:itemid=false -o file.mp4 +.br + +.br + +.br +To force non-item streams to be multiplexed as items, use #ItemID option on that PID: +.br +Example +.br +gpac -i source.jpg:#ItemID=1 -o file.mp4 .br .br @@ -1649,17 +1945,17 @@ Example .SH Storage .LP .br -The .I store option allows controling if the file is fragmented ot not, and when not fragmented, how interleaving is done. For cases where disk requirements are tight and fragmentation cannot be used, it is recommended to use either flat or fstart modes. +The .I store option allows controlling if the file is fragmented or not, and when not fragmented, how interleaving is done. For cases where disk requirements are tight and fragmentation cannot be used, it is recommended to use either flat or fstart modes. .br .br -The .I vodcache option allows controling how DASH onDemand segments are generated: +The .I vodcache option allows controlling how DASH onDemand segments are generated: .br - If set to on, file data is stored to a temporary file on disk and flushed upon completion, no padding is present. .br - If set to insert, SIDX/SSIX will be injected upon completion of the file by shifting bytes in file. In this case, no padding is required but this might not be compatible with all output sinks and will take longer to write the file. .br -- If set to replace, SIDX/SSIX size will be estimated based on duration and DASH segment length, and padding will be used in the file before the final SIDX. If input pids have the properties DSegs set, this will be as the number of segments. +- If set to replace, SIDX/SSIX size will be estimated based on duration and DASH segment length, and padding will be used in the file before the final SIDX. If input PIDs have the properties DSegs set, this will used be as the number of segments. .br The on and insert modes will produce exactly the same file, while the mode replace may inject a free box before the sidx. .br @@ -1676,7 +1972,7 @@ Per PID box patch can be specified through the PID property boxpatch. .br Example .br -src=source:#boxpatch=myfile.xml dst=mux.mp4 +gpac -i source:#boxpatch=myfile.xml -o mux.mp4 .br .br @@ -1684,7 +1980,7 @@ Per Item box patch can be specified through the PID property boxpatch. .br Example .br -src=source:1ItemID=1:#boxpatch=myfile.xml dst=mux.mp4 +gpac -i source:1ItemID=1:#boxpatch=myfile.xml -o mux.mp4 .br .br @@ -1699,24 +1995,84 @@ The box patch can either be a filename or the full XML string. .SH Tagging .LP .br -When tagging is enabled, the filter will watch the property CoverArt and all custom properties on incoming pid. +When tagging is enabled, the filter will watch the property CoverArt and all custom properties on incoming PID. .br -The built-in tag names are album, artist, comment, complilation, composer, year, disk, tool, genre, contentgroup, title, tempo, track, tracknum, writer, encoder, album_artist, gapless, conductor. +The built-in tag names are indicated by MP4Box -h tags. .br Other tag class may be specified using tag_NAME property names, and will be added if .I tags is set to all using: .br - NAME as a box 4CC if NAME is four characters long .br +- NAME as a box 4CC if NAME is 3 characters long, and will be prefixed by 0xA9 +.br - the CRC32 of the NAME as a box 4CC if NAME is not four characters long .br +.br +.SH User data +.LP +.br +The filter will look for the following PID properties to create user data entries: +.br +* `udtab`: set the track user-data box to the property value which must be a serialized box array blob +.br +* `mudtab`: set the movie user-data box to the property value which must be a serialized box array blob +.br +* `udta_U4CC`: set track user-data box entry of type U4CC to property value +.br +* `mudta_U4CC`: set movie user-data box entry of type U4CC to property value +.br + +.br +Example +.br +gpac -i src.mp4:#udta_tagc='My Awesome Tag' -o tag.mp4 +.br +gpac -i src.mp4:#mudtab=data@box.bin -o tag.mp4 +.br + +.br + +.br +.SH Custom sample group descriptions and sample auxiliary info +.LP +.br +The filter watches the following custom data properties on incoming packets: +.br +* `grp_A4CC`: maps packet to sample group description of type A4CC and entry set to property payload +.br +* `grp_A4CC_param`: same as above and sets sample to group grouping_type_parameter to param +.br +* `sai_A4CC`: adds property payload as sample auxiliary information of type A4CC +.br +* `sai_A4CC_param`: same as above and sets aux_info_type_parameterto param +.br + +.br +The property grp_EMSG consists in one or more EventMessageBox as defined in MPEG-DASH. +.br +- in fragmented mode, presence of these boxes in a packet will start a new fragment, with the boxes written before the moof +.br +- in regular mode, an internal sample group of type EMSG is currently used for emsg box storage +.br + .br .SH Notes .LP .br -The filter watches the property FileNumber on incoming packets to create new files or new segments in DASH mode. +The filter watches the property FileNumber on incoming packets to create new files (regular mode) or new segments (DASH mode). +.br + +.br +The filter watches the property DSIWrap (4CC as int or string) on incoming PID to wrap decoder configuration in a box of given type (unknonw wraping) +.br +Example +.br +-i unkn.mkv:#ISOMSubtype=VIUK:#DSIWrap=cfgv -o t.mp4 .br +.br +This will wrap the uknown stream using VIUK code point in stsd and wrap any decoder configuration data in a cfgv box. .br .br @@ -1725,7 +2081,7 @@ The filter watches the property FileNumber on incoming packets to create new fil .br m4sys (bool, default: false): force MPEG-4 Systems signaling of tracks .br -dref (bool, default: false): only references data from source file - not compatible with all media sources +dref (bool, default: false): only reference data from source file - not compatible with all media sources .br ctmode (enum, default: edit): set composition offset mode for video tracks .br @@ -1737,7 +2093,7 @@ ctmode (enum, default: edit): set composition offset mode for video tracks .br .br -idur (frac, default: 0): only import the specified duration. If negative, specify the number of coded frames to import +dur (frac, default: 0): only import the specified duration. If negative, specify the number of coded frames to import .br pack3gp (uint, default: 1): pack a given number of 3GPP audio frames in one sample .br @@ -1745,16 +2101,20 @@ importer (bool, default: false): compatibility with old importer, displays impor .br pack_nal (bool, default: false): repack NALU size length to minimum possible size for NALU-based video (AVC/HEVC/...) .br -xps_inband (enum, default: no): use inband (in sample data) param set for NALU-based video (AVC/HEVC/...) +xps_inband (enum, default: no): use inband (in sample data) parameter set for NALU-based video (AVC/HEVC/...) +.br +* no: parameter sets are not inband, several sample descriptions might be created .br -* no: paramater sets are not inband, several sample descriptions might be created +* pps: picture parameter sets are inband, all other parameter sets are in sample description .br -* all: paramater sets are inband, no param sets in sample description +* all: parameter sets are inband, no parameter sets in sample description .br -* both: paramater sets are inband, signaled as inband, and also first set is kept in sample descripton +* both: parameter sets are inband, signaled as inband, and also first set is kept in sample description .br * mix: creates non-standard files using single sample entry with first PSs found, and moves other PS inband .br +* auto: keep source config, or defaults to no if source is not ISOBMFF +.br .br store (enum, default: inter): file storage mode @@ -1769,15 +2129,17 @@ store (enum, default: inter): file storage mode .br * frag: fragments the file using cdur duration .br -* sfrag: framents the file using cdur duration but adjusting to start with SAP1/3 +* sfrag: fragments the file using cdur duration but adjusting to start with SAP1/3 .br .br -cdur (dbl, default: -1.0): chunk duration for interleaving and fragmentation modes +cdur (frac, default: -1/1): chunk duration for flat and interleaving modes or fragment duration for fragmentation modes .br * 0: no specific interleaving but moov first .br * negative: defaults to 1.0 unless overridden by storage profile +.br + .br moovts (sint, default: 600): timescale to use for movie. A negative value picks the media timescale of the first track added .br @@ -1787,27 +2149,27 @@ abs_offset (bool, default: false): use absolute file offset in fragments rather .br fsap (bool, default: true): split truns in video fragments at SAPs to reduce file size .br -subs_sidx (sint, default: -1): number of subsegments per sidx. negative value disables sidx, -2 removes sidx if present in source pid +subs_sidx (sint, default: -1): number of subsegments per sidx. negative value disables sidx, -2 removes sidx if present in source PID .br -m4cc (str): 4 character code of empty box to appen at the end of a segment +m4cc (str): 4 character code of empty box to append at the end of a segment .br chain_sidx (bool, default: false): use daisy-chaining of SIDX .br msn (uint, default: 1): sequence number of first moof to N .br -msninc (uint, default: 1): sequence number increase between moofs +msninc (uint, default: 1): sequence number increase between moof boxes .br -tfdt (lfrac, default: 0): set TFDT of first traf +tfdt (lfrac, default: 0): set initial decode time (tfdt) of first traf .br -tfdt_traf (bool, default: false): set TFDT in each traf +tfdt_traf (bool, default: false): force tfdt box in each traf .br nofragdef (bool, default: false): disable default flags in fragments .br -straf (bool, default: false): use a single traf per moov (smooth streaming and co) +straf (bool, default: false): use a single traf per moof (smooth streaming and co) .br strun (bool, default: false): use a single trun per traf (smooth streaming and co) .br -psshs (enum, default: moov): set PSSH boxes store mode +psshs (enum, default: moov): set pssh boxes store mode .br * moof: in first moof of each segments .br @@ -1819,7 +2181,7 @@ psshs (enum, default: moov): set PSSH boxes store mode .br sgpd_traf (bool, default: false): store sample group descriptions in traf (duplicated for each traf). If not used, sample group descriptions are stored in the movie box .br -vodcache (enum, default: replace): enable temp storage for VoD dash modes - see filter help +vodcache (enum, default: replace): enable temp storage for VoD dash modes .br * on: use temp storage of complete file for sidx and ssix injection .br @@ -1851,15 +2213,13 @@ mudta (enum, default: yes): use udta and other moov extension boxes from inpu .br .br -tmpd (str): set temp directory for intermediate file(s) -.br -mvex (bool, default: false): set mvex after tracks +mvex (bool, default: false): set mvex boxes after trak boxes .br -sdtp_traf (enum, default: no): use sdtp in traf rather than using flags in trun sample entries +sdtp_traf (enum, default: no): use sdtp box in traf box rather than using flags in trun sample entries .br * no: do not use sdtp .br -* sdtp: use sdtp box to indicate sample dependencies and don't write info in trun sample flags +* sdtp: use sdtp box to indicate sample dependencies and do not write info in trun sample flags .br * both: use sdtp box to indicate sample dependencies and also write info in trun sample flags .br @@ -1871,9 +2231,9 @@ fragdur (bool, default: false): fragment based on fragment duration rather than .br btrt (bool, default: true): set btrt box in sample description .br -styp (str): set segment styp major brand to the given 4CC[.version] +styp (str): set segment styp major brand (and optionally version) to the given 4CC[.version] .br -mediats (sint, default: 0): set media timescale. A value of 0 means inherit from pid, a value of -1 means derive from samplerate or frame rate +mediats (sint, default: 0): set media timescale. A value of 0 means inherit from PID, a value of -1 means derive from samplerate or frame rate .br ase (enum, default: v0): set audio sample entry mode for more than stereo layouts .br @@ -1887,7 +2247,7 @@ ase (enum, default: v0): set audio sample entry mode for more than stereo .br .br -ssix (bool, default: false): create ssix when sidx is present, level 1 mappping I-frames byte ranges, level 0xFF mapping the rest +ssix (bool, default: false): create ssix box when sidx box is present, level 1 mapping I-frames byte ranges, level 0xFF mapping the rest .br ccst (bool, default: false): insert coding constraint box for video tracks .br @@ -1895,7 +2255,11 @@ maxchunk (uint, default: 0): set max chunk size in bytes for runs (only used i .br noroll (bool, default: false): disable roll sample grouping .br -saio32 (bool, default: false): set single segment mode for dash +norap (bool, default: false): disable rap sample grouping +.br +saio32 (bool, default: false): use 32 bit offset for side data location instead of 64 bit offset +.br +tfdt64 (bool, default: false): use 64 bit tfdt and sidx even for 32 bits timestamps .br compress (enum, default: no): set top-level box compression mode .br @@ -1915,7 +2279,11 @@ compress (enum, default: no): set top-level box compression mode .br fcomp (bool, default: false): force using compress box even when compressed size is larger than uncompressed .br -trun_inter (bool, default: false): interleave samples in trun based on the temporal level, the lowest level are stored first - this will create as many trun as required +otyp (bool, default: false): inject original file type when using compressed boxes +.br +trun_inter (bool, default: false): interleave samples in trun based on the temporal level, the lowest level are stored first (this will create as many trun boxes as required) +.br +truns_first (bool, default: false): store track runs before sample group description and sample encryption information .br block_size (uint, default: 10000): target output block size, 0 for default internal value (10k) .br @@ -1925,9 +2293,11 @@ deps (bool, default: true): add samples dependencies information .br mfra (bool, default: false): enable movie fragment random access when fragmenting (ignored when dashing) .br -forcesync (bool, default: false): force all SAP types to be considered sync samples (might produce non-conformant files) +forcesync (bool, default: false): force all SAP types to be considered sync samples (might produce non-compliant files) .br -tags (enum, default: strict): tag injection mode +refrag (bool, default: false): use track fragment defaults from initial file if any rather than computing them from PID properties (used when processing standalone segments/fragments) +.br +itags (enum, default: strict): tag injection mode .br * none: do not inject tags .br @@ -1936,6 +2306,22 @@ tags (enum, default: strict): tag injection mode * all: inject all possible tags .br +.br +keep_utc (bool, default: false): force all new files and tracks to keep the source UTC creation and modification times +.br +pps_inband (bool, default: no): when .I xps_inband is set, inject PPS in each non SAP 1/2/3 sample +.br +moovpad (uint, default: 0): insert free box of given size after moov for future in-place editing +.br +cmaf (enum, default: no): use CMAF guidelines (turns on mvex, truns_first, strun, straf, tfdt_traf, chain_sidx and restricts subs_sidx to -1 or 0) +.br +* no: CMAF not enforced +.br +* cmfc: use CMAF cmfc guidelines +.br +* cmf2: use CMAF cmf2 guidelines (turns on nofragdef) +.br + .br .br @@ -1975,6 +2361,8 @@ fps (frac, default: 15000/1000): import frame rate .br index (dbl, default: 1.0): indexing window length .br +notime (bool, default: false): ignore input timestamps, rebuild from 0 +.br .br .SH rfmpgvid @@ -1986,7 +2374,7 @@ Description: M1V/M2V/M4V reframer .br This filter parses MPEG-1/2 and MPEG-4 part 2 video files/data and outputs corresponding video PID and frames. .br -Note: The demux uses negative CTS offsets: CTS is corrrect, but some frames may have DTS greater than CTS. +Note: The filter uses negative CTS offsets: CTS is correct, but some frames may have DTS greater than CTS. .br .br @@ -2001,6 +2389,8 @@ vfr (bool, default: false): set variable frame rate import .br importer (bool, default: false): compatibility with old importer, displays import results .br +notime (bool, default: false): ignore input timestamps, rebuild from 0 +.br .br .SH nhntr @@ -2015,13 +2405,11 @@ This filter reads NHNT files/data to produce a media PID and frames. NHNT documentation is available at https://wiki.gpac.io/NHNT-Format .br -.br - .br .SH Options (expert): .LP .br -reframe (bool, default: false): force reparsing of referenced content +reframe (bool, default: false): force re-parsing of referenced content .br index (dbl, default: 1.0): indexing window length .br @@ -2030,7 +2418,7 @@ index (dbl, default: 1.0): indexing window length .SH nhmlr .LP .br -Description: NHML parser +Description: NHML reader .br .br @@ -2039,13 +2427,11 @@ This filter reads NHML files/data to produce a media PID and frames. NHML documentation is available at https://wiki.gpac.io/NHML-Format .br -.br - .br .SH Options (expert): .LP .br -reframe (bool, default: false): force reparsing of referenced content +reframe (bool, default: false): force re-parsing of referenced content .br index (dbl, default: 1.0): indexing window length .br @@ -2060,9 +2446,9 @@ Description: AVC/HEVC reframer .br This filter parses AVC|H264 and HEVC files/data and outputs corresponding video PID and frames. .br -This demuxer only produces ISOBMFF-compatible output: start codes are removed, NALU length field added and avcC/hvcC config created. +This filter produces ISOBMFF-compatible output: start codes are removed, NALU length field added and avcC/hvcC config created. .br -Note: The demux uses negative CTS offsets: CTS is corrrect, but some frames may have DTS greater than CTS. +Note: The filter uses negative CTS offsets: CTS is correct, but some frames may have DTS greater than CTS. .br .br @@ -2071,7 +2457,7 @@ Note: The demux uses negative CTS offsets: CTS is corrrect, but some frames may .br fps (frac, default: 0/1000): import frame rate (0 default to FPS from bitstream or 25 Hz) .br -index (dbl, default: -1.0): indexing window length. If 0, bitstream is not probed for duration. A negative value skips the indexing if the source file is larger than 100M (slows down importers) unless a play with start range > 0 is issued, otherwise uses the positive value +index (dbl, default: -1.0): indexing window length. If 0, bitstream is not probed for duration. A negative value skips the indexing if the source file is larger than 100M (slows down importers) unless a play with start range > 0 is issued .br explicit (bool, default: false): use explicit layered (SVC/LHVC) import .br @@ -2097,82 +2483,201 @@ nal_length (uint, default: 4): set number of bytes used to code length field: 1, .br subsamples (bool, default: false): import subsamples information .br -deps (bool, default: false): import samples dependencies information +deps (bool, default: false): import sample dependency information .br seirw (bool, default: true): rewrite AVC sei messages for ISOBMFF constraints .br audelim (bool, default: false): keep Access Unit delimiter in payload .br - +notime (bool, default: false): ignore input timestamps, rebuild from 0 .br -.SH m2psdmx -.LP +dv_mode (enum, default: auto): signaling for DolbyVision .br -Description: MPEG PS demuxer +* none: never signal DV profile .br - +* auto: signal DV profile if RPU or EL are found .br -This filter demultiplexes MPEG-2 program stream files/data to produce media PIDs and frames. +* force: always signal DV profile .br - +* clean: do not signal and remove RPU and EL NAL units .br -No options +* single: remove EL NAL units .br .br -.SH avidmx -.LP +dv_profile (uint, default: 5): profile for DolbyVision (currently defined profiles are 4, 5, 7, 8, 9) .br -Description: AVI demuxer +dv_compatid (enum, default: none): cross-compatibility ID for DolbyVision .br - +* none: do not signal compatibility .br -This filter demultiplexes AVI files/data to produce media PIDs and frames. +* hdr10: CTA HDR10, as specified by EBU TR 03 .br - +* bt709: SDR BT.709 .br -.SH Options (expert): -.LP +* hlg709: HLG BT.709 gamut in ITU-R BT.2020 .br -fps (frac, default: 1/0): import frame rate, default is AVI one +* hlg2100: HLG BT.2100 gamut in ITU-R BT.2020 .br -importer (bool, default: false): compatibility with old importer, displays import results +* bt2020: SDR BT.2020 .br - +* brd: Ultra HD Blu-ray Disc HDR .br -.SH txtin -.LP + .br -Description: Subtitle loader +bsdbg (enum, default: off): debug NAL parsing in parser@debug logs .br - +* off: not enabled .br -This filter reads subtitle data (srt/webvtt/ttxt/sub) to produce media PIDs and frames. +* on: enabled .br -The TTXT documentation is available at https://wiki.gpac.io/TTXT-Format-Documentation +* full: enable with number of bits dumped .br .br .br -.SH Options (expert): +.SH m2psdmx .LP .br -webvtt (bool, default: false): force WebVTT import of SRT files +Description: MPEG PS demultiplexer +.br + +.br +This filter demultiplexes MPEG-2 program streams to produce media PIDs and frames. +.br + +.br +No options +.br + +.br +.SH avidmx +.LP +.br +Description: AVI demultiplexer +.br + +.br +This filter demultiplexes AVI files to produce media PIDs and frames. +.br + +.br +.SH Options (expert): +.LP +.br +fps (frac, default: 1/0): import frame rate, default is AVI one +.br +importer (bool, default: false): compatibility with old importer, displays import results +.br + +.br +.SH txtin +.LP +.br +Description: Subtitle loader +.br + +.br +This filter reads subtitle data from input file PID to produce subtitle frames on a single PID. +.br +The filter supports the following formats: +.br +* SRT: https://en.wikipedia.org/wiki/SubRip +.br +* WebVTT: https://www.w3.org/TR/webvtt1/ +.br +* TTXT: https://wiki.gpac.io/TTXT-Format-Documentation +.br +* QT 3GPP Text XML (TexML): Apple QT6, likely deprecated +.br +* TTML: https://www.w3.org/TR/ttml2/ +.br +* SUB: one subtitle per line formatted as {start_frame}{end_frame}text +.br + +.br +Input files must be in UTF-8 or UTF-16 format, with or without BOM. The internal frame format is: +.br +* WebVTT (and srt if desired): ISO/IEC 14496-30 VTT cues +.br +* TTML: ISO/IEC 14496-30 XML subtitles +.br +* Others: 3GPP/QT Timed Text +.br + +.br +.SH TTML Support +.LP +.br +The .I ttml_dur option controls how the TTML document is split into packets: +.br +- if negative (default), TTML document is split in independent time segments by inspecting all overlapping subtitles in the body +.br +- if 0, the input document is not split, forwarded as a single frame with CTS matching the first active time in document and a duration equal to the document duration +.br +- if >0, the input document is not split, forwarded as a single frame with CTS=0 and the specified duration in timescale units. +.br + +.br +By default, media resources are kept as declared in TTML2 documents. +.br + +.br +.I ttml_embed can be used to embed inside the TTML sample the resources in or : +.br +- for , ,