From 8f008af3c7a61c4d0c2c76248a6ffd8a79fae9cc Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Mon, 28 Jan 2019 17:13:59 -0500 Subject: [PATCH] New upstream version 0.7.1 --- .gitattributes | 3 + .github/ISSUE_TEMPLATE.md | 7 + .gitignore | 90 + .travis.yml | 60 +- AUTHORS | 29 +- BUGS | 8 +- Changelog | 4 +- Clean.bat | 46 +- INSTALLME | 12 +- Makefile | 147 +- README | 18 - README.md | 21 + TODO | 10 +- applications/dashcast/Makefile | 37 +- applications/dashcast/audio_data.c | 6 +- applications/dashcast/audio_data.h | 3 + applications/dashcast/audio_decoder.c | 73 +- applications/dashcast/audio_decoder.h | 2 +- applications/dashcast/audio_encoder.c | 20 +- applications/dashcast/audio_muxer.c | 24 +- applications/dashcast/audio_muxer.h | 5 +- applications/dashcast/circular_buffer.c | 10 +- applications/dashcast/cmd_data.c | 80 +- applications/dashcast/cmd_data.h | 3 +- applications/dashcast/controler.c | 547 +-- applications/dashcast/dashcast.c | 9 +- applications/dashcast/message_queue.c | 2 +- applications/dashcast/register.c | 2 +- applications/dashcast/task.c | 4 +- applications/dashcast/video_data.c | 8 +- applications/dashcast/video_data.h | 4 + applications/dashcast/video_decoder.c | 89 +- applications/dashcast/video_decoder.h | 4 +- applications/dashcast/video_encoder.c | 72 +- applications/dashcast/video_muxer.c | 175 +- applications/dashcast/video_muxer.h | 4 +- applications/dashcast/video_scaler.c | 28 +- applications/dashcast/video_scaler.h | 7 +- applications/generators/MPEG4/MPEG4Gen.dsp | 196 +- applications/generators/MPEG4/MPEG4Gen.dsw | 58 +- applications/generators/MPEG4/Makefile | 2 +- applications/generators/MPEG4/main.c | 1 + applications/generators/SVG/Makefile | 2 +- applications/generators/SVG/SVGGen.dsp | 252 +- applications/generators/SVG/SVGGen.dsw | 58 +- applications/generators/SVG/v3.c | 12 +- applications/generators/X3D/Makefile | 2 +- applications/generators/X3D/X3DGen.dsp | 196 +- applications/generators/X3D/X3DGen.dsw | 58 +- applications/generators/X3D/main.c | 1 + applications/m3u82mpd/m3u82mpd.vcproj | 183 - applications/m3u82mpd/main.c | 122 - applications/mp42avi/Makefile | 2 +- applications/mp42avi/main.c | 2 +- applications/mp42ts/Makefile | 22 +- applications/mp42ts/main.c | 291 +- applications/mp42ts/mp42ts.h | 202 - applications/mp4box/Makefile | 50 +- applications/mp4box/filedump.c | 655 ++- applications/mp4box/fileimport.c | 354 +- applications/mp4box/live.c | 48 +- applications/mp4box/main.c | 3480 +++++++------ applications/mp4client/Makefile | 25 +- applications/mp4client/carbon_events.c | 6 +- applications/mp4client/extract.c | 106 +- applications/mp4client/main.c | 431 +- applications/osmo4_android_studio/.gitignore | 41 + applications/osmo4_android_studio/Readme.md | 11 + .../osmo4_android_studio/app/build.gradle | 36 + .../osmo4_android_studio/app/libs/real3d.jar | Bin 0 -> 3786 bytes .../app/src/main/AndroidManifest.xml | 155 + .../app/src/main/assets/configuration.xml | 171 + .../main/java/com/gpac/Osmo4/BitmapView.java | 93 + .../java/com/gpac/Osmo4/GPACInstance.java | 425 ++ .../com/gpac/Osmo4/GPACInstanceInterface.java | 70 + .../java/com/gpac/Osmo4/GpacCallback.java | 313 ++ .../main/java/com/gpac/Osmo4/GpacConfig.java | 236 + .../main/java/com/gpac/Osmo4/MPEGVSensor.java | 503 ++ .../src/main/java/com/gpac/Osmo4/Osmo4.java | 1383 ++++++ .../com/gpac/Osmo4/Osmo4GLSurfaceView.java | 234 + .../java/com/gpac/Osmo4/Osmo4Renderer.java | 98 + .../src/main/java/com/gpac/Osmo4/Preview.java | 694 +++ .../java/com/gpac/Osmo4/SensorServices.java | 385 ++ .../gpac/Osmo4/extra/ConfigFileEditor.java | 326 ++ .../Osmo4/extra/ConfigFileEditorActivity.java | 150 + .../gpac/Osmo4/extra/FileArrayAdapter.java | 144 + .../gpac/Osmo4/extra/FileChooserActivity.java | 97 + .../gpac/Osmo4/extra/FileChooserFragment.java | 160 + .../com/gpac/Osmo4/extra/FileManager.java | 189 + .../com/gpac/Osmo4/extra/PrefsActivity.java | 31 + .../com/gpac/Osmo4/extra/XMLTagHandler.java | 40 + .../java/com/gpac/Osmo4/logs/GpacLogger.java | 159 + .../app/src/main/jni/README.txt | 2 + .../app/src/main/jni/wrapper.cpp | 1098 +++++ .../app/src/main/jni/wrapper.h | 239 + .../app/src/main/jni/wrapper_jni.cpp | 200 + .../app/src/main/jni/wrapper_jni.hpp | 83 + .../app/src/main/res/drawable-hdpi/icon.png | Bin 0 -> 9339 bytes .../app/src/main/res/drawable-ldpi/icon.png | Bin 0 -> 3105 bytes .../src/main/res/drawable-mdpi/ic_audio.xml | 9 + .../main/res/drawable-mdpi/ic_compressed.xml | 9 + .../src/main/res/drawable-mdpi/ic_error.xml | 9 + .../src/main/res/drawable-mdpi/ic_file.xml | 9 + .../src/main/res/drawable-mdpi/ic_folder.xml | 9 + .../src/main/res/drawable-mdpi/ic_image.xml | 9 + .../src/main/res/drawable-mdpi/ic_video.xml | 9 + .../app/src/main/res/drawable-mdpi/icon.png | Bin 0 -> 4070 bytes .../app/src/main/res/drawable/ic_back.xml | 9 + .../app/src/main/res/layout/about_dialog.xml | 63 + .../layout/activity_config_file_editor.xml | 197 + .../main/res/layout/activity_file_chooser.xml | 7 + .../src/main/res/layout/auth_requested.xml | 92 + .../main/res/layout/fragment_file_chooser.xml | 17 + .../res/layout/list_item_file_chooser.xml | 85 + .../app/src/main/res/layout/main.xml | 37 + .../app/src/main/res/menu/main_menu.xml | 105 + .../app/src/main/res/values/arrays.xml | 26 + .../app/src/main/res/values/strings.xml | 94 + .../app/src/main/res/xml/preference.xml | 38 + .../osmo4_android_studio/build.gradle | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + applications/osmo4_android_studio/gradlew | 160 + applications/osmo4_android_studio/gradlew.bat | 90 + .../osmo4_android_studio/import-summary.txt | 136 + .../osmo4_android_studio/settings.gradle | 1 + applications/testapps/bmp4demux/Makefile | 2 +- applications/testapps/bmp4demux/bmp4demux.sln | 40 +- .../testapps/bmp4demux/bmp4demux.vcxproj | 380 +- applications/testapps/broadcaster/Makefile | 2 +- .../testapps/broadcaster/broadcaster.c | 2 +- .../testapps/broadcaster/broadcaster.dsp | 292 +- applications/testapps/dmbrs/dmbrs.dsp | 180 +- applications/testapps/fmp4demux/Makefile | 2 +- applications/testapps/fmp4demux/fmp4demux.sln | 40 +- .../testapps/fmp4demux/fmp4demux.vcxproj | 339 +- .../fmp4demux/fmp4demux.vcxproj.filters | 134 - applications/testapps/fmp4demux/main.c | 52 +- applications/testapps/hevcbench/Makefile | 50 + applications/testapps/hevcbench/defbench.h | 18 +- .../testapps/hevcbench/hevcbench.vcxproj | 526 +- applications/testapps/hevcbench/main.c | 318 +- applications/testapps/largefile/largefile.dsp | 204 +- applications/testapps/largefile/largefile.dsw | 88 +- .../testapps/loadcompare/LoadCompare.dsp | 224 +- applications/testapps/loadcompare/Makefile | 2 +- .../testapps/loadcompare/loadcompare.c | 2 +- applications/testapps/mp42ts/mp42ts.vcproj | 217 - applications/testapps/mpedemux/Makefile | 2 +- applications/testapps/mpedemux/mpedemux.dsp | 180 +- applications/testapps/mpeg2ts/mpeg2ts.dsp | 200 +- applications/testapps/player_api/main.c | 112 + applications/testapps/segmp4demux/Makefile | 2 +- applications/testapps/segmp4demux/main.c | 2 +- .../testapps/segmp4demux/segmp4demux.sln | 40 +- .../testapps/segmp4demux/segmp4demux.vcxproj | 380 +- applications/testapps/svg2bifs/main.c | 2 +- applications/testapps/svg2bifs/svg2bifs.dsp | 180 +- applications/testapps/ts2udp/main.c | 149 + applications/testapps/ts2udp/ts2udp.vcxproj | 170 + applications/ts2hds/Makefile | 2 +- applications/ts2hds/main.c | 4 +- applications/udptsseg/Makefile | 2 +- applications/udptsseg/main.c | 2 +- applications/udptsseg/udptsseg.dsp | 188 +- applications/udptsseg/udptsseg.vcproj | 426 +- .../release/install/archive.bat | 32 +- .../release/install/build_installer.bat | 84 +- change_version.sh | 79 + check_revision.sh | 37 + configure | 169 +- debian/changelog | 6 + debian/compat | 1 + debian/control | 33 + debian/copyright | 13 + debian/dirs | 2 + debian/docs | 3 + debian/gpac-doc.docs | 2 + debian/gpac-doc.install | 2 + debian/gpac.install | 7 + debian/libgpac-dev.install | 2 + debian/postinst | 7 + debian/postrm | 5 + debian/rules | 109 + debian/watch | 3 + doc/configuration.html | 116 +- doc/doxyfile | 439 +- doc/man/dashcast.1 | 161 + doc/man/gpac.1 | 2 +- doc/man/mp42ts.1 | 172 + doc/man/mp4box.1 | 4 +- generate_installer.bat | 206 +- gpac.spec | 10 +- gui/extensions/H2B2VS/h2b2vs.js | 102 +- .../bifs_tests/applications-other.svg | 204 + gui/extensions/bifs_tests/bifs_tests.js | 354 ++ gui/extensions/bifs_tests/init.js | 16 + gui/extensions/player/fileopen.js | 339 +- gui/extensions/player/player.js | 689 ++- gui/extensions/player/playlist.js | 64 +- gui/extensions/player/stats.js | 418 +- gui/extensions/showroom/init.js | 16 + gui/extensions/showroom/osmo.bt | 107 + gui/extensions/showroom/showroom.js | 180 + gui/gui.bt | 1 - gui/gui.js | 82 +- gui/gwlib.js | 215 +- gui/icons/compass.svg | 45 + gui/webvtt-renderer.js | 18 +- include/gpac/ait.h | 33 +- include/gpac/avparse.h | 73 +- include/gpac/base_coding.h | 12 +- include/gpac/bifs.h | 17 + include/gpac/bitstream.h | 4 +- include/gpac/cache.h | 8 +- include/gpac/color.h | 21 +- include/gpac/compositor.h | 17 + include/gpac/config_file.h | 10 +- include/gpac/configuration.h | 35 +- include/gpac/constants.h | 197 +- include/gpac/crypt.h | 17 + include/gpac/dash.h | 166 +- include/gpac/download.h | 42 +- include/gpac/esi.h | 15 + include/gpac/events.h | 38 + include/gpac/events_constants.h | 20 + include/gpac/filestreamer.h | 12 +- include/gpac/html5_media.h | 22 + include/gpac/html5_mse.h | 17 + include/gpac/ietf.h | 21 +- include/gpac/internal/avilib.h | 114 +- include/gpac/internal/camera.h | 4 +- include/gpac/internal/compositor_dev.h | 66 +- include/gpac/internal/isomedia_dev.h | 2175 ++++----- include/gpac/internal/m3u8.h | 17 +- include/gpac/internal/media_dev.h | 85 +- include/gpac/internal/mesh.h | 16 +- include/gpac/internal/mpd.h | 90 +- include/gpac/internal/odf_parse_common.h | 2 +- include/gpac/internal/scenegraph_dev.h | 3 +- include/gpac/internal/terminal_dev.h | 62 +- include/gpac/ismacryp.h | 46 +- include/gpac/iso639.h | 16 + include/gpac/isomedia.h | 305 +- include/gpac/laser.h | 17 + include/gpac/list.h | 4 +- include/gpac/map.h | 6 +- include/gpac/maths.h | 33 +- include/gpac/media_tools.h | 1011 +++- include/gpac/mediaobject.h | 56 +- include/gpac/module.h | 8 +- include/gpac/modules/codec.h | 41 +- include/gpac/modules/ipmp.h | 4 + include/gpac/modules/raster2d.h | 7 +- include/gpac/modules/service.h | 71 +- include/gpac/mpeg4_odf.h | 723 ++- include/gpac/mpegts.h | 67 +- include/gpac/network.h | 31 +- include/gpac/nodes_mpeg4.h | 2 - include/gpac/options.h | 22 +- include/gpac/path2d.h | 8 +- include/gpac/rtp_streamer.h | 10 +- include/gpac/scene_engine.h | 16 + include/gpac/scene_manager.h | 24 +- include/gpac/scenegraph.h | 24 + include/gpac/scenegraph_svg.h | 16 + include/gpac/scenegraph_vrml.h | 20 +- include/gpac/setup.h | 35 +- include/gpac/svg_types.h | 16 +- include/gpac/sync_layer.h | 19 +- include/gpac/term_info.h | 18 + include/gpac/terminal.h | 36 +- include/gpac/thread.h | 8 +- include/gpac/token.h | 6 +- include/gpac/tools.h | 259 +- include/gpac/unicode.h | 11 +- include/gpac/user.h | 23 +- include/gpac/utf.h | 8 +- include/gpac/version.h | 18 +- include/gpac/webvtt.h | 17 + include/gpac/xml.h | 15 +- mkdmg.sh | 4 +- modules/Makefile | 29 +- modules/aac_in/Makefile | 4 +- modules/aac_in/aac_in.c | 28 +- modules/aac_in/faad_dec.c | 16 +- modules/ac3_in/Makefile | 2 +- modules/ac3_in/ac3_in.c | 75 +- modules/alsa/Makefile | 2 +- modules/amr_dec/Makefile | 20 +- modules/amr_dec/amr_dec.c | 10 +- modules/amr_dec/amr_in.c | 114 +- modules/amr_float_dec/Makefile | 4 +- modules/amr_float_dec/amr_float_dec.c | 16 +- modules/audio_filter/Makefile | 2 +- modules/audio_filter/audio_filter.c | 30 +- modules/avcap/Makefile | 2 +- modules/bifs_dec/Makefile | 4 +- modules/bifs_dec/bifs_dec.c | 6 +- modules/ctx_load/Makefile | 4 +- modules/ctx_load/ctx_load.c | 78 +- modules/dektec_out/Makefile | 4 +- modules/dektec_out/dektec_video.cpp | 514 +- modules/demo_is/Makefile | 2 +- modules/directfb_out/Makefile | 2 +- modules/directfb_out/directfb_wrapper.c | 8 +- modules/droid_audio/droidaudio.c | 37 +- modules/droid_cam/droid_cam.c | 159 +- modules/droid_mpegv/droid_mpegv.c | 5 +- modules/droid_out/droid_vout.c | 536 +- modules/dummy_in/Makefile | 4 +- modules/dummy_in/dummy_in.c | 64 +- modules/dx_hw/Makefile | 2 +- modules/dx_hw/copy_pixels.c | 196 +- modules/dx_hw/dx_2d.c | 66 +- modules/dx_hw/dx_audio.c | 28 +- modules/dx_hw/dx_hw.h | 8 +- modules/dx_hw/dx_video.c | 133 +- modules/dx_hw/dx_window.c | 121 +- modules/ffmpeg_in/Makefile | 27 +- modules/ffmpeg_in/ffmpeg_decode.c | 904 ++-- modules/ffmpeg_in/ffmpeg_demux.c | 141 +- modules/ffmpeg_in/ffmpeg_in.h | 58 +- modules/ffmpeg_in/ffmpeg_load.c | 5 +- modules/freenect/Makefile | 2 +- modules/ft_font/Makefile | 4 +- modules/ft_font/ft_font.c | 79 +- modules/gdip_raster/gdip_texture.cpp | 47 - modules/gpac_js/Makefile | 2 +- modules/gpac_js/gpac_js.c | 1430 ++++-- modules/hyb_in/Makefile | 4 +- modules/img_in/Makefile | 4 +- modules/img_in/bmp_dec.c | 2 +- modules/img_in/img_in.c | 57 +- modules/img_in/jp2_dec.c | 4 +- modules/img_in/jpeg_dec.c | 2 +- modules/img_in/png_dec.c | 4 +- modules/ismacryp/Makefile | 4 +- modules/ismacryp/isma_ea.c | 66 +- modules/isom_in/Makefile | 4 +- modules/isom_in/isom_cache.c | 23 +- modules/isom_in/isom_in.h | 5 +- modules/isom_in/load.c | 83 +- modules/isom_in/read.c | 95 +- modules/isom_in/read_ch.c | 225 +- modules/jack/Makefile | 2 +- modules/laser_dec/Makefile | 4 +- modules/laser_dec/laser_dec.c | 4 + modules/libplayer/Makefile | 2 +- modules/mediacodec_dec/Makefile | 58 + modules/mediacodec_dec/mediacodec_dec.c | 1104 +++++ modules/mediacodec_dec/mediacodec_dec.h | 35 + modules/mediacodec_dec/mediacodec_dec_jni.c | 204 + modules/mp3_in/Makefile | 4 +- modules/mp3_in/mad_dec.c | 19 +- modules/mp3_in/mp3_in.c | 78 +- modules/mpd_in/Makefile | 4 +- modules/mpd_in/mpd_in.c | 323 +- modules/mpegts_in/Makefile | 4 +- modules/mpegts_in/mpegts_in.c | 86 +- modules/mse_in/Makefile | 4 +- modules/mse_in/mse_in.c | 10 +- modules/odf_dec/Makefile | 4 +- modules/ogg/Makefile | 2 +- modules/ogg/ogg_in.c | 130 +- modules/ogg/ogg_load.c | 23 +- modules/opencv_is/Makefile | 2 +- modules/openhevc_dec/Makefile | 13 +- modules/openhevc_dec/openhevc_dec.c | 606 ++- modules/opensvc_dec/Makefile | 2 +- modules/opensvc_dec/opensvc_dec.c | 22 +- modules/osd/Makefile | 2 +- modules/osd/osd.c | 2 +- modules/oss_audio/Makefile | 4 +- modules/platinum/GPACFileMediaServer.h | 2 +- modules/platinum/GPACPlatinum.cpp | 2 +- modules/platinum/Makefile | 2 +- modules/pulseaudio/Makefile | 4 +- modules/raw_out/Makefile | 4 +- modules/raw_out/raw_video.c | 44 +- modules/redirect_av/Makefile | 2 +- modules/redirect_av/ffmpeg_ts_muxer.c | 28 +- modules/redirect_av/redirect_av.c | 72 +- modules/redirect_av/ts_muxer.h | 42 + modules/rtp_in/Makefile | 4 +- modules/rtp_in/rtp_in.c | 190 +- modules/rtp_in/rtp_in.h | 11 +- modules/rtp_in/rtp_session.c | 14 +- modules/rtp_in/rtp_signaling.c | 159 +- modules/rtp_in/rtp_stream.c | 105 +- modules/rtp_in/sdp_fetch.c | 3 +- modules/rtp_in/sdp_load.c | 75 +- modules/rvc_dec/Makefile | 2 +- modules/saf_in/Makefile | 4 +- modules/saf_in/saf_in.c | 68 +- modules/sdl_out/Makefile | 6 +- modules/sdl_out/audio.c | 8 +- modules/sdl_out/sdl_out.c | 4 +- modules/sdl_out/sdl_out.h | 23 +- modules/sdl_out/video.c | 851 ++-- modules/soft_raster/Makefile | 4 +- modules/soft_raster/ftgrays.c | 3 +- modules/soft_raster/rast_soft.h | 3 - modules/soft_raster/raster_argb.c | 18 +- modules/soft_raster/raster_load.c | 2 +- modules/soft_raster/stencil.c | 74 +- modules/soft_raster/surface.c | 26 +- modules/svg_in/Makefile | 4 +- modules/svg_in/svg_in.c | 25 +- modules/timedtext/Makefile | 4 +- modules/timedtext/timedtext_dec.c | 96 +- modules/timedtext/timedtext_in.c | 94 +- modules/ui_rec/Makefile | 2 +- modules/ui_rec/ui_rec.c | 26 +- modules/validator/Makefile | 4 +- modules/validator/validator.c | 350 +- modules/vtb_decode/Makefile | 43 + modules/vtb_decode/glcontext.m | 7 + modules/vtb_decode/vtb_decode.c | 1341 ++++++ modules/vtt_in/Makefile | 4 +- modules/vtt_in/vtt_dec.c | 112 +- modules/vtt_in/vtt_in.c | 75 +- modules/wav_out/Makefile | 2 +- modules/wav_out/wav_out.c | 30 +- modules/widgetman/Makefile | 2 +- modules/widgetman/unzip.c | 20 +- modules/widgetman/wgt_load.c | 24 +- modules/widgetman/widget.c | 20 +- modules/widgetman/widgetman.c | 307 +- modules/wiiis/Makefile | 2 +- modules/x11_out/Makefile | 4 +- modules/x11_out/x11_out.c | 63 +- modules/x11_out/x11_out.h | 2 + modules/xvid_dec/Makefile | 2 +- modules/xvid_dec/xvid_dec.c | 10 +- packagers/win32_64/nsis/gpac_installer.nsi | 9 +- .../bifs/bifs-3D-positioning-layer3D.bt | 186 - .../bifs/bifs-3D-shapes-box-transparent.bt | 118 - .../bifs/bifs-3D-viewpoint-ortho-bind.bt | 114 - .../bifs/bifs-linking-inline-rtsp-no-od.bt | 48 - .../bifs/bifs-linking-inline-rtsp.bt | 59 - regression_tests/bifs/bifs-script-proto.bt | 223 - ...s-timeline-mediacontrol-inline-segments.bt | 66 - .../bifs/bifs-timeline-mediacontrol-inline.bt | 231 - .../bifs/bifs-timeline-mediacontrol-rtsp.bt | 340 -- regression_tests/build-navigator-w32.bat | 14 - regression_tests/build-shell | 49 - regression_tests/build-w32.bat | 54 - regression_tests/utfscript.svg | 14 - regression_tests/xmlin4/first.xml | 3 - regression_tests/xmlin4/input.txt | 13 - regression_tests/xmlin4/last.xml | 3 - regression_tests/xmlin4/run_one_test.sh | 21 - regression_tests/xmlin4/run_tests.sh | 59 - regression_tests/xmlin4/second.xml | 3 - shaders/fragment.glsl | 386 ++ shaders/vertex.glsl | 196 + src/Makefile | 361 +- src/bifs/bifs_codec.c | 10 +- src/bifs/com_dec.c | 22 +- src/bifs/com_enc.c | 5 + src/bifs/field_decode.c | 23 +- src/bifs/field_encode.c | 4 +- src/bifs/memory_decoder.c | 5 +- src/bifs/script_dec.c | 26 +- src/bifs/unquantize.c | 75 +- src/compositor/audio_input.c | 9 +- src/compositor/audio_mixer.c | 106 +- src/compositor/audio_render.c | 160 +- src/compositor/bindable.c | 39 +- src/compositor/camera.c | 24 +- src/compositor/compositor.c | 487 +- src/compositor/compositor_2d.c | 171 +- src/compositor/compositor_3d.c | 20 +- src/compositor/compositor_node_init.c | 8 +- src/compositor/drawable.c | 38 +- src/compositor/drawable.h | 2 + src/compositor/events.c | 371 +- src/compositor/font_engine.c | 34 +- src/compositor/gl_inc.h | 64 +- src/compositor/hardcoded_protos.c | 537 ++- src/compositor/hc_flash_shape.c | 61 +- src/compositor/mesh.c | 91 +- src/compositor/mesh_collide.c | 86 +- src/compositor/mpeg4_animstream.c | 4 + src/compositor/mpeg4_audio.c | 16 +- src/compositor/mpeg4_background.c | 28 +- src/compositor/mpeg4_background2d.c | 36 +- src/compositor/mpeg4_bitmap.c | 33 +- src/compositor/mpeg4_composite.c | 674 +-- src/compositor/mpeg4_form.c | 32 +- src/compositor/mpeg4_geometry_2d.c | 4 + src/compositor/mpeg4_geometry_3d.c | 102 +- src/compositor/mpeg4_geometry_ils2d.c | 3 +- src/compositor/mpeg4_gradients.c | 88 +- src/compositor/mpeg4_grouping.c | 24 +- src/compositor/mpeg4_grouping_2d.c | 4 + src/compositor/mpeg4_layer_2d.c | 28 +- src/compositor/mpeg4_layer_3d.c | 148 +- src/compositor/mpeg4_layout.c | 13 +- src/compositor/mpeg4_sensors.c | 33 + src/compositor/mpeg4_sound.c | 8 + src/compositor/mpeg4_text.c | 47 +- src/compositor/mpeg4_textures.c | 27 +- src/compositor/mpeg4_timesensor.c | 4 + src/compositor/mpeg4_viewport.c | 26 +- src/compositor/navigate.c | 92 +- src/compositor/nodes_stacks.h | 3 +- src/compositor/offscreen_cache.c | 59 +- src/compositor/svg_base.c | 230 +- src/compositor/svg_filters.c | 8 +- src/compositor/svg_font.c | 18 +- src/compositor/svg_geometry.c | 1 - src/compositor/svg_grouping.c | 16 +- src/compositor/svg_media.c | 38 +- src/compositor/svg_paint_servers.c | 72 +- src/compositor/svg_text.c | 77 +- src/compositor/texturing.c | 35 +- src/compositor/texturing.h | 6 + src/compositor/texturing_gl.c | 651 ++- src/compositor/visual_manager.c | 4 + src/compositor/visual_manager.h | 77 +- src/compositor/visual_manager_2d.c | 98 +- src/compositor/visual_manager_2d.h | 7 +- src/compositor/visual_manager_2d_draw.c | 154 +- src/compositor/visual_manager_3d.c | 233 +- src/compositor/visual_manager_3d.h | 19 +- src/compositor/visual_manager_3d_gl.c | 2178 +++++++-- src/export.cpp | 143 +- src/ietf/rtcp.c | 8 +- src/ietf/rtp.c | 22 +- src/ietf/rtp_depacketizer.c | 53 +- src/ietf/rtp_packetizer.c | 72 +- src/ietf/rtp_pck_3gpp.c | 53 +- src/ietf/rtp_pck_mpeg12.c | 48 +- src/ietf/rtp_pck_mpeg4.c | 57 +- src/ietf/rtp_streamer.c | 82 +- src/ietf/rtsp_command.c | 3 +- src/ietf/rtsp_common.c | 17 +- src/ietf/rtsp_response.c | 23 +- src/ietf/rtsp_session.c | 59 +- src/ietf/sdp.c | 63 +- src/isomedia/avc_ext.c | 1146 ++++- src/isomedia/box_code_3gpp.c | 294 +- src/isomedia/box_code_adobe.c | 40 +- src/isomedia/box_code_apple.c | 59 +- src/isomedia/box_code_base.c | 4291 ++++++++++++----- src/isomedia/box_code_drm.c | 447 +- src/isomedia/box_code_meta.c | 481 +- src/isomedia/box_dump.c | 4066 +++++++++------- src/isomedia/box_funcs.c | 3787 +++++---------- src/isomedia/data_map.c | 28 +- src/isomedia/drm_sample.c | 504 +- src/isomedia/hint_track.c | 87 +- src/isomedia/hinting.c | 313 +- src/isomedia/iff.c | 939 ++++ src/isomedia/isom_intern.c | 210 +- src/isomedia/isom_read.c | 954 ++-- src/isomedia/isom_store.c | 115 +- src/isomedia/isom_write.c | 1151 +++-- src/isomedia/media.c | 114 +- src/isomedia/media_odf.c | 3 +- src/isomedia/meta.c | 417 +- src/isomedia/movie_fragments.c | 323 +- src/isomedia/sample_descs.c | 192 +- src/isomedia/stbl_read.c | 17 +- src/isomedia/stbl_write.c | 120 +- src/isomedia/track.c | 202 +- src/isomedia/tx3g.c | 2 +- src/laser/lsr_dec.c | 246 +- src/laser/lsr_enc.c | 17 +- src/laser/lsr_tables.c | 4 + src/mcrypt/ctr.c | 2 +- src/mcrypt/g_crypt.c | 12 +- src/media_tools/av_parsers.c | 1382 ++++-- src/media_tools/avilib.c | 109 +- src/media_tools/dash_client.c | 4121 +++++++++++----- src/media_tools/dash_segmenter.c | 2987 ++++++++---- src/media_tools/filestreamer.c | 71 +- src/media_tools/html5_media.c | 4 + src/media_tools/html5_mse.c | 10 +- src/media_tools/img.c | 119 +- src/media_tools/ismacryp.c | 488 +- src/media_tools/isom_hinter.c | 32 +- src/media_tools/isom_tools.c | 1022 ++-- src/media_tools/m2ts_mux.c | 506 +- src/media_tools/m3u8.c | 334 +- src/media_tools/media_export.c | 315 +- src/media_tools/media_import.c | 1569 ++++-- src/media_tools/mpd.c | 1937 ++++++-- src/media_tools/mpeg2_ps.c | 13 +- src/media_tools/mpegts.c | 321 +- src/media_tools/saf.c | 3 + src/media_tools/text_import.c | 320 +- src/media_tools/webvtt.c | 382 +- src/odf/descriptors.c | 199 +- src/odf/ipmpx_code.c | 58 +- src/odf/ipmpx_dump.c | 88 +- src/odf/ipmpx_parse.c | 7 +- src/odf/odf_code.c | 79 +- src/odf/odf_codec.c | 43 +- src/odf/odf_command.c | 8 +- src/odf/odf_dump.c | 275 +- src/odf/odf_parse.c | 24 +- src/odf/qos.c | 9 + src/odf/slc.c | 4 +- src/scene_manager/encode_isom.c | 57 +- src/scene_manager/loader_bt.c | 18 +- src/scene_manager/loader_isom.c | 29 +- src/scene_manager/loader_qt.c | 2 +- src/scene_manager/loader_svg.c | 121 +- src/scene_manager/loader_xmt.c | 96 +- src/scene_manager/scene_dump.c | 108 +- src/scene_manager/scene_engine.c | 9 +- src/scene_manager/scene_manager.c | 12 +- src/scene_manager/scene_stats.c | 20 +- src/scene_manager/swf_parse.c | 43 +- src/scene_manager/text_to_bifs.c | 28 +- src/scenegraph/base_scenegraph.c | 31 +- src/scenegraph/commands.c | 5 +- src/scenegraph/dom_events.c | 22 +- src/scenegraph/dom_smjs.c | 49 +- src/scenegraph/html5_media_smjs.c | 2 - src/scenegraph/html5_mse_smjs.c | 6 +- src/scenegraph/mpeg4_animators.c | 14 +- src/scenegraph/mpeg4_nodes.c | 1 + src/scenegraph/smil_anim.c | 17 +- src/scenegraph/smil_timing.c | 25 +- src/scenegraph/svg_attributes.c | 48 +- src/scenegraph/svg_properties.c | 177 +- src/scenegraph/svg_smjs.c | 31 +- src/scenegraph/svg_types.c | 20 +- src/scenegraph/vrml_proto.c | 66 +- src/scenegraph/vrml_route.c | 20 +- src/scenegraph/vrml_script.c | 8 + src/scenegraph/vrml_smjs.c | 45 +- src/scenegraph/vrml_tools.c | 10 +- src/scenegraph/x3d_nodes.c | 2 +- src/scenegraph/xbl_process.c | 4 + src/scenegraph/xml_ns.c | 7 +- src/terminal/channel.c | 162 +- src/terminal/clock.c | 9 +- src/terminal/decoder.c | 452 +- src/terminal/input_sensor.c | 8 + src/terminal/media_control.c | 27 +- src/terminal/media_control.h | 2 +- src/terminal/media_manager.c | 57 +- src/terminal/media_memory.c | 131 +- src/terminal/media_memory.h | 2 + src/terminal/media_object.c | 287 +- src/terminal/media_sensor.c | 6 +- src/terminal/mpeg4_inline.c | 26 +- src/terminal/network_service.c | 95 +- src/terminal/object_browser.c | 9 +- src/terminal/object_manager.c | 177 +- src/terminal/scene.c | 511 +- src/terminal/svg_external.c | 1 + src/terminal/terminal.c | 154 +- src/utils/alloc.c | 281 +- src/utils/base_encoding.c | 8 +- src/utils/bitstream.c | 32 +- src/utils/cache.c | 144 +- src/utils/color.c | 1240 ++++- src/utils/configfile.c | 22 +- src/utils/downloader.c | 636 ++- src/utils/error.c | 132 +- src/utils/list.c | 2 +- src/utils/math.c | 127 +- src/utils/module.c | 41 +- src/utils/os_config_init.c | 225 +- src/utils/os_divers.c | 151 +- src/utils/os_file.c | 204 +- src/utils/os_module.c | 31 +- src/utils/os_net.c | 80 +- src/utils/os_thread.c | 25 +- src/utils/path2d.c | 35 +- src/utils/path2d_stroker.c | 84 +- src/utils/ringbuffer.c | 6 +- src/utils/sha1.c | 8 +- src/utils/uni_bidi.c | 26 +- src/utils/url.c | 210 +- src/utils/xml_parser.c | 125 +- static.mak | 362 ++ tests/README.MD | 300 ++ tests/ghp_deploy.sh | 43 + tests/index.html | 21 + tests/make_tests.sh | 1570 ++++++ .../media}/auxiliary_files/count_arabic.mp3 | Bin .../media}/auxiliary_files/count_english.mp3 | Bin .../media}/auxiliary_files/count_french.mp3 | Bin .../media}/auxiliary_files/count_german.mp3 | Bin .../media}/auxiliary_files/count_italian.mp3 | Bin .../media}/auxiliary_files/count_spanish.mp3 | Bin .../media}/auxiliary_files/count_video.cmp | Bin tests/media/auxiliary_files/counter.hvc | Bin 0 -> 696407 bytes .../media}/auxiliary_files/enst_audio.aac | Bin .../media}/auxiliary_files/enst_video.h264 | Bin .../media}/auxiliary_files/index2batch.xslt | 0 .../media}/auxiliary_files/index2html.xslt | 0 .../media}/auxiliary_files/index2sh.xslt | 0 .../media}/auxiliary_files/logo.bt | 0 .../media}/auxiliary_files/logo.jpg | Bin .../media}/auxiliary_files/logo.png | Bin .../media}/auxiliary_files/nefertiti.wrl | 0 .../media}/auxiliary_files/sky.jpg | Bin tests/media/auxiliary_files/subs.ismt | Bin 0 -> 5033 bytes .../media}/auxiliary_files/subtitle.srt | 0 .../media}/auxiliary_files/subtitle_fr.srt | 0 .../media}/auxiliary_files/svg2html.xslt | 0 .../media}/auxiliary_files/x3d2html.xslt | 0 .../media}/auxiliary_files/xmt2html.xslt | 0 .../bifs-2D-background-background2D-bind.bt | 0 .../bifs-2D-background-background2D-image.bt | 0 ...bifs-2D-background-background2D-layer2D.bt | 0 .../bifs-2D-background-background2D-movie.bt | 0 ...s-2D-background-background2D-url-change.bt | 0 .../bifs/bifs-2D-interactivity-discsensor.bt | 0 .../bifs/bifs-2D-interactivity-htk-sensor.bt | 0 .../bifs/bifs-2D-interactivity-keysensor.bt | 0 .../bifs/bifs-2D-interactivity-mousesensor.bt | 0 .../bifs-2D-interactivity-nested-sensors.bt | 0 .../bifs-2D-interactivity-planesensor2D.bt | 0 ...bifs-2D-interactivity-proximitysensor2D.bt | 0 .../bifs-2D-interactivity-stringsensor.bt | 0 ...fs-2D-interactivity-touchsensor-4states.bt | 0 ...s-2D-interactivity-touchsensor-hitpoint.bt | 0 ...ivity-touchsensor-isactive-exposedfield.bt | 0 ...s-2D-interactivity-touchsensor-isactive.bt | 0 ...ifs-2D-interactivity-touchsensor-isover.bt | 0 ...-2D-interactivity-touchsensor-move_over.bt | 0 .../bifs-2D-painting-colortransform-alpha.bt | 0 .../bifs-2D-painting-colortransform-bitmap.bt | 0 .../bifs-2D-painting-colortransform-color.bt | 0 ...bifs-2D-painting-colortransform-texture.bt | 109 + .../bifs/bifs-2D-painting-lineproperties.bt | 0 .../bifs/bifs-2D-painting-material2D.bt | 0 .../bifs-2D-painting-xlineproperties-cap.bt | 0 ...ting-xlineproperties-compositetexture2D.bt | 0 .../bifs-2D-painting-xlineproperties-dash.bt | 0 ...D-painting-xlineproperties-imagetexture.bt | 0 .../bifs-2D-painting-xlineproperties-join.bt | 0 ...painting-xlineproperties-lineargradient.bt | 0 ...painting-xlineproperties-radialgradient.bt | 0 ...fs-2D-painting-xlineproperties-scalable.bt | 0 ...2D-painting-xlineproperties-transparent.bt | 0 .../bifs/bifs-2D-positioning-clipper2D.bt | 0 .../bifs-2D-positioning-form-align-center.bt | 0 .../bifs-2D-positioning-form-align-horiz.bt | 0 .../bifs-2D-positioning-form-align-vert.bt | 0 .../bifs-2D-positioning-form-spread-horiz.bt | 0 .../bifs-2D-positioning-form-spread-vert.bt | 0 .../bifs/bifs-2D-positioning-layer2D.bt | 0 .../bifs-2D-positioning-layer2d-in-layer2d.bt | 0 ...-2D-positioning-layout-horiz-ltr-nowrap.bt | 0 ...D-positioning-layout-horiz-ltr-wrap-btt.bt | 0 ...D-positioning-layout-horiz-ltr-wrap-ttb.bt | 0 ...-2D-positioning-layout-horiz-rtl-nowrap.bt | 0 ...D-positioning-layout-horiz-rtl-wrap-btt.bt | 0 ...D-positioning-layout-horiz-rtl-wrap-ttb.bt | 0 .../bifs-2D-positioning-layout-horiz-text.bt | 0 ...bifs-2D-positioning-layout-scroll-child.bt | 0 .../bifs-2D-positioning-layout-scroll-full.bt | 0 ...D-positioning-layout-scroll-modes-horiz.bt | 0 ...2D-positioning-layout-scroll-modes-vert.bt | 0 ...ifs-2D-positioning-layout-scroll-on-off.bt | 0 ...s-2D-positioning-layout-vert-btt-nowrap.bt | 0 ...2D-positioning-layout-vert-btt-wrap-ltr.bt | 0 ...2D-positioning-layout-vert-btt-wrap-rtl.bt | 0 ...s-2D-positioning-layout-vert-ttb-nowrap.bt | 0 ...2D-positioning-layout-vert-ttb-wrap-ltr.bt | 0 ...2D-positioning-layout-vert-ttb-wrap-rtl.bt | 0 .../bifs/bifs-2D-positioning-orderedgroup.bt | 0 ...bifs-2D-positioning-pathlayout-graphics.bt | 0 .../bifs/bifs-2D-positioning-pathlayout.bt | 0 .../bifs/bifs-2D-positioning-transform2D.bt | 0 .../bifs-2D-positioning-transformmatrix2D.bt | 0 .../media}/bifs/bifs-2D-shapes-all.bt | 0 .../bifs/bifs-2D-shapes-indexfaceset2D.bt | 0 .../bifs/bifs-2D-shapes-indexlineset2D.bt | 0 .../media}/bifs/bifs-2D-shapes-pointset2D.bt | 0 .../media}/bifs/bifs-2D-shapes-xcurve2D.bt | 0 ...texturing-compositetexture2D-background.bt | 0 ...-2D-texturing-compositetexture2D-bitmap.bt | 0 ...exturing-compositetexture2D-transparent.bt | 0 .../bifs/bifs-2D-texturing-gradients-text.bt | 0 ...bifs-2D-texturing-gradients-transparent.bt | 0 .../bifs-2D-texturing-imagetexture-shapes.bt | 0 ...bifs-2D-texturing-lineargradient-simple.bt | 0 ...bifs-2D-texturing-lineargradient-spread.bt | 0 .../bifs-2D-texturing-movietexture-shapes.bt | 0 .../bifs/bifs-2D-texturing-pixeltexture.bt | 0 ...bifs-2D-texturing-radialgradient-simple.bt | 0 ...bifs-2D-texturing-radialgradient-spread.bt | 0 ...bifs-2D-texturing-texturetransform-base.bt | 0 ...-2D-texturing-texturetransform-interact.bt | 0 ...ring-texturetransform-transformmatrix2D.bt | 0 .../media}/bifs/bifs-2D-viewport-complete.bt | 0 .../media}/bifs/bifs-2D-viewport-simple.bt | 0 .../media}/bifs/bifs-3D-background-images.bt | 0 .../media}/bifs/bifs-3D-background.bt | 0 .../bifs-3D-interactivity-collision-proxy.bt | 0 .../bifs/bifs-3D-interactivity-collision.bt | 0 .../bifs-3D-interactivity-cylindersensor.bt | 0 .../bifs/bifs-3D-interactivity-planesensor.bt | 0 .../bifs-3D-interactivity-proximitysensor.bt | 0 .../bifs-3D-interactivity-spheresensor.bt | 0 .../bifs-3D-interactivity-visibilitysensor.bt | 0 .../bifs/bifs-3D-lighting-directionalLight.bt | 0 .../media}/bifs/bifs-3D-lighting-fog.bt | 0 .../bifs/bifs-3D-lighting-pointlight.bt | 0 .../media}/bifs/bifs-3D-lighting-spotlight.bt | 0 ...-positioning-billboard-viewer-alignment.bt | 0 .../bifs/bifs-3D-positioning-billboard.bt | 0 .../bifs/bifs-3D-positioning-gravity.bt | 0 .../bifs/bifs-3D-positioning-layer3D-views.bt | 0 .../media/bifs/bifs-3D-positioning-layer3D.bt | 193 + .../media}/bifs/bifs-3D-positioning-lod.bt | 0 .../bifs/bifs-3D-positioning-transform.bt | 0 .../bifs/bifs-3D-shapes-box-transparent.bt | 117 + .../media}/bifs/bifs-3D-shapes-box.bt | 0 .../media}/bifs/bifs-3D-shapes-cone.bt | 0 .../media}/bifs/bifs-3D-shapes-cylinder.bt | 0 .../bifs/bifs-3D-shapes-elevationgrid.bt | 0 .../media}/bifs/bifs-3D-shapes-extrusion.bt | 0 .../bifs/bifs-3D-shapes-indexedfaceset.bt | 0 .../bifs/bifs-3D-shapes-indexedlineset.bt | 0 .../bifs/bifs-3D-shapes-nonlineardeformer.bt | 0 .../media}/bifs/bifs-3D-shapes-pointset.bt | 0 .../bifs/bifs-3D-texturing-box-transparent.bt | 0 .../bifs/bifs-3D-texturing-box-video.bt | 0 .../media}/bifs/bifs-3D-texturing-box.bt | 0 ...-3D-texturing-compositetexture3D-bitmap.bt | 0 ...ifs-3D-texturing-compositetexture3D-box.bt | 0 .../bifs-3D-texturing-cone-transparent.bt | 0 .../media}/bifs/bifs-3D-texturing-cone.bt | 0 .../bifs-3D-texturing-cylinder-transparent.bt | 0 .../media}/bifs/bifs-3D-texturing-cylinder.bt | 0 .../bifs/bifs-3D-texturing-transform-box.bt | 0 .../bifs-3D-texturing-transform-matrix-box.bt | 0 .../media}/bifs/bifs-3D-viewpoint-anim.bt | 0 .../bifs/bifs-3D-viewpoint-bind-jump.bt | 0 .../media}/bifs/bifs-3D-viewpoint-bind.bt | 0 .../bifs/bifs-3D-viewpoint-ortho-bind.bt | 118 + .../bifs/bifs-bitmap-image-meter-metrics.bt | 0 .../bifs/bifs-bitmap-image-pixel-metrics.bt | 0 .../media}/bifs/bifs-bitmap-image-resizing.bt | 0 .../bifs/bifs-bitmap-movie-materialkey.bt | 0 .../media}/bifs/bifs-bitmap-movie.bt | 0 .../media}/bifs/bifs-bitmap-video-resizing.bt | 0 .../media}/bifs/bifs-cachetexture_cache.bt | 0 .../media}/bifs/bifs-cachetexture_nocache.bt | 0 .../bifs/bifs-command-animated-osmo4logo.bt | 0 .../media}/bifs/bifs-command-delete-index.bt | 0 .../media}/bifs/bifs-command-delete-node.bt | 0 .../media}/bifs/bifs-command-delete-route.bt | 0 .../media}/bifs/bifs-command-global-qp.bt | 0 .../media}/bifs/bifs-command-insert-index.bt | 0 .../media}/bifs/bifs-command-insert-node.bt | 0 .../bifs/bifs-command-insert-nodedef.bt | 0 .../media}/bifs/bifs-command-insert-route.bt | 0 .../bifs-command-multiple-replace-field.bt | 0 .../bifs-command-multiple-replace-index.bt | 0 .../bifs/bifs-command-node-delete-ex.bt | 0 .../media}/bifs/bifs-command-proto-delete.bt | 0 .../media}/bifs/bifs-command-proto-insert.bt | 0 .../bifs/bifs-command-protolist-delete.bt | 0 .../bifs/bifs-command-quantification.bt | 0 .../media}/bifs/bifs-command-replace-field.bt | 0 .../media}/bifs/bifs-command-replace-index.bt | 0 .../bifs/bifs-command-replace-node-null.bt | 0 .../media}/bifs/bifs-command-replace-node.bt | 0 .../media}/bifs/bifs-command-replace-route.bt | 0 .../bifs/bifs-command-replace-scene-null.bt | 0 .../media}/bifs/bifs-command-replace-scene.bt | 0 .../bifs/bifs-command-route-add-children.bt | 0 .../bifs/bifs-command-route-children.bt | 0 .../bifs-command-route-node-exposedfield.bt | 0 .../media}/bifs/bifs-command-route-node.bt | 0 .../bifs-command-route-remove-children.bt | 0 .../media}/bifs/bifs-environmenttest.bt | 0 .../bifs/bifs-externproto-forestgump-lib.bt | 0 .../bifs/bifs-externproto-forestgump.bt | 0 .../media}/bifs/bifs-externproto-mfurl-lib.bt | 0 .../media}/bifs/bifs-externproto-mfurl.bt | 0 .../media}/bifs/bifs-externproto-nood-lib.bt | 0 .../media}/bifs/bifs-externproto-nood.bt | 0 .../bifs/bifs-externproto-simple-lib.bt | 0 .../media}/bifs/bifs-externproto-simple.bt | 0 .../media}/bifs/bifs-game-arrange.bt | 0 .../media}/bifs/bifs-game-breakout.bt | 0 .../media}/bifs/bifs-game-bubble.bt | 0 .../media}/bifs/bifs-game-minesweeper.bt | 0 .../media}/bifs/bifs-game-othello.bt | 0 .../bifs-interpolation-colorinterpolator.bt | 0 ...-interpolation-coordinateinterpolator2D.bt | 0 .../bifs-interpolation-positionanimator.bt | 0 .../bifs-interpolation-positionanimator2D.bt | 0 ...rpolation-positioninterpolator-position.bt | 0 ...interpolation-positioninterpolator-size.bt | 0 ...olation-positioninterpolator2D-position.bt | 0 ...terpolation-positioninterpolator2D-size.bt | 0 .../bifs/bifs-interpolation-scalaranimator.bt | 0 .../bifs-interpolation-scalarinterpolator.bt | 0 .../bifs-interpolation-timesensor-enabled.bt | 0 ...polation-timesensor-starttime_norestart.bt | 0 ...erpolation-timesensor-starttime_restart.bt | 0 .../bifs-interpolation-valuator-sftime.bt | 0 .../media}/bifs/bifs-keynavigator.bt | 0 .../bifs/bifs-linking-anchor-mp4-next.bt | 0 .../bifs/bifs-linking-anchor-mp4-prev.bt | 0 .../bifs/bifs-linking-anchor-viewpoint.bt | 0 .../media}/bifs/bifs-linking-anchor-www.bt | 0 .../bifs/bifs-linking-animationstream.bt | 0 .../bifs/bifs-linking-inline-direct-inline.bt | 0 .../media}/bifs/bifs-linking-inline-direct.bt | 0 .../bifs/bifs-linking-inline-http-no-od.bt | 48 + tests/media/bifs/bifs-linking-inline-http.bt | 58 + .../bifs/bifs-linking-inline-od-inline.bt | 0 .../media}/bifs/bifs-linking-inline-od.bt | 0 .../bifs-linking-inline-segment-inline.bt | 0 .../bifs/bifs-linking-inline-segment.bt | 0 .../media}/bifs/bifs-media-audiobuffer.bt | 0 .../bifs/bifs-media-audioclip-urlchanged.bt | 0 .../media}/bifs/bifs-media-audioclip.bt | 0 .../bifs/bifs-media-audiosource-mixing.bt | 0 .../bifs/bifs-media-audiosource-urlchanged.bt | 0 .../media}/bifs/bifs-media-audiosource.bt | 0 .../bifs/bifs-media-imagetexture-OD-reuse.bt | 0 .../bifs/bifs-media-imagetexture-no-od.bt | 0 .../bifs-media-imagetexture-object-scale.bt | 0 .../bifs-media-imagetexture-transparent.bt | 0 .../bifs-media-imagetexture-url-change.bt | 0 .../bifs/bifs-media-movietexture-control.bt | 0 .../bifs/bifs-media-movietexture-no-od.bt | 0 .../bifs-media-movietexture-od-joinsession.bt | 0 ...ifs-media-movietexture-od-leave-session.bt | 0 .../bifs/bifs-media-movietexture-owns-OCR.bt | 0 .../bifs-media-movietexture-shares-OCR.bt | 0 .../bifs-media-movietexture-url-change.bt | 0 .../bifs/bifs-media-sound-spatialize.bt | 0 .../media}/bifs/bifs-media-sound.bt | 0 .../media}/bifs/bifs-misc-UTF16-input.bt | 0 .../media}/bifs/bifs-misc-cyclic-graph.bt | 0 .../media}/bifs/bifs-misc-hc-proto-events.bt | 0 .../bifs/bifs-misc-hc-proto-offscreengroup.bt | 139 + .../bifs/bifs-misc-hc-proto-pathextrusion.bt | 0 .../bifs-misc-hc-proto-planarextrusion.bt | 0 .../bifs-misc-hc-proto-planeclipper-box.bt | 77 + .../bifs/bifs-misc-hc-proto-planeclipper.bt | 0 .../media/bifs/bifs-misc-hc-proto-texture.bt | 63 + ...ifs-misc-non-linear-parsing-conditional.bt | 0 .../bifs/bifs-misc-non-linear-parsing-use.bt | 0 ...-misc-srt-import-3gpp-control-share-ocr.bt | 0 .../bifs/bifs-misc-srt-import-3gpp-control.bt | 0 .../media}/bifs/bifs-misc-srt-import-3gpp.bt | 0 .../media}/bifs/bifs-misc-srt-import.bt | 0 tests/media/bifs/bifs-od-language-code.bt | 117 + .../media}/bifs/bifs-od-remove-esd.bt | 0 .../media}/bifs/bifs-od-remove-od.bt | 0 .../media}/bifs/bifs-od-update-od.bt | 0 .../media}/bifs/bifs-proto-conditional.bt | 0 .../media}/bifs/bifs-proto-delete-def.bt | 0 .../media}/bifs/bifs-proto-delete-index.bt | 0 .../media}/bifs/bifs-proto-forestgump.bt | 0 .../media}/bifs/bifs-proto-mfurl.bt | 0 .../media}/bifs/bifs-proto-multiple.bt | 0 .../media}/bifs/bifs-proto-nested.bt | 0 .../media}/bifs/bifs-proto-route.bt | 0 .../bifs/bifs-proto-sftime-protocode.bt | 0 .../bifs/bifs-proto-sftime-protointerface.bt | 0 .../media}/bifs/bifs-proto-simple.bt | 0 .../media}/bifs/bifs-proto-use.bt | 0 .../media}/bifs/bifs-script-char-to-int.bt | 0 .../media}/bifs/bifs-script-child-create.bt | 0 .../media}/bifs/bifs-script-date.bt | 0 .../media}/bifs/bifs-script-event-out.bt | 0 .../media}/bifs/bifs-script-initialize.bt | 0 .../media}/bifs/bifs-script-load-url.bt | 0 .../media}/bifs/bifs-script-node-access.bt | 0 .../media}/bifs/bifs-script-node-create.bt | 0 tests/media/bifs/bifs-script-proto.bt | 224 + .../media}/bifs/bifs-script-timestamp.bt | 0 .../media}/bifs/bifs-storage.bt | 0 .../media}/bifs/bifs-stream-text-switch.bt | 0 .../media}/bifs/bifs-text-align-horiz1.bt | 0 .../media}/bifs/bifs-text-align-horiz2.bt | 0 .../media}/bifs/bifs-text-align-horiz3.bt | 0 .../media}/bifs/bifs-text-align-horiz4.bt | 0 .../media}/bifs/bifs-text-align-vert1.bt | 0 .../media}/bifs/bifs-text-align-vert2.bt | 0 .../media}/bifs/bifs-text-align-vert3.bt | 0 .../media}/bifs/bifs-text-align-vert4.bt | 0 .../media}/bifs/bifs-text-glyph-advance.bt | 0 .../media}/bifs/bifs-text-length.bt | 0 .../media}/bifs/bifs-text-maxextend.bt | 0 .../media}/bifs/bifs-text-style.bt | 0 .../media}/bifs/bifs-text-unicode.bt | 0 .../media}/bifs/bifs-text-vrml-alignment.bt | 0 .../bifs/bifs-timeline-mediacontrol-OCR.bt | 0 .../bifs-timeline-mediacontrol-audio-speed.bt | 0 .../bifs/bifs-timeline-mediacontrol-audio.bt | 0 .../bifs-timeline-mediacontrol-complete.bt | 0 ...bifs-timeline-mediacontrol-deactivation.bt | 0 .../bifs/bifs-timeline-mediacontrol-http.bt | 340 ++ ...-timeline-mediacontrol-inline-av-inline.bt | 0 .../bifs-timeline-mediacontrol-inline-av.bt | 231 + ...ine-mediacontrol-inline-segments-inline.bt | 0 ...s-timeline-mediacontrol-inline-segments.bt | 66 + .../bifs-timeline-mediacontrol-segments.bt | 0 .../bifs/bifs-timeline-mediacontrol-video.bt | 0 .../bifs-timeline-mediacontrol-videospeed.bt | 0 ...ifs-timeline-mediasensor-segment-switch.bt | 0 .../bifs/bifs-timeline-mediasensor-segment.bt | 0 .../media}/bifs/bifs-timeline-mediasensor.bt | 0 tests/media/bifs/counter-auto.bt | 177 + .../mozilla_ie_action.html | 0 .../mozilla_ie_simple.html | 0 .../media/browser_integration/ppc_action.html | 0 .../media/browser_integration/ppc_simple.html | 0 .../media}/build-navigator-sh | 0 tests/media/build-navigator-w32.bat | 14 + tests/media/chaptering/chapters.txt | 8 + .../media}/dom/gpac-dom-portability.js | 0 .../media}/dom/gpac-html-portability.js | 0 tests/media/encryption/drm_adobe.xml | 9 + tests/media/encryption/drm_cbc.xml | 28 + tests/media/encryption/drm_cbcs.xml | 28 + tests/media/encryption/drm_cens.xml | 25 + tests/media/encryption/drm_ctr.xml | 34 + tests/media/encryption/drm_isma.xml | 4 + .../media}/html5_video/basic_arraybuffer.js | 0 .../media}/html5_video/basic_audio.svg | 0 .../media}/html5_video/basic_mediasource.js | 0 .../media}/html5_video/basic_sourcebuffer.js | 0 .../media}/html5_video/basic_url.js | 0 .../media}/html5_video/basic_video.js | 0 .../media}/html5_video/basic_video.svg | 0 .../media}/html5_video/bind.js | 0 .../counter-mp4-audio-segments-http.js | 0 .../counter-mp4-av-segments-http.js | 0 .../counter-mp4-video-segments-http.js | 0 ...unter-mp4-video-segments-live-nobs-http.js | 0 .../counter-mp4-video-segments-local.js | 0 .../media}/html5_video/file.json | 0 .../media}/html5_video/file.txt | 0 .../media}/html5_video/file.xml | 0 .../media}/html5_video/gpac-mse-spatial.js | 0 .../media}/html5_video/gpac-mse.js | 0 .../html5_video/implementation_notes.txt | 0 .../media}/html5_video/mediaevents.js | 0 .../media}/html5_video/mediaevents.svg | 0 .../media}/html5_video/mse-overlap.js | 0 .../media}/html5_video/mse.svg | 0 .../media}/html5_video/myanmar-tiles.js | 0 .../media}/html5_video/nodejs-byte-server.js | 0 .../redbull-mp4-audio-segments-http.js | 0 .../redbull-mp4-video-segments-http.js | 0 .../media}/html5_video/spatial-mse.svg | 0 .../media}/html5_video/two-videos.svg | 0 .../media}/html5_video/video.svg | 0 .../media}/html5_video/xhr.js | 0 .../media}/html5_video/xhr.svg | 0 {regression_tests => tests/media}/index.css | 0 {regression_tests => tests/media}/index.xml | 0 tests/media/laser/enst_2laser3.xml | 90 + tests/media/laser/enst_3laser.xml | 53 + tests/media/laser/enst_afrique.xml | 70 + tests/media/laser/enst_amerique_centrale.xml | 23 + tests/media/laser/enst_amerique_sud.xml | 30 + tests/media/laser/enst_canvas.xml | 193 + tests/media/laser/enst_cee.xml | 103 + tests/media/laser/enst_europe.xml | 114 + tests/media/laser/enst_flow.xml | 1161 +++++ tests/media/laser/enst_gold.xml | 637 +++ tests/media/laser/enst_hame.xml | 1505 ++++++ tests/media/laser/enst_sydn.xml | 292 ++ tests/media/laser/enst_topk.xml | 1240 +++++ tests/media/laser/enst_tram.xml | 784 +++ tests/media/laser/stz_Navigation_simple.xml | 27 + tests/media/laser/stz_a_parsing.xml | 41 + tests/media/laser/stz_a_parsing2.xml | 21 + tests/media/laser/stz_animateMotion_mpath.xml | 32 + .../media/laser/stz_animateMotion_parsing.xml | 92 + .../laser/stz_animateMotion_parsing2.xml | 22 + .../laser/stz_animateTransform_rotate.xml | 37 + .../laser/stz_animateTransform_rotate2.xml | 21 + .../laser/stz_animateTransform_scale.xml | 28 + .../laser/stz_animateTransform_scale2.xml | 17 + .../media/laser/stz_animateTransform_skew.xml | 35 + .../laser/stz_animateTransform_skew2.xml | 22 + .../laser/stz_animateTransform_translate.xml | 35 + .../laser/stz_animateTransform_translate2.xml | 19 + tests/media/laser/stz_animate_choice.xml | 28 + tests/media/laser/stz_animate_choice2.xml | 21 + .../laser/stz_animate_colorrendering.xml | 23 + .../laser/stz_animate_colorrendering2.xml | 16 + .../media/laser/stz_animate_display-align.xml | 22 + .../laser/stz_animate_display-align2.xml | 15 + tests/media/laser/stz_animate_display.xml | 23 + tests/media/laser/stz_animate_display2.xml | 16 + tests/media/laser/stz_animate_editable.xml | 22 + tests/media/laser/stz_animate_editable2.xml | 15 + tests/media/laser/stz_animate_fill-rule.xml | 25 + tests/media/laser/stz_animate_fill-rule2.xml | 19 + tests/media/laser/stz_animate_fill.xml | 23 + tests/media/laser/stz_animate_fill2.xml | 16 + .../laser/stz_animate_fillstroke-opacity.xml | 26 + .../laser/stz_animate_fillstroke-opacity2.xml | 17 + tests/media/laser/stz_animate_font-family.xml | 22 + .../media/laser/stz_animate_font-family2.xml | 15 + tests/media/laser/stz_animate_font-style.xml | 22 + tests/media/laser/stz_animate_font-style2.xml | 15 + tests/media/laser/stz_animate_font-weight.xml | 22 + .../media/laser/stz_animate_font-weight2.xml | 15 + .../media/laser/stz_animate_gradientUnits.xml | 29 + .../laser/stz_animate_gradientUnits2.xml | 20 + tests/media/laser/stz_animate_gsize.xml | 28 + tests/media/laser/stz_animate_gsize2.xml | 21 + tests/media/laser/stz_animate_hrefa.xml | 30 + tests/media/laser/stz_animate_hrefa2.xml | 20 + .../media/laser/stz_animate_hrefstreamid.xml | 757 +++ .../media/laser/stz_animate_hrefstreamid2.xml | 746 +++ tests/media/laser/stz_animate_hrefuse.xml | 31 + tests/media/laser/stz_animate_hrefuse2.xml | 21 + .../laser/stz_animate_image-rendering.xml | 21 + .../laser/stz_animate_image-rendering2.xml | 14 + tests/media/laser/stz_animate_paintserver.xml | 31 + .../media/laser/stz_animate_paintserver2.xml | 23 + tests/media/laser/stz_animate_parsing.xml | 45 + tests/media/laser/stz_animate_parsing2.xml | 20 + tests/media/laser/stz_animate_path.xml | 25 + tests/media/laser/stz_animate_path2.xml | 18 + .../laser/stz_animate_pointer-events.xml | 23 + .../laser/stz_animate_pointer-events2.xml | 16 + tests/media/laser/stz_animate_points.xml | 24 + tests/media/laser/stz_animate_points2.xml | 16 + .../laser/stz_animate_preserveAspectRatio.xml | 29 + .../stz_animate_preserveAspectRatio2.xml | 319 ++ .../laser/stz_animate_shaperendering.xml | 23 + .../laser/stz_animate_shaperendering2.xml | 16 + .../laser/stz_animate_stroke-linecap.xml | 23 + .../laser/stz_animate_stroke-linecap2.xml | 16 + .../laser/stz_animate_stroke-linejoin.xml | 23 + .../laser/stz_animate_stroke-linejoin2.xml | 16 + .../media/laser/stz_animate_stroke-width.xml | 23 + .../media/laser/stz_animate_stroke-width2.xml | 16 + tests/media/laser/stz_animate_text-anchor.xml | 22 + .../media/laser/stz_animate_text-anchor2.xml | 15 + .../media/laser/stz_animate_vector-effect.xml | 23 + .../laser/stz_animate_vector-effect2.xml | 16 + tests/media/laser/stz_animate_viewBox.xml | 26 + tests/media/laser/stz_animate_viewBox2.xml | 17 + tests/media/laser/stz_animate_visibility.xml | 25 + tests/media/laser/stz_animate_visibility2.xml | 18 + tests/media/laser/stz_animate_xy.xml | 34 + tests/media/laser/stz_animate_xy2.xml | 17 + tests/media/laser/stz_anyXML_replace.xml | 18 + tests/media/laser/stz_circle_parsing.xml | 21 + tests/media/laser/stz_circle_parsing2.xml | 14 + tests/media/laser/stz_defs_parsing.xml | 28 + tests/media/laser/stz_defs_parsing2.xml | 21 + tests/media/laser/stz_desc_parsing.xml | 21 + tests/media/laser/stz_desc_parsing2.xml | 15 + tests/media/laser/stz_ellipse_parsing.xml | 21 + tests/media/laser/stz_ellipse_parsing2.xml | 14 + .../media/laser/stz_foreignObject_parsing.xml | 27 + tests/media/laser/stz_g_parsing.xml | 45 + tests/media/laser/stz_g_parsing2.xml | 33 + tests/media/laser/stz_image_parsing.xml | 45 + tests/media/laser/stz_image_parsing2.xml | 319 ++ tests/media/laser/stz_line_parsing.xml | 21 + tests/media/laser/stz_line_parsing2.xml | 14 + tests/media/laser/stz_linearGradient_bbox.xml | 30 + .../media/laser/stz_linearGradient_bbox2.xml | 21 + .../laser/stz_linearGradient_userSpace.xml | 37 + .../laser/stz_linearGradient_userSpace2.xml | 26 + tests/media/laser/stz_metadata_parsing.xml | 44 + tests/media/laser/stz_path_parsing.xml | 41 + tests/media/laser/stz_path_parsing2.xml | 25 + tests/media/laser/stz_polygon_parsing.xml | 34 + tests/media/laser/stz_polygon_parsing2.xml | 17 + tests/media/laser/stz_polyline_parsing.xml | 34 + tests/media/laser/stz_polyline_parsing2.xml | 17 + tests/media/laser/stz_rect_parsing.xml | 50 + tests/media/laser/stz_rect_parsing2.xml | 15 + tests/media/laser/stz_set_color.xml | 24 + tests/media/laser/stz_set_color2.xml | 17 + tests/media/laser/stz_svg_parsing.xml | 42 + tests/media/laser/stz_svg_parsing2.xml | 15 + tests/media/laser/stz_switch_parsing.xml | 31 + tests/media/laser/stz_text_parsing.xml | 38 + tests/media/laser/stz_text_parsing2.xml | 22 + tests/media/laser/stz_title_parsing.xml | 21 + tests/media/laser/stz_use_parsing.xml | 26 + tests/media/laser/stz_use_parsing2.xml | 19 + tests/media/laser/x_austria_relief.png | Bin 0 -> 56516 bytes .../media}/svg/all_syntaxes_1.1F2.svg | 0 .../media}/svg/createanim-by-script.svg | 0 .../media}/svg/createimage-by-script.svg | 0 tests/media/svg/opacity.svg | 67 + .../media}/svg/utfscript.svg | 0 tests/media/swf/cuisine.swf | Bin 0 -> 42416 bytes tests/media/ttml/ebu-ttd_prefix.ttml | 30 + .../media}/ttml/ebu-ttd_sample.ttml | 0 ...u-ttd_sample_invalid_mixed_namespaces.ttml | 28 + .../media/ttml/ebu-ttd_sample_invalid_ns.ttml | 28 + .../ttml/ebu-ttd_sample_invalid_root.ttml | 0 .../media}/ttml/ebu-ttd_sample_span.ttml | 0 .../ttml/ebu-ttd_timing_contiguous.ttml | 0 .../ttml/ebu-ttd_timing_non-contiguous.ttml | 0 .../ttml/ebu-ttd_timing_overlapping_fail.ttml | 0 tests/media/ttml/ttml.nhml | 14 + .../media}/webvtt/comments.vtt | 0 .../media}/webvtt/concatenation.vtt | 0 .../media}/webvtt/counter.srt | 0 .../media}/webvtt/counter.vtt | 0 .../webvtt/elephants-dream-chapters-en.vtt | 0 .../webvtt/elephants-dream-subtitles-de.vtt | 0 .../webvtt/elephants-dream-subtitles-en.vtt | 0 .../media}/webvtt/empty.vtt | 0 .../media}/webvtt/empty2.vtt | 0 .../media}/webvtt/empty3.vtt | 0 .../media}/webvtt/empty4.vtt | 0 .../media}/webvtt/header.vtt | 0 .../media}/webvtt/invalid1.vtt | 0 .../media}/webvtt/invalid2.vtt | 0 .../media}/webvtt/invalid3.vtt | 0 .../media}/webvtt/invalid4.vtt | 0 .../media}/webvtt/invalid5.vtt | 0 .../media}/webvtt/long-duration.vtt | 0 .../webvtt/multiline-header-additional.vtt | 0 .../webvtt/multiline-header-id-invalid.vtt | 0 .../media}/webvtt/multiline-header-id.vtt | 0 .../media}/webvtt/multiline-header.vtt | 0 .../media}/webvtt/overlapping-end.vtt | 0 .../media}/webvtt/overlapping-middle.vtt | 0 .../media}/webvtt/overlapping-rewritten.vtt | 0 .../media}/webvtt/overlapping-start.vtt | 0 .../media}/webvtt/overlapping.vtt | 0 .../media}/webvtt/simple.vtt | 0 .../media}/webvtt/spaces.vtt | 0 .../media}/webvtt/spec-example-basic.vtt | 0 .../media}/webvtt/spec-example-comment.vtt | 0 .../media}/webvtt/spec-example-comment2.vtt | 0 .../media}/webvtt/spec-example-identifier.vtt | 0 .../webvtt/spec-example-multiple-lines.vtt | 0 .../media}/webvtt/spec-example-nested.vtt | 0 .../media}/webvtt/spec-example-voice.vtt | 0 .../media}/webvtt/svg.vtt | 0 .../media}/webvtt/timestamps-invalid.vtt | 0 .../media}/webvtt/timestamps.vtt | 0 .../media}/x3d/x3d-2D-Arc2d.x3dv | 0 .../media}/x3d/x3d-2D-ArcClose2d.x3dv | 0 .../media}/x3d/x3d-2D-Disk2d.x3dv | 0 .../media}/x3d/x3d-2D-Polyline2d.x3dv | 0 .../media}/x3d/x3d-2D-Polypoint2d.x3dv | 0 .../media}/x3d/x3d-2D-TriangleSet2d.x3dv | 0 .../x3d/x3d-3D-IndexedTriangleFanSet.x3dv | 0 .../media}/x3d/x3d-3D-IndexedTriangleSet.x3dv | 0 .../x3d/x3d-3D-IndexedTriangleStripSet.x3dv | 0 .../media}/x3d/x3d-3D-LineSet.x3dv | 0 .../media}/x3d/x3d-3D-TriangleFanSet.x3dv | 0 .../media}/x3d/x3d-3D-TriangleSet.x3dv | 0 .../media}/x3d/x3d-3D-TriangleStripSet.x3dv | 0 .../media}/x3d/x3d-misc-ColorRGBA.x3dv | 0 .../media}/x3d/x3d-misc-HatchStyle.x3dv | 0 .../media}/x3d/x3d-misc-KeySensor.x3dv | 0 .../media}/x3d/x3d-misc-StringSensor.x3dv | 0 tests/media/xmlin4/anim.swf | Bin 0 -> 6913 bytes .../media}/xmlin4/ebu-ttd_sample.ttml | 0 tests/media/xmlin4/first.xml | 1 + tests/media/xmlin4/input.txt | 13 + .../media}/xmlin4/input.xml | 0 tests/media/xmlin4/last.xml | 1 + .../media}/xmlin4/meta-mett-no-mime.nhml | 0 .../media}/xmlin4/meta-mett-xml-header.nhml | 0 .../media}/xmlin4/meta-mett-xml.nhml | 0 .../media}/xmlin4/meta-mett.nhml | 0 .../media}/xmlin4/meta-metx-no-namespace.nhml | 0 .../media}/xmlin4/meta-metx.nhml | 0 tests/media/xmlin4/second.xml | 1 + .../media}/xmlin4/subt-sbtt-no-mime.nhml | 0 .../media}/xmlin4/subt-sbtt.nhml | 0 .../media}/xmlin4/subt-stpp-no-namespace.nhml | 0 .../media}/xmlin4/subt-stpp.nhml | 0 .../media}/xmlin4/text-stxt-header.nhml | 0 .../media}/xmlin4/text-stxt-no-mime.nhml | 0 .../media}/xmlin4/text-stxt.nhml | 0 ...D-background-background2D-bind-play-ui.xml | 73 + ...-background-background2D-image-play-ui.xml | 62 + ...-background-background2D-movie-play-ui.xml | 43 + ...ground-background2D-url-change-play-ui.xml | 53 + ...fs-2D-interactivity-discsensor-play-ui.xml | 120 + ...D-interactivity-htk-sensor-play-stderr.txt | 1 + ...ifs-2D-interactivity-keysensor-play-ui.xml | 97 + ...s-2D-interactivity-mousesensor-play-ui.xml | 93 + ...D-interactivity-nested-sensors-play-ui.xml | 81 + ...2D-interactivity-planesensor2D-play-ui.xml | 80 + ...nteractivity-proximitysensor2D-play-ui.xml | 75 + ...-2D-interactivity-stringsensor-play-ui.xml | 62 + ...eractivity-touchsensor-4states-play-ui.xml | 66 + ...ractivity-touchsensor-hitpoint-play-ui.xml | 115 + ...chsensor-isactive-exposedfield-play-ui.xml | 36 + ...ractivity-touchsensor-isactive-play-ui.xml | 26 + ...teractivity-touchsensor-isover-play-ui.xml | 40 + ...activity-touchsensor-move_over-play-ui.xml | 54 + ...D-painting-xlineproperties-cap-play-ui.xml | 75 + ...-painting-xlineproperties-join-play-ui.xml | 52 + ...xlineproperties-lineargradient-play-ui.xml | 23 + ...xlineproperties-radialgradient-play-ui.xml | 26 + .../bifs-2D-positioning-clipper2D-play-ui.xml | 20 + .../bifs-2D-positioning-layer2D-play-ui.xml | 34 + ...ning-layout-scroll-modes-horiz-play-ui.xml | 81 + ...oning-layout-scroll-modes-vert-play-ui.xml | 99 + ...sitioning-layout-scroll-on-off-play-ui.xml | 62 + ...fs-2D-positioning-orderedgroup-play-ui.xml | 34 + ...ositioning-pathlayout-graphics-play-ui.xml | 46 + ...bifs-2D-positioning-pathlayout-play-ui.xml | 40 + ...-positioning-transformmatrix2D-play-ui.xml | 63 + ...-compositetexture2D-background-play-ui.xml | 46 + ...compositetexture2D-transparent-play-ui.xml | 53 + ...fs-2D-texturing-gradients-text-play-ui.xml | 89 + ...exturing-gradients-transparent-play-ui.xml | 112 + ...exturing-lineargradient-simple-play-ui.xml | 123 + ...exturing-lineargradient-spread-play-ui.xml | 42 + ...exturing-radialgradient-simple-play-ui.xml | 92 + ...exturing-radialgradient-spread-play-ui.xml | 33 + ...ring-texturetransform-interact-play-ui.xml | 125 + .../rules/bifs-2D-viewport-simple-play-ui.xml | 36 + ...D-interactivity-cylindersensor-play-ui.xml | 101 + ...s-3D-interactivity-planesensor-play-ui.xml | 105 + ...-interactivity-proximitysensor-play-ui.xml | 56 + ...-3D-interactivity-spheresensor-play-ui.xml | 134 + ...interactivity-visibilitysensor-play-ui.xml | 44 + tests/rules/bifs-3D-lighting-fog-play-ui.xml | 53 + .../bifs-3D-positioning-layer3D-play-ui.xml | 149 + ...bifs-3D-shapes-box-transparent-play-ui.xml | 78 + .../bifs-3D-shapes-elevationgrid-play-ui.xml | 70 + .../bifs-3D-shapes-extrusion-play-ui.xml | 65 + ...fs-3D-shapes-nonlineardeformer-play-ui.xml | 5 + ...ring-compositetexture3D-bitmap-play-ui.xml | 43 + .../bifs-3D-viewpoint-bind-jump-play-ui.xml | 65 + .../rules/bifs-3D-viewpoint-bind-play-ui.xml | 55 + .../bifs-3D-viewpoint-ortho-bind-play-ui.xml | 56 + ...ifs-bitmap-image-meter-metrics-play-ui.xml | 96 + ...ifs-bitmap-image-pixel-metrics-play-ui.xml | 109 + .../bifs-cachetexture_nocache-play-ui.xml | 64 + .../bifs-command-proto-delete-play-stderr.txt | 4 + ...s-command-protolist-delete-play-stderr.txt | 3 + tests/rules/bifs-game-arrange-play-ui.xml | 118 + tests/rules/bifs-game-arrange.sh | 4 + tests/rules/bifs-game-breakout-play-ui.xml | 79 + tests/rules/bifs-game-breakout.sh | 4 + tests/rules/bifs-game-bubble-play-ui.xml | 109 + tests/rules/bifs-game-bubble.sh | 4 + tests/rules/bifs-game-minesweeper-play-ui.xml | 57 + tests/rules/bifs-game-minesweeper.sh | 5 + tests/rules/bifs-game-othello-play-ui.xml | 153 + tests/rules/bifs-game-othello.sh | 4 + ...terpolation-timesensor-enabled-play-ui.xml | 63 + ...timesensor-starttime_norestart-play-ui.xml | 47 + ...n-timesensor-starttime_restart-play-ui.xml | 44 + tests/rules/bifs-keynavigator-play-ui.xml | 70 + ...s-linking-inline-direct-inline-play-ui.xml | 83 + .../bifs-linking-inline-od-inline-play-ui.xml | 114 + ...-linking-inline-segment-inline-play-ui.xml | 61 + .../rules/bifs-media-audiobuffer-play-ui.xml | 84 + tests/rules/bifs-media-audioclip-play-ui.xml | 73 + ...ifs-media-audioclip-urlchanged-play-ui.xml | 51 + .../bifs-media-audiosource-mixing-play-ui.xml | 152 + .../rules/bifs-media-audiosource-play-ui.xml | 54 + ...s-media-audiosource-urlchanged-play-ui.xml | 54 + ...-media-imagetexture-url-change-play-ui.xml | 86 + ...ifs-media-movietexture-control-play-ui.xml | 68 + ...-media-movietexture-url-change-play-ui.xml | 39 + .../bifs-misc-hc-proto-events-play-ui.xml | 92 + ...non-linear-parsing-conditional-play-ui.xml | 72 + .../rules/bifs-proto-conditional-play-ui.xml | 30 + tests/rules/bifs-proto-multiple-play-ui.xml | 79 + tests/rules/bifs-proto-nested-play-ui.xml | 54 + tests/rules/bifs-proto-route-play-ui.xml | 21 + .../bifs-script-child-create-play-ui.xml | 31 + tests/rules/bifs-script-date.sh | 4 + tests/rules/bifs-script-load-url-play-ui.xml | 4 + .../rules/bifs-script-node-create-play-ui.xml | 50 + tests/rules/bifs-script-proto-play-ui.xml | 100 + tests/rules/bifs-storage-play-ui.xml | 68 + .../rules/bifs-stream-text-switch-play-ui.xml | 37 + ...bifs-timeline-mediacontrol-OCR-play-ui.xml | 139 + tests/rules/bifs-timeline-mediacontrol-OCR.sh | 2 + ...fs-timeline-mediacontrol-audio-play-ui.xml | 82 + ...eline-mediacontrol-audio-speed-play-ui.xml | 64 + ...timeline-mediacontrol-complete-play-ui.xml | 95 + ...line-mediacontrol-deactivation-play-ui.xml | 26 + ...ifs-timeline-mediacontrol-http-play-ui.xml | 112 + ...imeline-mediacontrol-inline-av-play-ui.xml | 105 + ...s-timeline-mediacontrol-inline-segments.sh | 2 + ...timeline-mediacontrol-segments-play-ui.xml | 23 + ...fs-timeline-mediacontrol-video-play-ui.xml | 85 + ...meline-mediacontrol-videospeed-play-ui.xml | 59 + ...r-stz_animate_hrefstreamid-play-stderr.txt | 2 + ...-stz_animate_hrefstreamid2-play-stderr.txt | 1 + ...n-meta-metx-no-namespace-import-stderr.txt | 3 + .../xmlin-subt-stpp-export-track-stderr.txt | 3 + ...n-subt-stpp-no-namespace-import-stderr.txt | 2 + .../xmlin-ttml-stpp-export-track-stderr.txt | 3 + tests/scripts/3D-HEVC.sh | 23 + tests/scripts/bifs_all.sh | 147 + tests/scripts/compositor_modes.sh | 80 + tests/scripts/dash-if-live.sh | 11 + tests/scripts/dash-if-ondemand.sh | 11 + tests/scripts/dash-live-generation.sh | 14 + tests/scripts/dash-live.sh | 11 + tests/scripts/dash-multiperiod.sh | 24 + tests/scripts/dash-ts.sh | 17 + tests/scripts/dash.sh | 11 + tests/scripts/encryption.sh | 61 + tests/scripts/fuzz-base.sh | 114 + tests/scripts/hls.sh | 14 + tests/scripts/iff.sh | 15 + tests/scripts/item.sh | 49 + tests/scripts/laser_all.sh | 81 + tests/scripts/mp42ts.sh | 45 + tests/scripts/mp4box-base.sh | 86 + tests/scripts/mp4box-io.sh | 119 + tests/scripts/mp4box-kind.sh | 157 + tests/scripts/mp4box-lang.sh | 86 + tests/scripts/mp4box-rtp.sh | 48 + tests/scripts/mp4box-subtitle.sh | 41 + tests/scripts/mp4client-base.sh | 65 + tests/scripts/mp4client-dash-config.sh | 31 + tests/scripts/mp4client-dash.sh | 33 + tests/scripts/mp4client-http.sh | 35 + tests/scripts/mp4client-rawout.sh | 36 + tests/scripts/negctts.sh | 16 + tests/scripts/nhml-subs.sh | 9 + tests/scripts/noFragsDefault.sh | 11 + tests/scripts/range_extension.sh | 35 + tests/scripts/scalable.sh | 51 + tests/scripts/smooth.sh | 45 + tests/scripts/swf.sh | 8 + tests/scripts/test_prl.sh | 28 + tests/scripts/vtt-all.sh | 43 + tests/scripts/x3d.sh | 27 + tests/scripts/xmlin.sh | 100 + tests/stylesheet.xsl | 38 + version.bat | 70 +- 1447 files changed, 94437 insertions(+), 32888 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .gitignore delete mode 100644 README create mode 100644 README.md delete mode 100644 applications/m3u82mpd/m3u82mpd.vcproj delete mode 100644 applications/m3u82mpd/main.c delete mode 100644 applications/mp42ts/mp42ts.h create mode 100644 applications/osmo4_android_studio/.gitignore create mode 100644 applications/osmo4_android_studio/Readme.md create mode 100644 applications/osmo4_android_studio/app/build.gradle create mode 100644 applications/osmo4_android_studio/app/libs/real3d.jar create mode 100644 applications/osmo4_android_studio/app/src/main/AndroidManifest.xml create mode 100755 applications/osmo4_android_studio/app/src/main/assets/configuration.xml create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/BitmapView.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstance.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstanceInterface.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacCallback.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacConfig.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/MPEGVSensor.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4GLSurfaceView.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4Renderer.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Preview.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/SensorServices.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditor.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditorActivity.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileArrayAdapter.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserActivity.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserFragment.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileManager.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/PrefsActivity.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/XMLTagHandler.java create mode 100644 applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/logs/GpacLogger.java create mode 100644 applications/osmo4_android_studio/app/src/main/jni/README.txt create mode 100644 applications/osmo4_android_studio/app/src/main/jni/wrapper.cpp create mode 100644 applications/osmo4_android_studio/app/src/main/jni/wrapper.h create mode 100644 applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.cpp create mode 100644 applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.hpp create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-hdpi/icon.png create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-ldpi/icon.png create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_audio.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_compressed.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_error.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_file.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_folder.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_image.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_video.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/icon.png create mode 100644 applications/osmo4_android_studio/app/src/main/res/drawable/ic_back.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/about_dialog.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/activity_config_file_editor.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/activity_file_chooser.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/auth_requested.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/fragment_file_chooser.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/list_item_file_chooser.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/layout/main.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/menu/main_menu.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/values/arrays.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/values/strings.xml create mode 100644 applications/osmo4_android_studio/app/src/main/res/xml/preference.xml create mode 100644 applications/osmo4_android_studio/build.gradle create mode 100644 applications/osmo4_android_studio/gradle/wrapper/gradle-wrapper.jar create mode 100644 applications/osmo4_android_studio/gradle/wrapper/gradle-wrapper.properties create mode 100755 applications/osmo4_android_studio/gradlew create mode 100644 applications/osmo4_android_studio/gradlew.bat create mode 100644 applications/osmo4_android_studio/import-summary.txt create mode 100644 applications/osmo4_android_studio/settings.gradle create mode 100644 applications/testapps/hevcbench/Makefile delete mode 100644 applications/testapps/mp42ts/mp42ts.vcproj create mode 100644 applications/testapps/player_api/main.c create mode 100644 applications/testapps/ts2udp/main.c create mode 100644 applications/testapps/ts2udp/ts2udp.vcxproj create mode 100755 change_version.sh create mode 100755 check_revision.sh create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/gpac-doc.docs create mode 100644 debian/gpac-doc.install create mode 100644 debian/gpac.install create mode 100644 debian/libgpac-dev.install create mode 100644 debian/postinst create mode 100644 debian/postrm create mode 100755 debian/rules create mode 100644 debian/watch create mode 100644 doc/man/dashcast.1 create mode 100644 doc/man/mp42ts.1 create mode 100644 gui/extensions/bifs_tests/applications-other.svg create mode 100644 gui/extensions/bifs_tests/bifs_tests.js create mode 100644 gui/extensions/bifs_tests/init.js create mode 100644 gui/extensions/showroom/init.js create mode 100644 gui/extensions/showroom/osmo.bt create mode 100644 gui/extensions/showroom/showroom.js create mode 100644 gui/icons/compass.svg create mode 100755 modules/mediacodec_dec/Makefile create mode 100644 modules/mediacodec_dec/mediacodec_dec.c create mode 100644 modules/mediacodec_dec/mediacodec_dec.h create mode 100644 modules/mediacodec_dec/mediacodec_dec_jni.c create mode 100644 modules/vtb_decode/Makefile create mode 100644 modules/vtb_decode/glcontext.m create mode 100644 modules/vtb_decode/vtb_decode.c delete mode 100644 regression_tests/bifs/bifs-3D-positioning-layer3D.bt delete mode 100644 regression_tests/bifs/bifs-3D-shapes-box-transparent.bt delete mode 100644 regression_tests/bifs/bifs-3D-viewpoint-ortho-bind.bt delete mode 100644 regression_tests/bifs/bifs-linking-inline-rtsp-no-od.bt delete mode 100644 regression_tests/bifs/bifs-linking-inline-rtsp.bt delete mode 100644 regression_tests/bifs/bifs-script-proto.bt delete mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-inline-segments.bt delete mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-inline.bt delete mode 100644 regression_tests/bifs/bifs-timeline-mediacontrol-rtsp.bt delete mode 100644 regression_tests/build-navigator-w32.bat delete mode 100644 regression_tests/build-shell delete mode 100644 regression_tests/build-w32.bat delete mode 100644 regression_tests/utfscript.svg delete mode 100644 regression_tests/xmlin4/first.xml delete mode 100644 regression_tests/xmlin4/input.txt delete mode 100644 regression_tests/xmlin4/last.xml delete mode 100644 regression_tests/xmlin4/run_one_test.sh delete mode 100644 regression_tests/xmlin4/run_tests.sh delete mode 100644 regression_tests/xmlin4/second.xml create mode 100644 shaders/fragment.glsl create mode 100644 shaders/vertex.glsl create mode 100644 src/isomedia/iff.c create mode 100644 static.mak create mode 100644 tests/README.MD create mode 100755 tests/ghp_deploy.sh create mode 100644 tests/index.html create mode 100755 tests/make_tests.sh rename {regression_tests => tests/media}/auxiliary_files/count_arabic.mp3 (100%) rename {regression_tests => tests/media}/auxiliary_files/count_english.mp3 (100%) rename {regression_tests => tests/media}/auxiliary_files/count_french.mp3 (100%) rename {regression_tests => tests/media}/auxiliary_files/count_german.mp3 (100%) rename {regression_tests => tests/media}/auxiliary_files/count_italian.mp3 (100%) rename {regression_tests => tests/media}/auxiliary_files/count_spanish.mp3 (100%) rename {regression_tests => tests/media}/auxiliary_files/count_video.cmp (100%) create mode 100644 tests/media/auxiliary_files/counter.hvc rename {regression_tests => tests/media}/auxiliary_files/enst_audio.aac (100%) rename {regression_tests => tests/media}/auxiliary_files/enst_video.h264 (100%) rename {regression_tests => tests/media}/auxiliary_files/index2batch.xslt (100%) rename {regression_tests => tests/media}/auxiliary_files/index2html.xslt (100%) rename {regression_tests => tests/media}/auxiliary_files/index2sh.xslt (100%) rename {regression_tests => tests/media}/auxiliary_files/logo.bt (100%) rename {regression_tests => tests/media}/auxiliary_files/logo.jpg (100%) rename {regression_tests => tests/media}/auxiliary_files/logo.png (100%) rename {regression_tests => tests/media}/auxiliary_files/nefertiti.wrl (100%) rename {regression_tests => tests/media}/auxiliary_files/sky.jpg (100%) create mode 100644 tests/media/auxiliary_files/subs.ismt rename {regression_tests => tests/media}/auxiliary_files/subtitle.srt (100%) rename {regression_tests => tests/media}/auxiliary_files/subtitle_fr.srt (100%) rename {regression_tests => tests/media}/auxiliary_files/svg2html.xslt (100%) rename {regression_tests => tests/media}/auxiliary_files/x3d2html.xslt (100%) rename {regression_tests => tests/media}/auxiliary_files/xmt2html.xslt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-background-background2D-bind.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-background-background2D-image.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-background-background2D-layer2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-background-background2D-movie.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-background-background2D-url-change.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-discsensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-htk-sensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-keysensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-mousesensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-nested-sensors.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-planesensor2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-proximitysensor2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-stringsensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-touchsensor-4states.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-touchsensor-hitpoint.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-touchsensor-isactive-exposedfield.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-touchsensor-isactive.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-touchsensor-isover.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-interactivity-touchsensor-move_over.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-colortransform-alpha.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-colortransform-bitmap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-colortransform-color.bt (100%) create mode 100644 tests/media/bifs/bifs-2D-painting-colortransform-texture.bt rename {regression_tests => tests/media}/bifs/bifs-2D-painting-lineproperties.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-material2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-cap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-compositetexture2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-dash.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-imagetexture.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-join.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-lineargradient.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-radialgradient.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-scalable.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-painting-xlineproperties-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-clipper2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-form-align-center.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-form-align-horiz.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-form-align-vert.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-form-spread-horiz.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-form-spread-vert.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layer2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layer2d-in-layer2d.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-ltr-nowrap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-ltr-wrap-btt.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-ltr-wrap-ttb.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-rtl-nowrap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-rtl-wrap-btt.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-rtl-wrap-ttb.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-horiz-text.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-scroll-child.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-scroll-full.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-scroll-modes-horiz.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-scroll-modes-vert.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-scroll-on-off.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-vert-btt-nowrap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-vert-btt-wrap-ltr.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-vert-btt-wrap-rtl.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-vert-ttb-nowrap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-vert-ttb-wrap-ltr.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-layout-vert-ttb-wrap-rtl.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-orderedgroup.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-pathlayout-graphics.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-pathlayout.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-transform2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-positioning-transformmatrix2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-shapes-all.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-shapes-indexfaceset2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-shapes-indexlineset2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-shapes-pointset2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-shapes-xcurve2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-compositetexture2D-background.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-compositetexture2D-bitmap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-compositetexture2D-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-gradients-text.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-gradients-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-imagetexture-shapes.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-lineargradient-simple.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-lineargradient-spread.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-movietexture-shapes.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-pixeltexture.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-radialgradient-simple.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-radialgradient-spread.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-texturetransform-base.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-texturetransform-interact.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-texturing-texturetransform-transformmatrix2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-viewport-complete.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-2D-viewport-simple.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-background-images.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-background.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-collision-proxy.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-collision.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-cylindersensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-planesensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-proximitysensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-spheresensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-interactivity-visibilitysensor.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-lighting-directionalLight.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-lighting-fog.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-lighting-pointlight.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-lighting-spotlight.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-positioning-billboard-viewer-alignment.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-positioning-billboard.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-positioning-gravity.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-positioning-layer3D-views.bt (100%) create mode 100644 tests/media/bifs/bifs-3D-positioning-layer3D.bt rename {regression_tests => tests/media}/bifs/bifs-3D-positioning-lod.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-positioning-transform.bt (100%) create mode 100644 tests/media/bifs/bifs-3D-shapes-box-transparent.bt rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-box.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-cone.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-cylinder.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-elevationgrid.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-extrusion.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-indexedfaceset.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-indexedlineset.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-nonlineardeformer.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-shapes-pointset.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-box-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-box-video.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-box.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-compositetexture3D-bitmap.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-compositetexture3D-box.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-cone-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-cone.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-cylinder-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-cylinder.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-transform-box.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-texturing-transform-matrix-box.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-viewpoint-anim.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-viewpoint-bind-jump.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-3D-viewpoint-bind.bt (100%) create mode 100644 tests/media/bifs/bifs-3D-viewpoint-ortho-bind.bt rename {regression_tests => tests/media}/bifs/bifs-bitmap-image-meter-metrics.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-bitmap-image-pixel-metrics.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-bitmap-image-resizing.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-bitmap-movie-materialkey.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-bitmap-movie.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-bitmap-video-resizing.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-cachetexture_cache.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-cachetexture_nocache.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-animated-osmo4logo.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-delete-index.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-delete-node.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-delete-route.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-global-qp.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-insert-index.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-insert-node.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-insert-nodedef.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-insert-route.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-multiple-replace-field.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-multiple-replace-index.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-node-delete-ex.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-proto-delete.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-proto-insert.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-protolist-delete.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-quantification.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-field.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-index.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-node-null.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-node.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-route.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-scene-null.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-replace-scene.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-route-add-children.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-route-children.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-route-node-exposedfield.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-route-node.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-command-route-remove-children.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-environmenttest.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-forestgump-lib.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-forestgump.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-mfurl-lib.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-mfurl.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-nood-lib.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-nood.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-simple-lib.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-externproto-simple.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-game-arrange.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-game-breakout.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-game-bubble.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-game-minesweeper.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-game-othello.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-colorinterpolator.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-coordinateinterpolator2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-positionanimator.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-positionanimator2D.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-positioninterpolator-position.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-positioninterpolator-size.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-positioninterpolator2D-position.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-positioninterpolator2D-size.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-scalaranimator.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-scalarinterpolator.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-timesensor-enabled.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-timesensor-starttime_norestart.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-timesensor-starttime_restart.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-interpolation-valuator-sftime.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-keynavigator.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-anchor-mp4-next.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-anchor-mp4-prev.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-anchor-viewpoint.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-anchor-www.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-animationstream.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-inline-direct-inline.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-inline-direct.bt (100%) create mode 100644 tests/media/bifs/bifs-linking-inline-http-no-od.bt create mode 100644 tests/media/bifs/bifs-linking-inline-http.bt rename {regression_tests => tests/media}/bifs/bifs-linking-inline-od-inline.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-inline-od.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-inline-segment-inline.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-linking-inline-segment.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-audiobuffer.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-audioclip-urlchanged.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-audioclip.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-audiosource-mixing.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-audiosource-urlchanged.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-audiosource.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-imagetexture-OD-reuse.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-imagetexture-no-od.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-imagetexture-object-scale.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-imagetexture-transparent.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-imagetexture-url-change.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-control.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-no-od.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-od-joinsession.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-od-leave-session.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-owns-OCR.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-shares-OCR.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-movietexture-url-change.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-sound-spatialize.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-media-sound.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-UTF16-input.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-cyclic-graph.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-hc-proto-events.bt (100%) create mode 100644 tests/media/bifs/bifs-misc-hc-proto-offscreengroup.bt rename {regression_tests => tests/media}/bifs/bifs-misc-hc-proto-pathextrusion.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-hc-proto-planarextrusion.bt (100%) create mode 100644 tests/media/bifs/bifs-misc-hc-proto-planeclipper-box.bt rename {regression_tests => tests/media}/bifs/bifs-misc-hc-proto-planeclipper.bt (100%) create mode 100644 tests/media/bifs/bifs-misc-hc-proto-texture.bt rename {regression_tests => tests/media}/bifs/bifs-misc-non-linear-parsing-conditional.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-non-linear-parsing-use.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-srt-import-3gpp-control-share-ocr.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-srt-import-3gpp-control.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-srt-import-3gpp.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-misc-srt-import.bt (100%) create mode 100755 tests/media/bifs/bifs-od-language-code.bt rename {regression_tests => tests/media}/bifs/bifs-od-remove-esd.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-od-remove-od.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-od-update-od.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-conditional.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-delete-def.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-delete-index.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-forestgump.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-mfurl.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-multiple.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-nested.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-route.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-sftime-protocode.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-sftime-protointerface.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-simple.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-proto-use.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-char-to-int.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-child-create.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-date.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-event-out.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-initialize.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-load-url.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-node-access.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-script-node-create.bt (100%) create mode 100644 tests/media/bifs/bifs-script-proto.bt rename {regression_tests => tests/media}/bifs/bifs-script-timestamp.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-storage.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-stream-text-switch.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-horiz1.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-horiz2.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-horiz3.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-horiz4.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-vert1.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-vert2.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-vert3.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-align-vert4.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-glyph-advance.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-length.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-maxextend.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-style.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-unicode.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-text-vrml-alignment.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-OCR.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-audio-speed.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-audio.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-complete.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-deactivation.bt (100%) create mode 100644 tests/media/bifs/bifs-timeline-mediacontrol-http.bt rename regression_tests/bifs/bifs-timeline-mediacontrol-inline-av.bt => tests/media/bifs/bifs-timeline-mediacontrol-inline-av-inline.bt (100%) create mode 100644 tests/media/bifs/bifs-timeline-mediacontrol-inline-av.bt rename regression_tests/bifs/bifs-timeline-mediacontrol-seg-inline.bt => tests/media/bifs/bifs-timeline-mediacontrol-inline-segments-inline.bt (100%) create mode 100644 tests/media/bifs/bifs-timeline-mediacontrol-inline-segments.bt rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-segments.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-video.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediacontrol-videospeed.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediasensor-segment-switch.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediasensor-segment.bt (100%) rename {regression_tests => tests/media}/bifs/bifs-timeline-mediasensor.bt (100%) create mode 100644 tests/media/bifs/counter-auto.bt rename regression_tests/_mozilla_ie_action.html => tests/media/browser_integration/mozilla_ie_action.html (100%) rename regression_tests/_mozilla_ie_simple.html => tests/media/browser_integration/mozilla_ie_simple.html (100%) rename regression_tests/_ppc_action.html => tests/media/browser_integration/ppc_action.html (100%) rename regression_tests/_ppc_simple.html => tests/media/browser_integration/ppc_simple.html (100%) rename {regression_tests => tests/media}/build-navigator-sh (100%) create mode 100644 tests/media/build-navigator-w32.bat create mode 100755 tests/media/chaptering/chapters.txt rename {regression_tests => tests/media}/dom/gpac-dom-portability.js (100%) rename {regression_tests => tests/media}/dom/gpac-html-portability.js (100%) create mode 100644 tests/media/encryption/drm_adobe.xml create mode 100644 tests/media/encryption/drm_cbc.xml create mode 100644 tests/media/encryption/drm_cbcs.xml create mode 100644 tests/media/encryption/drm_cens.xml create mode 100644 tests/media/encryption/drm_ctr.xml create mode 100644 tests/media/encryption/drm_isma.xml rename {regression_tests => tests/media}/html5_video/basic_arraybuffer.js (100%) rename {regression_tests => tests/media}/html5_video/basic_audio.svg (100%) rename {regression_tests => tests/media}/html5_video/basic_mediasource.js (100%) rename {regression_tests => tests/media}/html5_video/basic_sourcebuffer.js (100%) rename {regression_tests => tests/media}/html5_video/basic_url.js (100%) rename {regression_tests => tests/media}/html5_video/basic_video.js (100%) rename {regression_tests => tests/media}/html5_video/basic_video.svg (100%) rename {regression_tests => tests/media}/html5_video/bind.js (100%) rename {regression_tests => tests/media}/html5_video/counter-mp4-audio-segments-http.js (100%) rename {regression_tests => tests/media}/html5_video/counter-mp4-av-segments-http.js (100%) rename {regression_tests => tests/media}/html5_video/counter-mp4-video-segments-http.js (100%) rename {regression_tests => tests/media}/html5_video/counter-mp4-video-segments-live-nobs-http.js (100%) rename {regression_tests => tests/media}/html5_video/counter-mp4-video-segments-local.js (100%) rename {regression_tests => tests/media}/html5_video/file.json (100%) rename {regression_tests => tests/media}/html5_video/file.txt (100%) rename {regression_tests => tests/media}/html5_video/file.xml (100%) rename {regression_tests => tests/media}/html5_video/gpac-mse-spatial.js (100%) rename {regression_tests => tests/media}/html5_video/gpac-mse.js (100%) rename {regression_tests => tests/media}/html5_video/implementation_notes.txt (100%) rename {regression_tests => tests/media}/html5_video/mediaevents.js (100%) rename {regression_tests => tests/media}/html5_video/mediaevents.svg (100%) rename {regression_tests => tests/media}/html5_video/mse-overlap.js (100%) rename {regression_tests => tests/media}/html5_video/mse.svg (100%) rename {regression_tests => tests/media}/html5_video/myanmar-tiles.js (100%) rename {regression_tests => tests/media}/html5_video/nodejs-byte-server.js (100%) rename {regression_tests => tests/media}/html5_video/redbull-mp4-audio-segments-http.js (100%) rename {regression_tests => tests/media}/html5_video/redbull-mp4-video-segments-http.js (100%) rename {regression_tests => tests/media}/html5_video/spatial-mse.svg (100%) rename {regression_tests => tests/media}/html5_video/two-videos.svg (100%) rename {regression_tests => tests/media}/html5_video/video.svg (100%) rename {regression_tests => tests/media}/html5_video/xhr.js (100%) rename {regression_tests => tests/media}/html5_video/xhr.svg (100%) rename {regression_tests => tests/media}/index.css (100%) rename {regression_tests => tests/media}/index.xml (100%) create mode 100755 tests/media/laser/enst_2laser3.xml create mode 100755 tests/media/laser/enst_3laser.xml create mode 100755 tests/media/laser/enst_afrique.xml create mode 100755 tests/media/laser/enst_amerique_centrale.xml create mode 100755 tests/media/laser/enst_amerique_sud.xml create mode 100755 tests/media/laser/enst_canvas.xml create mode 100755 tests/media/laser/enst_cee.xml create mode 100755 tests/media/laser/enst_europe.xml create mode 100755 tests/media/laser/enst_flow.xml create mode 100755 tests/media/laser/enst_gold.xml create mode 100755 tests/media/laser/enst_hame.xml create mode 100755 tests/media/laser/enst_sydn.xml create mode 100755 tests/media/laser/enst_topk.xml create mode 100755 tests/media/laser/enst_tram.xml create mode 100755 tests/media/laser/stz_Navigation_simple.xml create mode 100755 tests/media/laser/stz_a_parsing.xml create mode 100755 tests/media/laser/stz_a_parsing2.xml create mode 100755 tests/media/laser/stz_animateMotion_mpath.xml create mode 100755 tests/media/laser/stz_animateMotion_parsing.xml create mode 100755 tests/media/laser/stz_animateMotion_parsing2.xml create mode 100755 tests/media/laser/stz_animateTransform_rotate.xml create mode 100755 tests/media/laser/stz_animateTransform_rotate2.xml create mode 100755 tests/media/laser/stz_animateTransform_scale.xml create mode 100755 tests/media/laser/stz_animateTransform_scale2.xml create mode 100755 tests/media/laser/stz_animateTransform_skew.xml create mode 100755 tests/media/laser/stz_animateTransform_skew2.xml create mode 100755 tests/media/laser/stz_animateTransform_translate.xml create mode 100755 tests/media/laser/stz_animateTransform_translate2.xml create mode 100755 tests/media/laser/stz_animate_choice.xml create mode 100755 tests/media/laser/stz_animate_choice2.xml create mode 100755 tests/media/laser/stz_animate_colorrendering.xml create mode 100755 tests/media/laser/stz_animate_colorrendering2.xml create mode 100755 tests/media/laser/stz_animate_display-align.xml create mode 100755 tests/media/laser/stz_animate_display-align2.xml create mode 100755 tests/media/laser/stz_animate_display.xml create mode 100755 tests/media/laser/stz_animate_display2.xml create mode 100755 tests/media/laser/stz_animate_editable.xml create mode 100755 tests/media/laser/stz_animate_editable2.xml create mode 100755 tests/media/laser/stz_animate_fill-rule.xml create mode 100755 tests/media/laser/stz_animate_fill-rule2.xml create mode 100755 tests/media/laser/stz_animate_fill.xml create mode 100755 tests/media/laser/stz_animate_fill2.xml create mode 100755 tests/media/laser/stz_animate_fillstroke-opacity.xml create mode 100755 tests/media/laser/stz_animate_fillstroke-opacity2.xml create mode 100755 tests/media/laser/stz_animate_font-family.xml create mode 100755 tests/media/laser/stz_animate_font-family2.xml create mode 100755 tests/media/laser/stz_animate_font-style.xml create mode 100755 tests/media/laser/stz_animate_font-style2.xml create mode 100755 tests/media/laser/stz_animate_font-weight.xml create mode 100755 tests/media/laser/stz_animate_font-weight2.xml create mode 100755 tests/media/laser/stz_animate_gradientUnits.xml create mode 100755 tests/media/laser/stz_animate_gradientUnits2.xml create mode 100755 tests/media/laser/stz_animate_gsize.xml create mode 100755 tests/media/laser/stz_animate_gsize2.xml create mode 100755 tests/media/laser/stz_animate_hrefa.xml create mode 100755 tests/media/laser/stz_animate_hrefa2.xml create mode 100755 tests/media/laser/stz_animate_hrefstreamid.xml create mode 100755 tests/media/laser/stz_animate_hrefstreamid2.xml create mode 100755 tests/media/laser/stz_animate_hrefuse.xml create mode 100755 tests/media/laser/stz_animate_hrefuse2.xml create mode 100755 tests/media/laser/stz_animate_image-rendering.xml create mode 100755 tests/media/laser/stz_animate_image-rendering2.xml create mode 100755 tests/media/laser/stz_animate_paintserver.xml create mode 100755 tests/media/laser/stz_animate_paintserver2.xml create mode 100755 tests/media/laser/stz_animate_parsing.xml create mode 100755 tests/media/laser/stz_animate_parsing2.xml create mode 100755 tests/media/laser/stz_animate_path.xml create mode 100755 tests/media/laser/stz_animate_path2.xml create mode 100755 tests/media/laser/stz_animate_pointer-events.xml create mode 100755 tests/media/laser/stz_animate_pointer-events2.xml create mode 100755 tests/media/laser/stz_animate_points.xml create mode 100755 tests/media/laser/stz_animate_points2.xml create mode 100755 tests/media/laser/stz_animate_preserveAspectRatio.xml create mode 100755 tests/media/laser/stz_animate_preserveAspectRatio2.xml create mode 100755 tests/media/laser/stz_animate_shaperendering.xml create mode 100755 tests/media/laser/stz_animate_shaperendering2.xml create mode 100755 tests/media/laser/stz_animate_stroke-linecap.xml create mode 100755 tests/media/laser/stz_animate_stroke-linecap2.xml create mode 100755 tests/media/laser/stz_animate_stroke-linejoin.xml create mode 100755 tests/media/laser/stz_animate_stroke-linejoin2.xml create mode 100755 tests/media/laser/stz_animate_stroke-width.xml create mode 100755 tests/media/laser/stz_animate_stroke-width2.xml create mode 100755 tests/media/laser/stz_animate_text-anchor.xml create mode 100755 tests/media/laser/stz_animate_text-anchor2.xml create mode 100755 tests/media/laser/stz_animate_vector-effect.xml create mode 100755 tests/media/laser/stz_animate_vector-effect2.xml create mode 100755 tests/media/laser/stz_animate_viewBox.xml create mode 100755 tests/media/laser/stz_animate_viewBox2.xml create mode 100755 tests/media/laser/stz_animate_visibility.xml create mode 100755 tests/media/laser/stz_animate_visibility2.xml create mode 100755 tests/media/laser/stz_animate_xy.xml create mode 100755 tests/media/laser/stz_animate_xy2.xml create mode 100755 tests/media/laser/stz_anyXML_replace.xml create mode 100755 tests/media/laser/stz_circle_parsing.xml create mode 100755 tests/media/laser/stz_circle_parsing2.xml create mode 100755 tests/media/laser/stz_defs_parsing.xml create mode 100755 tests/media/laser/stz_defs_parsing2.xml create mode 100755 tests/media/laser/stz_desc_parsing.xml create mode 100755 tests/media/laser/stz_desc_parsing2.xml create mode 100755 tests/media/laser/stz_ellipse_parsing.xml create mode 100755 tests/media/laser/stz_ellipse_parsing2.xml create mode 100755 tests/media/laser/stz_foreignObject_parsing.xml create mode 100755 tests/media/laser/stz_g_parsing.xml create mode 100755 tests/media/laser/stz_g_parsing2.xml create mode 100755 tests/media/laser/stz_image_parsing.xml create mode 100755 tests/media/laser/stz_image_parsing2.xml create mode 100755 tests/media/laser/stz_line_parsing.xml create mode 100755 tests/media/laser/stz_line_parsing2.xml create mode 100755 tests/media/laser/stz_linearGradient_bbox.xml create mode 100755 tests/media/laser/stz_linearGradient_bbox2.xml create mode 100755 tests/media/laser/stz_linearGradient_userSpace.xml create mode 100755 tests/media/laser/stz_linearGradient_userSpace2.xml create mode 100755 tests/media/laser/stz_metadata_parsing.xml create mode 100755 tests/media/laser/stz_path_parsing.xml create mode 100755 tests/media/laser/stz_path_parsing2.xml create mode 100755 tests/media/laser/stz_polygon_parsing.xml create mode 100755 tests/media/laser/stz_polygon_parsing2.xml create mode 100755 tests/media/laser/stz_polyline_parsing.xml create mode 100755 tests/media/laser/stz_polyline_parsing2.xml create mode 100755 tests/media/laser/stz_rect_parsing.xml create mode 100755 tests/media/laser/stz_rect_parsing2.xml create mode 100755 tests/media/laser/stz_set_color.xml create mode 100755 tests/media/laser/stz_set_color2.xml create mode 100755 tests/media/laser/stz_svg_parsing.xml create mode 100755 tests/media/laser/stz_svg_parsing2.xml create mode 100755 tests/media/laser/stz_switch_parsing.xml create mode 100755 tests/media/laser/stz_text_parsing.xml create mode 100755 tests/media/laser/stz_text_parsing2.xml create mode 100755 tests/media/laser/stz_title_parsing.xml create mode 100755 tests/media/laser/stz_use_parsing.xml create mode 100755 tests/media/laser/stz_use_parsing2.xml create mode 100644 tests/media/laser/x_austria_relief.png rename {regression_tests => tests/media}/svg/all_syntaxes_1.1F2.svg (100%) rename {regression_tests => tests/media}/svg/createanim-by-script.svg (100%) rename {regression_tests => tests/media}/svg/createimage-by-script.svg (100%) create mode 100644 tests/media/svg/opacity.svg rename {regression_tests => tests/media}/svg/utfscript.svg (100%) create mode 100644 tests/media/swf/cuisine.swf create mode 100644 tests/media/ttml/ebu-ttd_prefix.ttml rename {regression_tests => tests/media}/ttml/ebu-ttd_sample.ttml (100%) create mode 100644 tests/media/ttml/ebu-ttd_sample_invalid_mixed_namespaces.ttml create mode 100644 tests/media/ttml/ebu-ttd_sample_invalid_ns.ttml rename regression_tests/ttml/ebu-ttd_sample_invalid_ns.ttml => tests/media/ttml/ebu-ttd_sample_invalid_root.ttml (100%) rename {regression_tests => tests/media}/ttml/ebu-ttd_sample_span.ttml (100%) rename {regression_tests => tests/media}/ttml/ebu-ttd_timing_contiguous.ttml (100%) rename {regression_tests => tests/media}/ttml/ebu-ttd_timing_non-contiguous.ttml (100%) rename {regression_tests => tests/media}/ttml/ebu-ttd_timing_overlapping_fail.ttml (100%) create mode 100644 tests/media/ttml/ttml.nhml rename {regression_tests => tests/media}/webvtt/comments.vtt (100%) rename {regression_tests => tests/media}/webvtt/concatenation.vtt (100%) rename {regression_tests => tests/media}/webvtt/counter.srt (100%) rename {regression_tests => tests/media}/webvtt/counter.vtt (100%) rename {regression_tests => tests/media}/webvtt/elephants-dream-chapters-en.vtt (100%) rename {regression_tests => tests/media}/webvtt/elephants-dream-subtitles-de.vtt (100%) rename {regression_tests => tests/media}/webvtt/elephants-dream-subtitles-en.vtt (100%) rename {regression_tests => tests/media}/webvtt/empty.vtt (100%) rename {regression_tests => tests/media}/webvtt/empty2.vtt (100%) rename {regression_tests => tests/media}/webvtt/empty3.vtt (100%) rename {regression_tests => tests/media}/webvtt/empty4.vtt (100%) rename {regression_tests => tests/media}/webvtt/header.vtt (100%) rename {regression_tests => tests/media}/webvtt/invalid1.vtt (100%) rename {regression_tests => tests/media}/webvtt/invalid2.vtt (100%) rename {regression_tests => tests/media}/webvtt/invalid3.vtt (100%) rename {regression_tests => tests/media}/webvtt/invalid4.vtt (100%) rename {regression_tests => tests/media}/webvtt/invalid5.vtt (100%) rename {regression_tests => tests/media}/webvtt/long-duration.vtt (100%) rename {regression_tests => tests/media}/webvtt/multiline-header-additional.vtt (100%) rename {regression_tests => tests/media}/webvtt/multiline-header-id-invalid.vtt (100%) rename {regression_tests => tests/media}/webvtt/multiline-header-id.vtt (100%) rename {regression_tests => tests/media}/webvtt/multiline-header.vtt (100%) rename {regression_tests => tests/media}/webvtt/overlapping-end.vtt (100%) rename {regression_tests => tests/media}/webvtt/overlapping-middle.vtt (100%) rename {regression_tests => tests/media}/webvtt/overlapping-rewritten.vtt (100%) rename {regression_tests => tests/media}/webvtt/overlapping-start.vtt (100%) rename {regression_tests => tests/media}/webvtt/overlapping.vtt (100%) rename {regression_tests => tests/media}/webvtt/simple.vtt (100%) rename {regression_tests => tests/media}/webvtt/spaces.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-basic.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-comment.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-comment2.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-identifier.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-multiple-lines.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-nested.vtt (100%) rename {regression_tests => tests/media}/webvtt/spec-example-voice.vtt (100%) rename {regression_tests => tests/media}/webvtt/svg.vtt (100%) rename {regression_tests => tests/media}/webvtt/timestamps-invalid.vtt (100%) rename {regression_tests => tests/media}/webvtt/timestamps.vtt (100%) rename {regression_tests => tests/media}/x3d/x3d-2D-Arc2d.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-2D-ArcClose2d.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-2D-Disk2d.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-2D-Polyline2d.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-2D-Polypoint2d.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-2D-TriangleSet2d.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-IndexedTriangleFanSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-IndexedTriangleSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-IndexedTriangleStripSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-LineSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-TriangleFanSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-TriangleSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-3D-TriangleStripSet.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-misc-ColorRGBA.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-misc-HatchStyle.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-misc-KeySensor.x3dv (100%) rename {regression_tests => tests/media}/x3d/x3d-misc-StringSensor.x3dv (100%) create mode 100644 tests/media/xmlin4/anim.swf rename {regression_tests => tests/media}/xmlin4/ebu-ttd_sample.ttml (100%) create mode 100644 tests/media/xmlin4/first.xml create mode 100644 tests/media/xmlin4/input.txt rename {regression_tests => tests/media}/xmlin4/input.xml (100%) create mode 100644 tests/media/xmlin4/last.xml rename {regression_tests => tests/media}/xmlin4/meta-mett-no-mime.nhml (100%) rename {regression_tests => tests/media}/xmlin4/meta-mett-xml-header.nhml (100%) rename {regression_tests => tests/media}/xmlin4/meta-mett-xml.nhml (100%) rename {regression_tests => tests/media}/xmlin4/meta-mett.nhml (100%) rename {regression_tests => tests/media}/xmlin4/meta-metx-no-namespace.nhml (100%) rename {regression_tests => tests/media}/xmlin4/meta-metx.nhml (100%) create mode 100644 tests/media/xmlin4/second.xml rename {regression_tests => tests/media}/xmlin4/subt-sbtt-no-mime.nhml (100%) rename {regression_tests => tests/media}/xmlin4/subt-sbtt.nhml (100%) rename {regression_tests => tests/media}/xmlin4/subt-stpp-no-namespace.nhml (100%) rename {regression_tests => tests/media}/xmlin4/subt-stpp.nhml (100%) rename {regression_tests => tests/media}/xmlin4/text-stxt-header.nhml (100%) rename {regression_tests => tests/media}/xmlin4/text-stxt-no-mime.nhml (100%) rename {regression_tests => tests/media}/xmlin4/text-stxt.nhml (100%) create mode 100644 tests/rules/bifs-2D-background-background2D-bind-play-ui.xml create mode 100644 tests/rules/bifs-2D-background-background2D-image-play-ui.xml create mode 100644 tests/rules/bifs-2D-background-background2D-movie-play-ui.xml create mode 100644 tests/rules/bifs-2D-background-background2D-url-change-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-discsensor-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-htk-sensor-play-stderr.txt create mode 100644 tests/rules/bifs-2D-interactivity-keysensor-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-mousesensor-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-nested-sensors-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-planesensor2D-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-proximitysensor2D-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-stringsensor-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-touchsensor-4states-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-touchsensor-hitpoint-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-touchsensor-isactive-exposedfield-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-touchsensor-isactive-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-touchsensor-isover-play-ui.xml create mode 100644 tests/rules/bifs-2D-interactivity-touchsensor-move_over-play-ui.xml create mode 100644 tests/rules/bifs-2D-painting-xlineproperties-cap-play-ui.xml create mode 100644 tests/rules/bifs-2D-painting-xlineproperties-join-play-ui.xml create mode 100644 tests/rules/bifs-2D-painting-xlineproperties-lineargradient-play-ui.xml create mode 100644 tests/rules/bifs-2D-painting-xlineproperties-radialgradient-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-clipper2D-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-layer2D-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-layout-scroll-modes-horiz-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-layout-scroll-modes-vert-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-layout-scroll-on-off-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-orderedgroup-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-pathlayout-graphics-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-pathlayout-play-ui.xml create mode 100644 tests/rules/bifs-2D-positioning-transformmatrix2D-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-compositetexture2D-background-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-compositetexture2D-transparent-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-gradients-text-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-gradients-transparent-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-lineargradient-simple-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-lineargradient-spread-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-radialgradient-simple-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-radialgradient-spread-play-ui.xml create mode 100644 tests/rules/bifs-2D-texturing-texturetransform-interact-play-ui.xml create mode 100644 tests/rules/bifs-2D-viewport-simple-play-ui.xml create mode 100644 tests/rules/bifs-3D-interactivity-cylindersensor-play-ui.xml create mode 100644 tests/rules/bifs-3D-interactivity-planesensor-play-ui.xml create mode 100644 tests/rules/bifs-3D-interactivity-proximitysensor-play-ui.xml create mode 100644 tests/rules/bifs-3D-interactivity-spheresensor-play-ui.xml create mode 100644 tests/rules/bifs-3D-interactivity-visibilitysensor-play-ui.xml create mode 100644 tests/rules/bifs-3D-lighting-fog-play-ui.xml create mode 100644 tests/rules/bifs-3D-positioning-layer3D-play-ui.xml create mode 100644 tests/rules/bifs-3D-shapes-box-transparent-play-ui.xml create mode 100644 tests/rules/bifs-3D-shapes-elevationgrid-play-ui.xml create mode 100644 tests/rules/bifs-3D-shapes-extrusion-play-ui.xml create mode 100644 tests/rules/bifs-3D-shapes-nonlineardeformer-play-ui.xml create mode 100644 tests/rules/bifs-3D-texturing-compositetexture3D-bitmap-play-ui.xml create mode 100644 tests/rules/bifs-3D-viewpoint-bind-jump-play-ui.xml create mode 100644 tests/rules/bifs-3D-viewpoint-bind-play-ui.xml create mode 100644 tests/rules/bifs-3D-viewpoint-ortho-bind-play-ui.xml create mode 100644 tests/rules/bifs-bitmap-image-meter-metrics-play-ui.xml create mode 100644 tests/rules/bifs-bitmap-image-pixel-metrics-play-ui.xml create mode 100644 tests/rules/bifs-cachetexture_nocache-play-ui.xml create mode 100644 tests/rules/bifs-command-proto-delete-play-stderr.txt create mode 100644 tests/rules/bifs-command-protolist-delete-play-stderr.txt create mode 100644 tests/rules/bifs-game-arrange-play-ui.xml create mode 100644 tests/rules/bifs-game-arrange.sh create mode 100644 tests/rules/bifs-game-breakout-play-ui.xml create mode 100644 tests/rules/bifs-game-breakout.sh create mode 100644 tests/rules/bifs-game-bubble-play-ui.xml create mode 100644 tests/rules/bifs-game-bubble.sh create mode 100644 tests/rules/bifs-game-minesweeper-play-ui.xml create mode 100644 tests/rules/bifs-game-minesweeper.sh create mode 100644 tests/rules/bifs-game-othello-play-ui.xml create mode 100644 tests/rules/bifs-game-othello.sh create mode 100644 tests/rules/bifs-interpolation-timesensor-enabled-play-ui.xml create mode 100644 tests/rules/bifs-interpolation-timesensor-starttime_norestart-play-ui.xml create mode 100644 tests/rules/bifs-interpolation-timesensor-starttime_restart-play-ui.xml create mode 100644 tests/rules/bifs-keynavigator-play-ui.xml create mode 100644 tests/rules/bifs-linking-inline-direct-inline-play-ui.xml create mode 100644 tests/rules/bifs-linking-inline-od-inline-play-ui.xml create mode 100644 tests/rules/bifs-linking-inline-segment-inline-play-ui.xml create mode 100644 tests/rules/bifs-media-audiobuffer-play-ui.xml create mode 100644 tests/rules/bifs-media-audioclip-play-ui.xml create mode 100644 tests/rules/bifs-media-audioclip-urlchanged-play-ui.xml create mode 100644 tests/rules/bifs-media-audiosource-mixing-play-ui.xml create mode 100644 tests/rules/bifs-media-audiosource-play-ui.xml create mode 100644 tests/rules/bifs-media-audiosource-urlchanged-play-ui.xml create mode 100644 tests/rules/bifs-media-imagetexture-url-change-play-ui.xml create mode 100644 tests/rules/bifs-media-movietexture-control-play-ui.xml create mode 100644 tests/rules/bifs-media-movietexture-url-change-play-ui.xml create mode 100644 tests/rules/bifs-misc-hc-proto-events-play-ui.xml create mode 100644 tests/rules/bifs-misc-non-linear-parsing-conditional-play-ui.xml create mode 100644 tests/rules/bifs-proto-conditional-play-ui.xml create mode 100644 tests/rules/bifs-proto-multiple-play-ui.xml create mode 100644 tests/rules/bifs-proto-nested-play-ui.xml create mode 100644 tests/rules/bifs-proto-route-play-ui.xml create mode 100644 tests/rules/bifs-script-child-create-play-ui.xml create mode 100644 tests/rules/bifs-script-date.sh create mode 100644 tests/rules/bifs-script-load-url-play-ui.xml create mode 100644 tests/rules/bifs-script-node-create-play-ui.xml create mode 100644 tests/rules/bifs-script-proto-play-ui.xml create mode 100644 tests/rules/bifs-storage-play-ui.xml create mode 100644 tests/rules/bifs-stream-text-switch-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-OCR-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-OCR.sh create mode 100644 tests/rules/bifs-timeline-mediacontrol-audio-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-audio-speed-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-complete-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-deactivation-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-http-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-inline-av-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-inline-segments.sh create mode 100644 tests/rules/bifs-timeline-mediacontrol-segments-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-video-play-ui.xml create mode 100644 tests/rules/bifs-timeline-mediacontrol-videospeed-play-ui.xml create mode 100644 tests/rules/laser-stz_animate_hrefstreamid-play-stderr.txt create mode 100644 tests/rules/laser-stz_animate_hrefstreamid2-play-stderr.txt create mode 100644 tests/rules/xmlin-meta-metx-no-namespace-import-stderr.txt create mode 100644 tests/rules/xmlin-subt-stpp-export-track-stderr.txt create mode 100644 tests/rules/xmlin-subt-stpp-no-namespace-import-stderr.txt create mode 100644 tests/rules/xmlin-ttml-stpp-export-track-stderr.txt create mode 100644 tests/scripts/3D-HEVC.sh create mode 100755 tests/scripts/bifs_all.sh create mode 100755 tests/scripts/compositor_modes.sh create mode 100644 tests/scripts/dash-if-live.sh create mode 100644 tests/scripts/dash-if-ondemand.sh create mode 100644 tests/scripts/dash-live-generation.sh create mode 100644 tests/scripts/dash-live.sh create mode 100644 tests/scripts/dash-multiperiod.sh create mode 100644 tests/scripts/dash-ts.sh create mode 100644 tests/scripts/dash.sh create mode 100755 tests/scripts/encryption.sh create mode 100755 tests/scripts/fuzz-base.sh create mode 100644 tests/scripts/hls.sh create mode 100644 tests/scripts/iff.sh create mode 100644 tests/scripts/item.sh create mode 100755 tests/scripts/laser_all.sh create mode 100755 tests/scripts/mp42ts.sh create mode 100755 tests/scripts/mp4box-base.sh create mode 100755 tests/scripts/mp4box-io.sh create mode 100644 tests/scripts/mp4box-kind.sh create mode 100644 tests/scripts/mp4box-lang.sh create mode 100755 tests/scripts/mp4box-rtp.sh create mode 100755 tests/scripts/mp4box-subtitle.sh create mode 100755 tests/scripts/mp4client-base.sh create mode 100644 tests/scripts/mp4client-dash-config.sh create mode 100755 tests/scripts/mp4client-dash.sh create mode 100755 tests/scripts/mp4client-http.sh create mode 100755 tests/scripts/mp4client-rawout.sh create mode 100644 tests/scripts/negctts.sh create mode 100644 tests/scripts/nhml-subs.sh create mode 100644 tests/scripts/noFragsDefault.sh create mode 100644 tests/scripts/range_extension.sh create mode 100755 tests/scripts/scalable.sh create mode 100755 tests/scripts/smooth.sh create mode 100644 tests/scripts/swf.sh create mode 100755 tests/scripts/test_prl.sh create mode 100755 tests/scripts/vtt-all.sh create mode 100755 tests/scripts/x3d.sh create mode 100755 tests/scripts/xmlin.sh create mode 100644 tests/stylesheet.xsl diff --git a/.gitattributes b/.gitattributes index f8c796f..fe272ac 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,3 +17,6 @@ configure text eol=lf *.vcxproj text eol=crlf *.dsp text eol=crlf *.dsw text eol=crlf + +#tests +tests/media/xmlin4/input.txt text eol=crlf diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..2c5bf2e --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +Thanks for reporting your issue. Please make sure these boxes are checked before submitting your issue - thank you! + +- [ ] I looked for a similar issue and couldn't find any. +- [ ] I tried with the latest version of GPAC. Installers available at http://gpac.io/downloads/gpac-nightly-builds/ +- [ ] I give enough information for contributors to reproduce my issue (meaningful title, github labels, platform and compiler, command-line ...). I can share files anonymously with this dropbox: https://www.mediafire.com/filedrop/filedrop_hosted.php?drop=eec9e058a9486fe4e99c33021481d9e1826ca9dbc242a6cfaab0fe95da5e5d95 + +Detailed guidelines: http://gpac.io/2013/07/16/how-to-file-a-bug-properly/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..803dfb7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,90 @@ +*.o +*.suo +*.user +*.userosscache +*.sln.docstates +*.userprefs +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile +*~ +*.plg +*.opt +*.gcno +*.gcda +*.gcov +*.DS_Store + +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + + +.DS_Store .AppleDouble .LSOverride + +*.class + +*.so +*.dylib +*.dll +*.lai +*.la +*.a +*.lib +*.exe +*.out +*.app +*.apk +*.dmg +*.gz +*.deb + +.depend +.deps/ + +#GPAC specific +config.h +include/gpac/revision.h +include/gpac/revision.h.new +extra_lib/lib/ +extra_lib/include/SDL/ +extra_lib/include/ios/ +config.mak +configure-stamp +gpac.pc +tests/external_media/ +tests/results/ + diff --git a/.travis.yml b/.travis.yml index 1f2675f..5047ab9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,49 @@ language: c compiler: gcc -before_install: - - sudo apt-get update -qq +os: + - linux + - osx +before_install: + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get -y update -qq ; fi install: - - sudo apt-get install build-essential fakeroot dpkg-dev devscripts ccache debhelper pkg-config g++ - - sudo apt-get install -y zlib1g-dev libfreetype6-dev libjpeg62-dev libpng12-dev libopenjpeg-dev libmad0-dev libfaad-dev libogg-dev libvorbis-dev libtheora-dev liba52-0.7.4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxv-dev x11proto-video-dev libgl1-mesa-dev x11proto-gl-dev linux-sound-base libxvidcore-dev libssl-dev libjack-dev libasound2-dev libpulse-dev libsdl1.2-dev dvb-apps libavcodec-extra-53 libavdevice-dev libmozjs185-dev - - sudo apt-get install -y gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get -y install build-essential fakeroot dpkg-dev devscripts ccache debhelper pkg-config g++ mesa-utils ; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get -y install -y zlib1g-dev libfreetype6-dev libjpeg62-dev libpng12-dev libopenjpeg-dev libmad0-dev libfaad-dev libogg-dev libvorbis-dev libtheora-dev liba52-0.7.4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavdevice-dev libxv-dev x11proto-video-dev libgl1-mesa-dev x11proto-gl-dev linux-sound-base libxvidcore-dev libssl-dev libjack-dev libasound2-dev libpulse-dev libsdl1.2-dev dvb-apps libavcodec-extra-53 libmozjs185-dev ; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get -y install -y gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev ; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get -qq -y install lcov time; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then sudo chown -R "$USER":admin /usr/local; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi + - 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_PREFIX="--prefix=build/all" GPAC_CONFIGURE_OPTIONS="" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" - - GPAC_CONFIGURE_PREFIX="--prefix=build/disable-all" GPAC_CONFIGURE_OPTIONS="--disable-all" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" - - GPAC_CONFIGURE_PREFIX="--prefix=build/static-mp4box" GPAC_CONFIGURE_OPTIONS="--static-mp4box" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" - - GPAC_CONFIGURE_PREFIX="--prefix=build/static-modules" GPAC_CONFIGURE_OPTIONS="--static-modules" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" GPAC_CONFIGURE_CROSS="" TARGET="" - - GPAC_CONFIGURE_PREFIX="--prefix=build/disable-manual" GPAC_CONFIGURE_OPTIONS="--use-js=no --use-mad=no --use-xvid=no --use-ogg=no --use-vorbis=no --use-theora=no --use-openjpeg=no --disable-streaming --disable-isoff-frag --disable-isoff-hint --disable-isoff-write --disable-loader-xmt --disable-loader-bt --disable-loader-isoff --disable-scene-encode --disable-mcrypt --disable-od-dump --disable-scene-dump --disable-scene-stats --disable-swf --disable-export --disable-import --disable-m2ps --disable-ogg -disable-avi --disable-qtvr --disable-seng --disable-smgr --disable-x3d --disable-3d --disable-ssl --disable-jack --disable-pulse --use-a52=no --disable-odf --disable-isoff --disable-m2ts-mux --disable-dvbx --disable-saf --disable-vobsub --disable-ttxt --disable-od-parse" GPAC_CONFIGURE_ECFLAGS="" GPAC_CONFIGURE_ELDFLAGS="" TARGET="" - - GPAC_CONFIGURE_PREFIX="--prefix=build/i686-w64-mingw32" GPAC_CONFIGURE_OPTIONS="--static-mp4box --use-zlib=no" GPAC_CONFIGURE_ECFLAGS="-Ibuild/i686-w64-mingw32/include -w -fPIC" GPAC_CONFIGURE_ELDFLAGS="-Lbuild/i686-w64-mingw32/lib" GPAC_CONFIGURE_CROSS="--target-os=mingw32 --cross-prefix=i686-w64-mingw32-" TARGET="" - - GPAC_CONFIGURE_PREFIX="--prefix=build/x86_64-w64-mingw32" GPAC_CONFIGURE_OPTIONS="--static-mp4box --use-zlib=no" GPAC_CONFIGURE_ECFLAGS="-Ibuild/x86_64-w64-mingw32/include -w -fPIC" GPAC_CONFIGURE_ELDFLAGS="-Lbuild/x86_64-w64-mingw32/lib" GPAC_CONFIGURE_CROSS="--target-os=mingw32 --cross-prefix=x86_64-w64-mingw32-" TARGET="" - -script: - - ./configure $GPAC_CONFIGURE_PREFIX $GPAC_CONFIGURE_OPTIONS --extra-cflags="$GPAC_CONFIGURE_ECFLAGS" --extra-ldflags="$GPAC_CONFIGURE_ELDFLAGS" && make clean && make $TARGET && make install + - GPAC_CONFIGURE_OPTIONS="--prefix=build/mp4box --enable-debug --static-mp4box" 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="" +matrix: + include: + - os: linux + before_script: + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" + - sleep 3 # give xvfb some time to start + - glxinfo # check glx status + 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="" + - 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="" + - os: linux + env: GPAC_CONFIGURE_OPTIONS="--prefix=build/all --enable-debug --disable-all" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="make install" DOTRAVIS="" + - os: linux + env: GPAC_CONFIGURE_OPTIONS="--enable-debug --use-js=no --use-mad=no --use-xvid=no --use-ogg=no --use-vorbis=no --use-theora=no --use-openjpeg=no --disable-streaming --disable-isoff-frag --disable-isoff-hint --disable-isoff-write --disable-loader-xmt --disable-loader-bt --disable-loader-isoff --disable-scene-encode --disable-mcrypt --disable-od-dump --disable-scene-dump --disable-scene-stats --disable-swf --disable-export --disable-import --disable-m2ps --disable-ogg -disable-avi --disable-qtvr --disable-seng --disable-smgr --disable-x3d --disable-3d --disable-ssl --disable-jack --disable-pulse --use-a52=no --disable-odf --disable-isoff --disable-m2ts-mux --disable-dvbx --disable-saf --disable-vobsub --disable-ttxt --disable-od-parse" GPAC_CONFIGURE_ECFLAGS="" DOINSTALL="" DOTRAVIS="" + - os: osx + 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 && $DOTRAVIS +after_success: + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then bash <(curl -s https://codecov.io/bash) ; fi + +notifications: + email: + recipients: + - travisci@gpac.io + diff --git a/AUTHORS b/AUTHORS index 107c2c5..1dd25b9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,11 +1,28 @@ Author: ======= -Jean Le Feuvre +Jean Le Feuvre Contributors: ============= -Cyril Concolato contributing SVG, SMIL, ISMACryp MP4 support and V4Studio (together with some ENST people) - - -Pierre Souchay for PulseAudio and JACK audio support -Ivan Vecera () for VobSub support +Cyril Concolato +Romain Bouqueau +Pierre Souchay +Viet Tran Trung Nguyen +Emmanouil Potetsianakis +Rodolphe Fouquet +Jérôme Gorin +Arash Shafiei +Ivan Vecera +Jean-Claude Moissinac +Jean-Claude Dufourd +Benoit Pellan +Philippe de Cuetos +Jonathan Sillan +Harlina Daud +Daniel Comalrena +Stanislas Selle +Stéphane Thomas +Ayodeji Aribuki +Yi-Zhen Zhang +Berthele Rodriguez +Yen Chi Hsuan diff --git a/BUGS b/BUGS index 9402234..2785752 100644 --- a/BUGS +++ b/BUGS @@ -1,9 +1,3 @@ BUGS -A bug tracker is available at http://sourceforge.net/projects/gpac/ -BUG REPORTS - -If you find a bug that is not in the list above, please report it at - -http://sourceforge.net/tracker/?group_id=84101&atid=571738 - +A bug tracker is available at https://github.com/gpac/gpac/issues diff --git a/Changelog b/Changelog index 78660d9..6c682c2 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,5 @@ -Full Changelog is available here: -https://sourceforge.net/apps/trac/gpac/log/ +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 - MPEG-DASH and Apple HLS support in GPAC Clients diff --git a/Clean.bat b/Clean.bat index e63123d..e619504 100644 --- a/Clean.bat +++ b/Clean.bat @@ -1,23 +1,23 @@ -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 .. - - - - +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/INSTALLME b/INSTALLME index d6d61b0..9f7eb51 100644 --- a/INSTALLME +++ b/INSTALLME @@ -1,10 +1,10 @@ Installation instructions for latest GPAC GIT version - March 2015: -For Windows, Linux and Mac OS X versions, follow the instructions on http://gpac.sourceforge.net/home_download.php +For Windows, Linux and Mac OS X versions, follow the instructions on http://gpac.io/downloads/ For Android, follow the instructions in gpac/build/android/README -(WindowsMobile platform i sno longer maintained) +(WindowsMobile platform is no longer maintained) For WindowsMobile platform, get the latest package of gpac extra libs available here: https://sourceforge.net/p/gpac/code/HEAD/tree/trunk/gpac_extra_libs/ @@ -23,8 +23,8 @@ limited (no still image, no audio, no video, no text, no scripting). It is there extra lib package available at http://sourceforge.net/projects/gpac. Compilation instructions for these libraries are provided per library in the package. - The current extra_lib package to use with gpac 0.5.0 and above is gpac_extra_libs available here: -https://sourceforge.net/p/gpac/code/HEAD/tree/trunk/gpac_extra_libs/ + The current extra_lib package to use with gpac is gpac_extra_libs available here: +http://download.tsi.telecom-paristech.fr/gpac/gpac_extra_libs.zip In case you have some of these libs already installed on your system, the detailed list of dependencies is * freetype2 from version 2.1.4 on. @@ -33,7 +33,7 @@ https://sourceforge.net/p/gpac/code/HEAD/tree/trunk/gpac_extra_libs/ * Libpng version 1.2.33 (older versions should work) * MAD version 0.15.1b (older versions should work) * xvid version 1.0 (0.9.0 / .1 / .2 should also work) - * ffmpeg (latest stable API version checked was 08 February 2007 snapshot, you may need to change a few things with current versions) + * ffmpeg (latest stable API version checked was 17 February 2016 snapshot, you may need to change a few things with current versions) * libogg 1.1, libvorbis 1.1 and libtheora 1.0 from Xiph.org (newer versions work) * faad2, version 2.0 or above (2.6.1 working) * liba52, version 0.7.4 @@ -65,5 +65,3 @@ Detailed instruction for iOS Compilation are available in gpac/build/xcode/READM GPAC's client configuration is documented in gpac/doc/configuration.html MP4Box documentation is available online at http://gpac.sourceforge.net - - diff --git a/Makefile b/Makefile index 62b7850..9849173 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ endif GITREV_PATH:=$(SRC_PATH)/include/gpac/revision.h TAG:=$(shell git --git-dir=$(SRC_PATH)/.git describe --tags --abbrev=0 2> /dev/null) VERSION:=$(shell echo `git --git-dir=$(SRC_PATH)/.git describe --tags --long || echo "UNKNOWN"` | sed "s/^$(TAG)-//") -BRANCH:=$(shell git --git-dir=$(SRC_PATH)/.git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "UNKNOWN") +BRANCH:=$(shell git --git-dir=$(SRC_PATH)/.git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "UNKNOWN") version: @if [ -d $(SRC_PATH)/".git" ]; then \ @@ -57,54 +57,78 @@ distclean: $(MAKE) -C applications distclean $(MAKE) -C modules distclean rm -f config.mak config.h + @find . -type f -name '*.gcno*' -delete + @find . -type f -name '*.gcda*' -delete + @rm -f coverage.info 2> /dev/null + +docs: + @cd $(SRC_PATH)/doc && doxygen + +test_suite: + @cd $(SRC_PATH)/tests && ./make_tests.sh lcov_clean: lcov --directory . --zerocounters -lcov: - lcov --capture --directory . --output-file all.info - rm -rf coverage/ - lcov --remove all.info /usr/pkg/include/gtest/* /usr/pkg/include/gtest/internal/gtest-* \ - /usr/pkg/gcc44/include/c++/4.4.1/backward/binders.h /usr/pkg/gcc44/include/c++/4.4.1/bits/* \ - /usr/pkg/gcc44/include/c++/4.4.1/ext/*.h \ - /usr/pkg/gcc44/include/c++/4.4.1/x86_64-unknown-netbsd4.99.62/bits/gthr-default.h \ - /usr/include/machine/byte_swap.h /usr/pkg/gcc44/include/c++/4.4.1/* \ - /opt/local/include/mozjs185/*.h /usr/include/libkern/i386/*.h /usr/include/sys/_types/*.h /usr/include/*.h \ - --output cover.info - genhtml -o coverage cover.info +lcov_only: + @echo "Generating lcov info in coverage.info" + @rm -f ./gpac-conf-* > /dev/null + @lcov -q -capture --directory . --output-file all.info + @lcov --remove all.info /usr/* /usr/include/* /usr/local/include/* /usr/include/libkern/i386/* /usr/include/sys/_types/* /opt/* /opt/local/include/* /opt/local/include/mozjs185/* --output coverage.info + @rm all.info + @echo "Purging lcov info" + @cd src ; for dir in * ; do cd .. ; sed -i -- "s/$$dir\/$$dir\//$$dir\//g" coverage.info; cd src; done ; cd .. + @echo "Done - coverage.info ready" -dep: depend +lcov: lcov_only + @rm -rf coverage/ + @genhtml -q -o coverage coverage.info + +travis_tests: + @echo "Running tests" + @cd $(SRC_PATH)/tests && ./make_tests.sh -warn -sync-before -# tar release (use 'make -k tar' on a checkouted tree) -FILE=gpac-$(shell grep "\#define GPAC_VERSION " include/gpac/version.h | \ - cut -d "\"" -f 2 ) +travis_deploy: + @echo "Deploying results" + @cd $(SRC_PATH)/tests && ./ghp_deploy.sh -tar: - ( tar zcvf ~/$(FILE).tar.gz ../gpac --exclude CVS --exclude bin --exclude lib --exclude Obj --exclude temp --exclude amr_nb --exclude amr_nb_ft --exclude amr_wb_ft --exclude *.mak --exclude *.o --exclude *.~*) +travis: travis_tests lcov travis_deploy + +dep: depend install: $(INSTALL) -d "$(DESTDIR)$(prefix)" $(INSTALL) -d "$(DESTDIR)$(prefix)/$(libdir)" $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" -ifeq ($(DISABLE_ISOFF), no) -ifeq ($(CONFIG_LINUX), yes) +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 +ifneq ($(MP4BOX_STATIC), yes) + if [ -f bin/gcc/MP42TS$(EXE_SUFFIX) ] ; then \ + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP42TS$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" ; \ + fi +ifneq ($(CONFIG_WIN32), yes) ifneq ($(CONFIG_FFMPEG), no) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/DashCast$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" +ifneq ($(DISABLE_CORE_TOOLS), yes) +ifneq ($(DISABLE_AV_PARSERS), yes) + if [ -f bin/gcc/DashCast$(EXE_SUFFIX)g ] ; then \ + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/DashCast$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" ; \ + fi +endif endif endif endif -ifeq ($(DISABLE_ISOFF), no) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Box$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" -ifneq ($(MP4BOX_STATIC), yes) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP42TS$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" endif endif ifneq ($(MP4BOX_STATIC), yes) ifeq ($(DISABLE_PLAYER), no) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Client$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" + if [ -f bin/gcc/MP4Client$(EXE_SUFFIX) ] ; then \ + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Client$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" ; \ + fi endif endif - if [ -d $(DESTDIR)$(prefix)/$(libdir)/pkgconfig ] ; then \ + if [ -d $(DESTDIR)$(prefix)/$(libdir)/pkgconfig ] ; then \ $(INSTALL) $(INSTFLAGS) -m 644 gpac.pc "$(DESTDIR)$(prefix)/$(libdir)/pkgconfig" ; \ fi $(INSTALL) -d "$(DESTDIR)$(moddir)" @@ -115,35 +139,35 @@ ifneq ($(MP4BOX_STATIC),yes) $(MAKE) installdylib endif $(INSTALL) -d "$(DESTDIR)$(mandir)" - $(INSTALL) -d "$(DESTDIR)$(mandir)/man1"; - if [ -d doc ] ; then \ - $(INSTALL) $(INSTFLAGS) -m 644 doc/man/mp4box.1 $(DESTDIR)$(mandir)/man1/ ; \ - $(INSTALL) $(INSTFLAGS) -m 644 doc/man/mp4client.1 $(DESTDIR)$(mandir)/man1/ ; \ - $(INSTALL) $(INSTFLAGS) -m 644 doc/man/gpac.1 $(DESTDIR)$(mandir)/man1/ ; \ - $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac" ; \ - $(INSTALL) $(INSTFLAGS) -m 644 doc/gpac.mp4 $(DESTDIR)$(prefix)/share/gpac/ ; \ - fi - if [ -d gui ] ; then \ - $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui" ; \ - $(INSTALL) $(INSTFLAGS) -m 644 gui/gui.bt "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ - $(INSTALL) $(INSTFLAGS) -m 644 gui/gui.js "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ - $(INSTALL) $(INSTFLAGS) -m 644 gui/gwlib.js "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ - $(INSTALL) $(INSTFLAGS) -m 644 gui/mpegu-core.js "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ - $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui/icons" ; \ - $(INSTALL) $(INSTFLAGS) -m 644 gui/icons/*.svg "$(DESTDIR)$(prefix)/share/gpac/gui/icons/" ; \ - cp -R gui/extensions "$(DESTDIR)$(prefix)/share/gpac/gui/" ; \ - rm -rf "$(DESTDIR)$(prefix)/share/gpac/gui/extensions/*.git" ; \ - fi + $(INSTALL) -d "$(DESTDIR)$(mandir)/man1" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/doc/man/mp4box.1 $(DESTDIR)$(mandir)/man1/ + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/doc/man/mp4client.1 $(DESTDIR)$(mandir)/man1/ + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/doc/man/gpac.1 $(DESTDIR)$(mandir)/man1/ + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/doc/gpac.mp4 $(DESTDIR)$(prefix)/share/gpac/ + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/gui/gui.bt "$(DESTDIR)$(prefix)/share/gpac/gui/" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/gui/gui.js "$(DESTDIR)$(prefix)/share/gpac/gui/" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/gui/gwlib.js "$(DESTDIR)$(prefix)/share/gpac/gui/" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/gui/mpegu-core.js "$(DESTDIR)$(prefix)/share/gpac/gui/" + $(INSTALL) $(INSTFLAGS) -m 644 $(SRC_PATH)/gui/webvtt-renderer.js "$(DESTDIR)$(prefix)/share/gpac/gui/" + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui/icons" + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/gui/extensions" + $(INSTALL) -d "$(DESTDIR)$(prefix)/share/gpac/shaders/" +ifeq ($(CONFIG_DARWIN),yes) + cp $(SRC_PATH)/gui/icons/* "$(DESTDIR)$(prefix)/share/gpac/gui/icons/" + cp -R $(SRC_PATH)/gui/extensions/* "$(DESTDIR)$(prefix)/share/gpac/gui/extensions/" + cp $(SRC_PATH)/shaders/* "$(DESTDIR)$(prefix)/share/gpac/shaders/" +else + cp --no-preserve=mode,ownership,timestamp $(SRC_PATH)/gui/icons/* $(DESTDIR)$(prefix)/share/gpac/gui/icons/ + cp -R --no-preserve=mode,ownership,timestamp $(SRC_PATH)/gui/extensions/* $(DESTDIR)$(prefix)/share/gpac/gui/extensions/ + cp --no-preserve=mode,ownership,timestamp $(SRC_PATH)/shaders/* $(DESTDIR)$(prefix)/share/gpac/shaders/ +endif lninstall: $(INSTALL) -d "$(DESTDIR)$(prefix)" $(INSTALL) -d "$(DESTDIR)$(prefix)/$(libdir)" $(INSTALL) -d "$(DESTDIR)$(prefix)/bin" -ifeq ($(DISABLE_ISOFF), no) -ifneq ($(CONFIG_FFMPEG), no) - ln -sf $(BUILD_PATH)/bin/gcc/DashCast$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/DashCast$(EXE_SUFFIX) -endif -endif ifeq ($(DISABLE_ISOFF), no) ln -sf $(BUILD_PATH)/bin/gcc/MP4Box$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Box$(EXE_SUFFIX) ln -sf $(BUILD_PATH)/bin/gcc/MP42TS$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP42TS$(EXE_SUFFIX) @@ -152,6 +176,15 @@ ifneq ($(MP4BOX_STATIC),yes) ifeq ($(DISABLE_PLAYER), no) ln -sf $(BUILD_PATH)/bin/gcc/MP4Client$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Client$(EXE_SUFFIX) endif +ifneq ($(CONFIG_WIN32), yes) +ifneq ($(CONFIG_FFMPEG), no) +ifneq ($(DISABLE_CORE_TOOLS), yes) +ifneq ($(DISABLE_AV_PARSERS), yes) + ln -sf $(BUILD_PATH)/bin/gcc/DashCast$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/DashCast$(EXE_SUFFIX) +endif +endif +endif +endif endif ifeq ($(CONFIG_DARWIN),yes) ln -s $(BUILD_PATH)/bin/gcc/libgpac$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_MAJOR) @@ -230,7 +263,7 @@ uninstall-lib: ifeq ($(CONFIG_DARWIN),yes) dmg: - @if [ ! -z "$(shell git diff master..origin/master)" ]; then \ + @if [ ! -z "$(shell git diff FETCH_HEAD)" ]; then \ echo "Local revision and remote revision are not congruent; you may have local commit."; \ echo "Please consider pushing your commit before generating an installer"; \ exit 1; \ @@ -242,7 +275,7 @@ endif ifeq ($(CONFIG_LINUX),yes) deb: - @if [ ! -z "$(shell git diff master..origin/master)" ]; then \ + @if [ ! -z "$(shell git diff FETCH_HEAD)" ]; then \ echo "Local revision and remote revision are not congruent; you may have local commit."; \ echo "Please consider pushing your commit before generating an installer"; \ exit 1; \ @@ -268,7 +301,6 @@ help: @echo @echo "clean: clean src repository" @echo "distclean: clean src repository and host config file" - @echo "tar: create GPAC tarball" @echo @echo "install: install applications and modules on system" @echo "uninstall: uninstall applications and modules" @@ -282,6 +314,11 @@ endif @echo "install-lib: install gpac library (dyn and static) and headers , and " @echo "uninstall-lib: uninstall gpac library (dyn and static) and headers" @echo - @echo "to build libgpac documentation, go to gpac/doc and type 'doxygen'" + @echo "tests: run all tests. For more info, check gpac/regression_tests/test_suite_make.sh -h" + @echo + @echo "lcov: generate lcov files" + @echo "lcov_clean: clean all lcov/gcov files" + @echo + @echo "docs: build libgpac documentation in gpac/doc" -include .depend diff --git a/README b/README deleted file mode 100644 index 1e52c00..0000000 --- a/README +++ /dev/null @@ -1,18 +0,0 @@ -README for GPAC version 0.5.0, May 2012. - -GPAC is a multimedia framework oriented towards rich media and distributed under the LGPL license (see COPYING). -GPAC supports many multimedia formats, from simple audiovisual containers (avi, mov, mpg) to complex -presentation formats (MPEG-4 Systems, SVG Tiny 1.2, VRML/X3D). GPAC supports scripting of presentation for MPEG4/VRML/X3D through -mozilla SpiderMonkey javascript engine. -GPAC currently supports local playback, http progressive download, Adaptive HTTP Streaming (MPEG-DASH, HLS), RTP/RTSP streaming over UDP (unicast or multicast) or TCP and TS demuxing (from file, IP or DVB4Linux). -GPAC also features MP4Box, a multimedia swiss-army knife for the prompt. - -For compilation and installation instruction, check INSTALLME file - -For GPAC configuration instruction, check gpac/doc/configuration.html or gpac/doc/man/gpac.1 (man gpac when installed) - -For more information, visit the GPAC website: - http://gpac.io - - - diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ced437 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +[![Build Status](https://travis-ci.org/gpac/gpac.svg?branch=master)](https://travis-ci.org/gpac/gpac) +[![codecov.io](https://codecov.io/github/gpac/gpac/coverage.svg?branch=master)](https://codecov.io/github/gpac/gpac?branch=master) + +README for GPAC version 0.7.1 + +GPAC is a multimedia framework oriented towards rich media and distributed under the LGPL license (see COPYING). +GPAC supports many multimedia formats, from simple audiovisual containers (avi, mov, mpg) to complex +presentation formats (MPEG-4 Systems, SVG Tiny 1.2, VRML/X3D). GPAC supports scripting of presentation for MPEG4/VRML/X3D through +mozilla SpiderMonkey javascript engine. +GPAC currently supports local playback, http progressive download, Adaptive HTTP Streaming (MPEG-DASH, HLS), RTP/RTSP streaming over UDP (unicast or multicast) or TCP and TS demuxing (from file, IP or DVB4Linux). +GPAC also features MP4Box, a multimedia swiss-army knife for the prompt. + +For compilation and installation instruction, check INSTALLME file + +For GPAC configuration instruction, check gpac/doc/configuration.html or gpac/doc/man/gpac.1 (man gpac when installed) + +For more information, visit the GPAC website: + http://gpac.io + + + diff --git a/TODO b/TODO index 3586187..c68a2f9 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,3 @@ -todo items as of version 0.5.0: - * more work on DASH support - * improve stereo/multiview renderer and texture+depth support - * more work on DIMS/RME and scene generation support - * rearchitecture of modules - * more SVG support (filter , SVG 2.0) - \ No newline at end of file +cf https://github.com/gpac/gpac/issues for ongoing tasks and bugs. + +When filing a request there, please tag it as feature-request. diff --git a/applications/dashcast/Makefile b/applications/dashcast/Makefile index 89eeeda..dc963d9 100644 --- a/applications/dashcast/Makefile +++ b/applications/dashcast/Makefile @@ -4,7 +4,7 @@ vpath %.c $(SRC_PATH)/applications/dashcast CFLAGS= $(OPTFLAGS) -D_GNU_SOURCE -I"$(SRC_PATH)/include" -I../../ $(ffmpeg_cflags) -LINKLIBS=$(GPAC_SH_FLAGS) +LINKFLAGS=$(GPAC_SH_FLAGS) ifeq ($(DEBUGBUILD), yes) CFLAGS+=-g @@ -24,15 +24,6 @@ ifneq ($(CONFIG_LIBAV),no) CFLAGS+=-DGPAC_USE_LIBAV endif -ifneq ($(CONFIG_LIBAVRESAMPLE),no) -CFLAGS+=-DDC_AUDIO_RESAMPLER -LINKLIBS+=-lavresample -endif - - -#common obj -OBJS= dashcast.o audio_data.o audio_decoder.o audio_encoder.o audio_muxer.o circular_buffer.o cmd_data.o controler.o message_queue.o register.o video_data.o video_decoder.o video_encoder.o video_muxer.o video_scaler.o task.o - ifeq ($(CONFIG_WIN32),yes) EXE=.exe PROG=DashCast$(EXE) @@ -41,20 +32,38 @@ EXT= PROG=DashCast endif -LINKLIBS+= $(ffmpeg_lflags) + +ifeq ($(STATICBUILD),yes) +##include static modules and other deps for libgpac +include ../../static.mak +LINKFLAGS+=-lgpac_static +LINKFLAGS+= $(GPAC_SH_FLAGS) +LINKFLAGS+=$(EXTRALIBS) +else +LINKFLAGS+=-lgpac +endif + +#common obj +OBJS= dashcast.o audio_data.o audio_decoder.o audio_encoder.o audio_muxer.o circular_buffer.o cmd_data.o controler.o message_queue.o register.o video_data.o video_decoder.o video_encoder.o video_muxer.o video_scaler.o task.o + +LINKFLAGS+= $(ffmpeg_lflags_dashcast) + +ifneq ($(CONFIG_LIBAVRESAMPLE),no) +CFLAGS+=-DDC_AUDIO_RESAMPLER +LINKFLAGS+=-lavresample +endif ifeq ($(CONFIG_DARWIN), yes) #fixme - use proper detection of libavdevice dependencies -LINKLIBS+=-lavfilter -lswresample -lbz2 +#LINKFLAGS+=-lavfilter -lswresample -lbz2 endif - SRCS := $(OBJS:.o=.c) all: $(PROG) DashCast$(EXE): $(OBJS) - $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(LINKLIBS) + $(CC) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc $(LDFLAGS) $(LINKFLAGS) clean: rm -f $(OBJS) ../../bin/gcc/$(PROG) diff --git a/applications/dashcast/audio_data.c b/applications/dashcast/audio_data.c index 5512d0f..98eb07c 100644 --- a/applications/dashcast/audio_data.c +++ b/applications/dashcast/audio_data.c @@ -57,11 +57,11 @@ int dc_audio_input_data_init(AudioInputData *audio_input_data, int channels, int dc_circular_buffer_create(&audio_input_data->circular_buf, AUDIO_CB_SIZE, mode, num_consumers); for (i = 0; i < AUDIO_CB_SIZE; i++) { - AudioDataNode *audio_data_node = gf_malloc(sizeof(AudioDataNode)); + AudioDataNode *audio_data_node = (AudioDataNode*)gf_malloc(sizeof(AudioDataNode)); audio_input_data->circular_buf.list[i].data = (void *) audio_data_node; audio_data_node->abuf_size = MAX_AUDIO_PACKET_SIZE; - audio_data_node->abuf = gf_malloc(audio_data_node->abuf_size * sizeof(uint8_t)); + audio_data_node->abuf = (uint8_t*)gf_malloc(audio_data_node->abuf_size * sizeof(uint8_t)); } audio_input_data->aframe = FF_ALLOC_FRAME(); @@ -81,7 +81,7 @@ void dc_audio_input_data_destroy(AudioInputData *audio_input_data) int i; if (audio_input_data->circular_buf.list) { for (i = 0; i < AUDIO_CB_SIZE; i++) { - AudioDataNode *audio_data_node = audio_input_data->circular_buf.list[i].data; + AudioDataNode *audio_data_node = (AudioDataNode*)audio_input_data->circular_buf.list[i].data; gf_free(audio_data_node->abuf); gf_free(audio_data_node); } diff --git a/applications/dashcast/audio_data.h b/applications/dashcast/audio_data.h index c2b4e35..3f60bbb 100644 --- a/applications/dashcast/audio_data.h +++ b/applications/dashcast/audio_data.h @@ -91,6 +91,9 @@ typedef struct { char source_id[GF_MAX_PATH]; time_t start_time; time_t end_time; + + /* RFC6381 codec name, only valid when VIDEO_MUXER == GPAC_INIT_VIDEO_MUXER_AVC1 */ + char codec6381[GF_MAX_PATH]; } AudioDataConf; /* diff --git a/applications/dashcast/audio_decoder.c b/applications/dashcast/audio_decoder.c index b5fc1bf..e2d7045 100644 --- a/applications/dashcast/audio_decoder.c +++ b/applications/dashcast/audio_decoder.c @@ -25,14 +25,18 @@ #include "audio_decoder.h" -int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop) +int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop, int video_framerate) { u32 i; AVCodecContext *codec_ctx; AVCodec *codec; AVInputFormat *in_fmt = NULL; - if (audio_data_conf->format && strcmp(audio_data_conf->format,"") != 0) { + if (!audio_data_conf) return -1; + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio Decoder enter setup at UTC "LLU"\n", gf_net_get_utc() )); + + if (strcmp(audio_data_conf->format,"") != 0) { in_fmt = av_find_input_format(audio_data_conf->format); if (in_fmt == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", audio_data_conf->format)); @@ -44,11 +48,37 @@ int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio * Open audio (may already be opened when shared with the video input). */ if (!audio_input_file->av_fmt_ctx) { - if (avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, NULL) != 0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file: %s\n", audio_data_conf->filename)); - return -1; + s32 ret; + AVDictionary *options = NULL; + //we may need to set the framerate when the default one used by ffmpeg is not supported + if (video_framerate > 0) { + char vfr[16]; + snprintf(vfr, sizeof(vfr), "%d", video_framerate); + ret = av_dict_set(&options, "framerate", vfr, 0); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video framerate %s.\n", vfr)); + return -1; + } + } + + ret = avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, options ? &options : NULL); + + if (ret != 0) { + if (options) { + av_dict_free(&options); + options = NULL; + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error %d opening input - retrying without options\n", ret)); + ret = avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, NULL); + } + + if (ret != 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file: %s\n", audio_data_conf->filename)); + return -1; + } } + if (options) av_dict_free(&options); + /* * Retrieve stream information */ @@ -59,6 +89,7 @@ int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio av_dump_format(audio_input_file->av_fmt_ctx, 0, audio_data_conf->filename, 0); } + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio capture open at UTC "LLU"\n", gf_net_get_utc() )); /* * Find the first audio stream @@ -110,6 +141,8 @@ int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio audio_input_file->mode = mode; audio_input_file->no_loop = no_loop; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio Decoder open at UTC "LLU"\n", gf_net_get_utc() )); + return 0; } @@ -178,7 +211,7 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi AVPacket *packet_copy; assert(audio_input_file->av_pkt_list); gf_mx_p(audio_input_file->av_pkt_list_mutex); - packet_copy = gf_list_pop_front(audio_input_file->av_pkt_list); + packet_copy = (AVPacket*)gf_list_pop_front(audio_input_file->av_pkt_list); gf_mx_v(audio_input_file->av_pkt_list_mutex); if (packet_copy == NULL) { @@ -260,12 +293,16 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi audio_input_data->next_pts += ((int64_t)AV_TIME_BASE * audio_input_data->aframe->nb_samples) / codec_ctx->sample_rate; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Decode audio frame pts %d at UTC "LLU"\n", audio_input_data->next_pts, gf_net_get_utc() )); + /* Did we get an audio frame? */ if (got_frame) { uint8_t **data; int data_size; + enum AVSampleFormat sample_format; + Bool resample; #ifdef DC_AUDIO_RESAMPLER - int num_planes_out; + int num_planes_out=0; #endif #ifdef GPAC_USE_LIBAV int sample_rate = codec_ctx->sample_rate; @@ -274,10 +311,21 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi #else int sample_rate = audio_input_data->aframe->sample_rate; int num_channels = audio_input_data->aframe->channels; - u64 channel_layout = audio_input_data->aframe->channel_layout; + u64 channel_layout; + if (!audio_input_data->aframe->channel_layout) { + if (audio_input_data->aframe->channels == 2) { + audio_input_data->aframe->channel_layout = AV_CH_LAYOUT_STEREO; + } else if (audio_input_data->aframe->channels == 1) { + audio_input_data->aframe->channel_layout = AV_CH_LAYOUT_MONO; + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown input channel layout for %d channels. Aborting.\n", audio_input_data->aframe->channels)); + exit(1); + } + } + channel_layout = audio_input_data->aframe->channel_layout; #endif - enum AVSampleFormat sample_format = (enum AVSampleFormat)audio_input_data->aframe->format; - Bool resample = (sample_rate != DC_AUDIO_SAMPLE_RATE + sample_format = (enum AVSampleFormat)audio_input_data->aframe->format; + resample = (sample_rate != DC_AUDIO_SAMPLE_RATE || num_channels != DC_AUDIO_NUM_CHANNELS || channel_layout != DC_AUDIO_CHANNEL_LAYOUT || sample_format != DC_AUDIO_SAMPLE_FORMAT); @@ -297,7 +345,7 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi nb_samp = resample_audio(audio_input_file, audio_input_data, codec_ctx, &output, &num_planes_out, num_channels, sample_format); if (nb_samp<0) { return -1; - } + } av_samples_get_buffer_size(&data_size, DC_AUDIO_NUM_CHANNELS, nb_samp, DC_AUDIO_SAMPLE_FORMAT, 0); data = output; @@ -331,7 +379,6 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi while (av_fifo_size(audio_input_file->fifo) >= LIVE_FRAME_SIZE) { /* Lock the current node in the circular buffer. */ if (dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf) < 0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped an audio frame\n")); continue; } @@ -382,7 +429,7 @@ void dc_audio_decoder_close(AudioInputFile *audio_input_file) if (audio_input_file->av_pkt_list_mutex) { gf_mx_p(audio_input_file->av_pkt_list_mutex); while (gf_list_count(audio_input_file->av_pkt_list)) { - AVPacket *pkt = gf_list_last(audio_input_file->av_pkt_list); + AVPacket *pkt = (AVPacket*)gf_list_last(audio_input_file->av_pkt_list); av_free_packet(pkt); gf_list_rem_last(audio_input_file->av_pkt_list); } diff --git a/applications/dashcast/audio_decoder.h b/applications/dashcast/audio_decoder.h index db094fb..9f155f0 100644 --- a/applications/dashcast/audio_decoder.h +++ b/applications/dashcast/audio_decoder.h @@ -75,7 +75,7 @@ typedef struct { * * @return 0 on success -1 on failure. */ -int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop); +int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop, int video_framerate); /* * Read and decode audio and put samples on circular buffer diff --git a/applications/dashcast/audio_encoder.c b/applications/dashcast/audio_encoder.c index c0d6a79..8d69c40 100644 --- a/applications/dashcast/audio_encoder.c +++ b/applications/dashcast/audio_encoder.c @@ -33,6 +33,7 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud { AVDictionary *opts = NULL; + audio_output_file->audio_data_conf = audio_data_conf; audio_output_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE); audio_output_file->aframe = FF_ALLOC_FRAME(); audio_output_file->adata_buf = (uint8_t*) av_malloc(2 * MAX_AUDIO_PACKET_SIZE); @@ -46,7 +47,7 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud audio_output_file->aframe->format = -1; audio_output_file->codec = avcodec_find_encoder_by_name(audio_data_conf->codec); if (audio_output_file->codec == NULL) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output audio codec not found\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output audio codec %s not found\n", audio_data_conf->codec)); return -1; } @@ -55,7 +56,7 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud audio_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_AUDIO; audio_output_file->codec_ctx->bit_rate = audio_data_conf->bitrate; audio_output_file->codec_ctx->sample_rate = DC_AUDIO_SAMPLE_RATE /*audio_data_conf->samplerate*/; - + { AVRational time_base; time_base.num = 1; @@ -63,12 +64,19 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud audio_output_file->codec_ctx->time_base = time_base; } audio_output_file->codec_ctx->channels = audio_data_conf->channels; - audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; /*FIXME: depends on channels -> http://ffmpeg.org/doxygen/trunk/channel__layout_8c_source.html#l00074*/ + + /*FIXME: depends on channels -> http://ffmpeg.org/doxygen/trunk/channel__layout_8c_source.html#l00074*/ + if (audio_data_conf->channels == 1) { + audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_MONO; + } else { + audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; + } + audio_output_file->codec_ctx->sample_fmt = audio_output_file->codec->sample_fmts[0]; #ifdef DC_AUDIO_RESAMPLER audio_output_file->aresampler = NULL; #endif - if (audio_data_conf->custom) { + if (strcmp(audio_data_conf->custom, "")) { build_dict(audio_output_file->codec_ctx->priv_data, audio_data_conf->custom); } audio_output_file->astream_idx = 0; @@ -233,8 +241,8 @@ int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData * while (av_fifo_size(audio_output_file->fifo) >= audio_output_file->frame_bytes) { #ifdef DC_AUDIO_RESAMPLER - uint8_t **data; //mirror AVFrame::data - int num_planes_out; + uint8_t **data = NULL; //mirror AVFrame::data + int num_planes_out = 0; #endif Bool resample; diff --git a/applications/dashcast/audio_muxer.c b/applications/dashcast/audio_muxer.c index 50ae59e..2374c9d 100644 --- a/applications/dashcast/audio_muxer.c +++ b/applications/dashcast/audio_muxer.c @@ -55,7 +55,7 @@ int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); esd->decoderConfig->streamType = GF_STREAM_AUDIO; if (!strcmp(audio_output_file->codec_ctx->codec->name, "aac")) { //TODO: find an automatic table - esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG2_LCP; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4; esd->decoderConfig->bufferSizeDB = 20; esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate; esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); @@ -152,6 +152,8 @@ int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename return -1; } + ret = gf_media_get_rfc_6381_codec_name(audio_output_file->isof, track, audio_output_file->audio_data_conf->codec6381, GF_FALSE, GF_FALSE); + if (ret != GF_OK) return -1; return 0; } @@ -164,6 +166,8 @@ int dc_gpac_audio_isom_open_seg(AudioOutputFile *audio_output_file, char *filena return -1; } + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio segment %s started at "LLU"\n", filename, gf_net_get_utc() )); + audio_output_file->dts = 0; return 0; @@ -177,7 +181,6 @@ int dc_gpac_audio_isom_write(AudioOutputFile *audio_output_file) audio_output_file->sample->DTS = audio_output_file->dts; //audio_output_file->aframe->pts; audio_output_file->sample->IsRAP = RAP; //audio_output_file->aframe->key_frame;//audio_codec_ctx->coded_frame->key_frame; - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("RAP %d , DTS %ld \n", audio_output_file->sample->IsRAP, audio_output_file->sample->DTS)); ret = gf_isom_fragment_add_sample(audio_output_file->isof, 1, audio_output_file->sample, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0); audio_output_file->dts += audio_output_file->codec_ctx->frame_size; @@ -185,13 +188,6 @@ int dc_gpac_audio_isom_write(AudioOutputFile *audio_output_file) GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_fragment_add_sample\n", gf_error_to_string(ret))); return -1; } - -// ret = gf_isom_flush_fragments(video_output_file->isof, 1); -// if (ret != GF_OK) { -// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_flush_fragments\n", gf_error_to_string(ret))); -// return -1; -// } - return 0; } @@ -203,6 +199,7 @@ int dc_gpac_audio_isom_close_seg(AudioOutputFile *audio_output_file) GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close_segment\n", gf_error_to_string(ret))); return -1; } + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio segment closed at "LLU"\n", gf_net_get_utc() )); //audio_output_file->acc_samples = 0; @@ -411,7 +408,7 @@ GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, return ret; } -int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb) +int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb, Bool insert_ntp) { switch (audio_output_file->muxer_type) { case FFMPEG_AUDIO_MUXER: @@ -421,12 +418,19 @@ int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb) case GPAC_INIT_AUDIO_MUXER: if (frame_nb % audio_output_file->frame_per_frag == 0) { gf_isom_start_fragment(audio_output_file->isof, 1); + + if (insert_ntp) { + gf_isom_set_fragment_reference_time(audio_output_file->isof, 1, audio_output_file->frame_ntp, audio_output_file->first_dts * audio_output_file->codec_ctx->frame_size); + } + gf_isom_set_traf_base_media_decode_time(audio_output_file->isof, 1, audio_output_file->first_dts * audio_output_file->codec_ctx->frame_size); audio_output_file->first_dts += audio_output_file->frame_per_frag; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio start fragment first DTS %u at "LLU"\n", audio_output_file->first_dts, gf_net_get_utc() )); } dc_gpac_audio_isom_write(audio_output_file); if (frame_nb % audio_output_file->frame_per_frag == audio_output_file->frame_per_frag - 1) { gf_isom_flush_fragments(audio_output_file->isof, 1); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio flush fragment first DTS %u at "LLU"\n", audio_output_file->first_dts, gf_net_get_utc() )); } //TODO - do same as video, flush based on time in case of losses if (frame_nb + 1 == audio_output_file->frame_per_seg) { diff --git a/applications/dashcast/audio_muxer.h b/applications/dashcast/audio_muxer.h index 7c1d95e..94151d8 100644 --- a/applications/dashcast/audio_muxer.h +++ b/applications/dashcast/audio_muxer.h @@ -57,7 +57,7 @@ typedef enum { * */ typedef struct { - //AudioDataConf *audio_data_conf; + AudioDataConf *audio_data_conf; /* File format context structure */ AVFormatContext *av_fmt_ctx; @@ -107,6 +107,7 @@ typedef struct { int first_dts; u32 seg_marker; + u64 frame_ntp; } AudioOutputFile; int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag, u32 seg_marker); @@ -124,7 +125,7 @@ void dc_audio_muxer_free(AudioOutputFile *audio_output_file); */ GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg); -GF_Err dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb); +GF_Err dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb, Bool insert_ntp); GF_Err dc_audio_muxer_close(AudioOutputFile *audio_output_file); diff --git a/applications/dashcast/circular_buffer.c b/applications/dashcast/circular_buffer.c index 4f1e6f4..f494c1d 100644 --- a/applications/dashcast/circular_buffer.c +++ b/applications/dashcast/circular_buffer.c @@ -33,7 +33,7 @@ void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode { u32 i; circular_buf->size = size; - circular_buf->list = gf_malloc(size * sizeof(Node)); + circular_buf->list = (Node*)gf_malloc(size * sizeof(Node)); circular_buf->mode = mode; circular_buf->max_num_consumers = max_num_consumers; @@ -78,7 +78,6 @@ int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf) Node *node = &circular_buf->list[consumer->idx]; gf_mx_p(node->mutex); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s enters lock %d\n", consumer->name, consumer->idx)); if (node->marked == 2) { gf_mx_v(node->mutex); return -1; @@ -103,7 +102,6 @@ int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf) } node->num_consumers++; node->num_consumers_accessed++; - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s exits lock %d \n", consumer->name, consumer->idx)); gf_mx_v(node->mutex); return 0; @@ -125,7 +123,6 @@ int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf) gf_sema_notify(node->producers_semaphore, 1); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s unlock %d \n", consumer->name, consumer->idx)); gf_mx_v(node->mutex); return last_consumer; @@ -152,7 +149,6 @@ int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf gf_sema_notify(node->producers_semaphore, 1); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s unlock %d \n", consumer->name, node_idx)); gf_mx_v(node->mutex); return last_consumer; @@ -180,7 +176,6 @@ int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf) Node *node = &circular_buf->list[producer->idx]; gf_mx_p(node->mutex); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s enters lock %d \n", producer->name, producer->idx)); if ( (circular_buf->mode == LIVE_CAMERA || circular_buf->mode == LIVE_MEDIA) && (node->num_consumers || node->marked)) { gf_mx_v(node->mutex); @@ -198,7 +193,6 @@ int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf) node->marked = 1; } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s exits lock %d \n", producer->name, producer->idx)); gf_mx_v(node->mutex); return 0; @@ -211,7 +205,6 @@ void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf) gf_mx_p(node->mutex); node->num_producers--; gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s unlock %d \n", producer->name, producer->idx)); gf_mx_v(node->mutex); } @@ -223,7 +216,6 @@ void dc_producer_unlock_previous(Producer *producer, CircularBuffer *circular_bu gf_mx_p(node->mutex); node->num_producers = 0; gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s unlock %d \n", producer->name, node_idx)); gf_mx_v(node->mutex); } diff --git a/applications/dashcast/cmd_data.c b/applications/dashcast/cmd_data.c index 176369f..1754d0b 100644 --- a/applications/dashcast/cmd_data.c +++ b/applications/dashcast/cmd_data.c @@ -153,8 +153,12 @@ static void dc_create_configuration(CmdData *cmd_data) gf_cfg_set_key(conf, section_name, "channels", value); } - if (!gf_cfg_get_key(conf, section_name, "codec")) - gf_cfg_set_key(conf, section_name, "codec", DEFAULT_AUDIO_CODEC); + if (!gf_cfg_get_key(conf, section_name, "codec")) { + if (strlen(cmd_data->audio_data_conf.codec)) + gf_cfg_set_key(conf, section_name, "codec", cmd_data->audio_data_conf.codec); + else + gf_cfg_set_key(conf, section_name, "codec", DEFAULT_AUDIO_CODEC); + } } } } @@ -228,14 +232,14 @@ int dc_read_configuration(CmdData *cmd_data) fprintf(stdout, "\33[34m\33[1m"); fprintf(stdout, "Configurations:\n"); for (i=0; ivideo_lst); i++) { - VideoDataConf *video_data_conf = gf_list_get(cmd_data->video_lst, i); + VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_get(cmd_data->video_lst, i); fprintf(stdout, " id:%s\tres:%dx%d\tvbr:%d\n", video_data_conf->filename, video_data_conf->width, video_data_conf->height, video_data_conf->bitrate/*, video_data_conf->framerate, video_data_conf->codec*/); } for (i=0; iaudio_lst); i++) { - AudioDataConf *audio_data_conf = gf_list_get(cmd_data->audio_lst, i); + AudioDataConf *audio_data_conf = (AudioDataConf*)gf_list_get(cmd_data->audio_lst, i); fprintf(stdout, " id:%s\tabr:%d\n", audio_data_conf->filename, audio_data_conf->bitrate/*, audio_data_conf->samplerate, audio_data_conf->channels,audio_data_conf->codec*/); } fprintf(stdout, "\33[0m"); @@ -287,7 +291,7 @@ int dc_read_switch_config(CmdData *cmd_data) const char *section_type = gf_cfg_get_key(conf, section_name, "type"); if (strcmp(section_type, "video") == 0) { - VideoDataConf *video_data_conf = gf_malloc(sizeof(VideoDataConf)); + VideoDataConf *video_data_conf = (VideoDataConf*)gf_malloc(sizeof(VideoDataConf)); strcpy(video_data_conf->source_id, section_name); strcpy(video_data_conf->filename, gf_cfg_get_key(conf, section_name, "source")); @@ -307,7 +311,7 @@ int dc_read_switch_config(CmdData *cmd_data) } else if (strcmp(section_type, "audio") == 0) { - AudioDataConf *audio_data_conf = gf_malloc(sizeof(AudioDataConf)); + AudioDataConf *audio_data_conf = (AudioDataConf*)gf_malloc(sizeof(AudioDataConf)); strcpy(audio_data_conf->source_id, section_name); strcpy(audio_data_conf->filename, gf_cfg_get_key(conf, section_name, "source")); @@ -328,14 +332,14 @@ int dc_read_switch_config(CmdData *cmd_data) fprintf(stdout, "\33[34m\33[1m"); fprintf(stdout, "Sources:\n"); for (i=0; ivsrc); i++) { - VideoDataConf *video_data_conf = gf_list_get(cmd_data->vsrc, i); + VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_get(cmd_data->vsrc, i); strftime(start_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&video_data_conf->start_time)); strftime(end_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&video_data_conf->end_time)); fprintf(stdout, " id:%s\tsource:%s\tstart:%s\tend:%s\n", video_data_conf->source_id, video_data_conf->filename, start_time, end_time); } for (i=0; iasrc); i++) { - AudioDataConf *audio_data_conf = gf_list_get(cmd_data->asrc, i); + AudioDataConf *audio_data_conf = (AudioDataConf*)gf_list_get(cmd_data->asrc, i); strftime(start_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&audio_data_conf->start_time)); strftime(end_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&audio_data_conf->end_time)); fprintf(stdout, " id:%s\tsource:%s\tstart:%s\tend:%s\n", audio_data_conf->source_id, audio_data_conf->filename, start_time, end_time); @@ -356,7 +360,7 @@ void dc_cmd_data_init(CmdData *cmd_data) cmd_data->ast_offset = -1; cmd_data->min_buffer_time = -1; cmd_data->minimum_update_period = -1; - cmd_data->use_source_timing = 1; + cmd_data->use_source_timing = GF_TRUE; cmd_data->audio_lst = gf_list_new(); cmd_data->video_lst = gf_list_new(); @@ -367,14 +371,14 @@ void dc_cmd_data_init(CmdData *cmd_data) void dc_cmd_data_destroy(CmdData *cmd_data) { while (gf_list_count(cmd_data->audio_lst)) { - AudioDataConf *audio_data_conf = gf_list_last(cmd_data->audio_lst); + AudioDataConf *audio_data_conf = (AudioDataConf*)gf_list_last(cmd_data->audio_lst); gf_list_rem_last(cmd_data->audio_lst); gf_free(audio_data_conf); } gf_list_del(cmd_data->audio_lst); while (gf_list_count(cmd_data->video_lst)) { - VideoDataConf *video_data_conf = gf_list_last(cmd_data->video_lst); + VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_last(cmd_data->video_lst); gf_list_rem_last(cmd_data->video_lst); gf_free(video_data_conf); } @@ -392,16 +396,16 @@ void dc_cmd_data_destroy(CmdData *cmd_data) gf_sys_close(); } -static void on_dc_log(void *cbk, u32 ll, u32 lm, const char *av_fmt_ctx, va_list list) +static void on_dc_log(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *av_fmt_ctx, va_list list) { - FILE *logs = cbk; + FILE *logs = (FILE*)cbk; vfprintf(logs, av_fmt_ctx, list); fflush(logs); } int dc_parse_command(int argc, char **argv, CmdData *cmd_data) { - Bool use_mem_track = GF_FALSE; + GF_MemTrackerType mem_track = GF_MemTrackerNone; int i; const char *command_usage = @@ -413,6 +417,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) " -logs LOGS set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" #ifdef GPAC_MEMORY_TRACKING " -mem-track enable the memory tracker\n" + " -mem-track-stack enable the memory tracker with stack dumping\n" #endif " -conf filename set the configuration file name (default: dashcast.conf)\n" " -switch-source filename set the configuration file name for source switching\n" @@ -422,7 +427,8 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) " -live-media system is live and input is a media file\n" " -no-loop system does not loop on the input media file when live\n" " -dynamic-ast changes segment availability start time at each MPD generation (old behaviour but not allowed in most profiles)\n" - " -insert-utc inserts UTC clock at the start of each segment\n" + " -insert-utc inserts UTC clock at the start of each segment\n" + " -no-rewrite Do not rewrite the MPD as a static one at the end of the live session\n" "\n" "Source options:\n" " -npts use frame counting for timestamps (not error-free) instead of source timing (default)\n" @@ -437,7 +443,6 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) " - if input is from stdin, use \"pipe:\"\n" " -vf string set the input video format\n" #ifdef WIN32 - " - to capture from a VfW webcam, set vfwcap\n" " - to capture from a directshow device, set dshow\n" #else " - to capture from a webcam, set video4linux2\n" @@ -449,6 +454,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) " -vfr N force the input video framerate\n" " -vres WxH force the video resolution (e.g. 640x480)\n" " -vcrop XxY crop the source video from X pixels left and Y pixels top. Must be used with -vres.\n" + " -demux-buffer SIZE sets demux buffer size to SIZE.\n" "* Audio options:\n" " -a string set the source name for an audio input\n" " - if input is from microphone, use \"plughw:[x],[y]\"\n" @@ -476,7 +482,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) "\n" "DASH options:\n" " -seg-dur dur:int set the segment duration in millisecond (default value: 1000)\n" - " -frag dur:int set the fragment duration in millisecond (default value: 1000) (same as -frag-dur)\n" + " -frag dur:int set the fragment duration in millisecond (default value: 1000) (same as -frag-dur)\n" " -seg-marker marker:4cc add a marker box named marker at the end of DASH segment\n" " -out outdir:str outdir is the output data directory (default: output)\n" " -mpd mpdname:str mpdname is the MPD file name (default: dashcast.mpd)\n" @@ -493,12 +499,11 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) " DashCast -av test.avi -live-media\n" " DashCast -a test_audio.mp3 -v test_audio.mp4 -live-media\n" #ifdef WIN32 - " DashCast -vf vfwcap -vres 1280x720 -vfr 24 -v 0 -live\n" " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"screen-capture-recorder\" -live (please install http://screencapturer.sf.net/)\n" - " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"YOUR-WEBCAM\" -pixf yuv420p -live\n" + " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"YOUR-WEBCAM\" -pixf yuv420p -live (see https://trac.ffmpeg.org/wiki/DirectShow)\n" #elif defined(__DARWIN) || defined(__APPLE__) - " DashCast -vf avfoundation -vres 1280x720 -v \"FaceTime HD Camera\" -vfr 25 -live\n" - " DashCast -vf avfoundation -vres 1280x720 -v \"Capture screen 0\" -vfr 25 -live\n" + " DashCast -vf avfoundation -vres 1280x720 -v \"FaceTime HD Camera\" -vfr 25 -live\n" + " DashCast -vf avfoundation -vres 1280x720 -v \"Capture screen 0\" -vfr 25 -live\n" #else " DashCast -vf video4linux2 -vres 1280x720 -vfr 24 -v4l2f mjpeg -v /dev/video0 -af alsa -a plughw:1,0 -live\n" " DashCast -vf x11grab -vres 800x600 -vfr 25 -v :0.0 -live\n" @@ -515,24 +520,28 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) #ifdef GPAC_MEMORY_TRACKING i = 1; while (i < argc) { - if (strcmp(argv[i], "-mem-track") == 0) { - use_mem_track = GF_TRUE; - break; - } + if (strcmp(argv[i], "-mem-track") == 0) { + mem_track = GF_MemTrackerSimple; + break; + } + else if (strcmp(argv[i], "-mem-track-stack") == 0) { + mem_track = GF_MemTrackerBackTrace; + break; + } i++; } #endif - gf_sys_init(use_mem_track); + gf_sys_init(mem_track); gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); - if (use_mem_track) { + if (mem_track) { gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); } /* Initialize command data */ dc_cmd_data_init(cmd_data); - cmd_data->use_mem_track = use_mem_track; + cmd_data->mem_track = mem_track; i = 1; while (i < argc) { @@ -753,6 +762,10 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) } cmd_data->min_buffer_time = (float)atof(argv[i]); i++; + } else if (strcmp(argv[i], "-demux-buffer") == 0) { + DASHCAST_CHECK_NEXT_ARG + cmd_data->video_data_conf.demux_buffer_size = (int)atoi(argv[i]); + i++; } else if (strcmp(argv[i], "-base-url") == 0) { DASHCAST_CHECK_NEXT_ARG if (strcmp(cmd_data->base_url, "") != 0) { @@ -769,7 +782,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) cmd_data->mode = LIVE_CAMERA; i++; } else if (strcmp(argv[i], "-npts") == 0) { - cmd_data->use_source_timing = 0; + cmd_data->use_source_timing = GF_FALSE; i++; } else if (strcmp(argv[i], "-live-media") == 0) { cmd_data->mode = LIVE_MEDIA; @@ -780,6 +793,9 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) } else if (strcmp(argv[i], "-insert-utc") == 0) { cmd_data->insert_utc = 1; i++; + } else if (strcmp(argv[i], "-no-rewrite") == 0) { + cmd_data->no_mpd_rewrite = 1; + i++; } else if (strcmp(argv[i], "-dynamic-ast") == 0) { cmd_data->use_dynamic_ast = 1; i++; @@ -794,10 +810,10 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) return 1; } i++; - } else if (strcmp(argv[i], "-mem-track") == 0) { + } else if (!strcmp(argv[i], "-mem-track") || !strcmp(argv[i], "-mem-track-stack") ) { i++; #ifndef GPAC_MEMORY_TRACKING - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("WARNING - GPAC not compiled with Memory Tracker - ignoring \"%s\"\n", argv[i])); #endif } else if (!strcmp(argv[i], "-lf") || !strcmp(argv[i], "-log-file")) { DASHCAST_CHECK_NEXT_ARG @@ -865,7 +881,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) if ((cmd_data->minimum_update_period == -1) && (cmd_data->mode == LIVE_CAMERA)) { fprintf(stderr, "MPD refresh time not set in live - defaulting to segment duration\n"); - cmd_data->minimum_update_period = cmd_data->seg_dur; + cmd_data->minimum_update_period = cmd_data->seg_dur / 1000; } //safety checks diff --git a/applications/dashcast/cmd_data.h b/applications/dashcast/cmd_data.h index 73bdbf4..61869d0 100644 --- a/applications/dashcast/cmd_data.h +++ b/applications/dashcast/cmd_data.h @@ -108,7 +108,8 @@ typedef struct { int insert_utc; Bool use_source_timing; - Bool use_mem_track; + GF_MemTrackerType mem_track; + Bool no_mpd_rewrite; } CmdData; /* diff --git a/applications/dashcast/controler.c b/applications/dashcast/controler.c index 08d5601..1cab9d7 100644 --- a/applications/dashcast/controler.c +++ b/applications/dashcast/controler.c @@ -52,7 +52,6 @@ typedef struct { //#define MAX_SOURCE_NUMBER 20 -#define DASHER 0 #define FRAGMENTER 0 //#define DEBUG 1 @@ -66,8 +65,6 @@ typedef struct { //#define AUDIO_MUXER GPAC_AUDIO_MUXER #define AUDIO_MUXER GPAC_INIT_AUDIO_MUXER -#define DASHCAST_PRINT - #define AUDIO_FRAME_SIZE 1024 @@ -79,7 +76,7 @@ void optimize_seg_frag_dur(int *seg, int *frag) if (!frag_nb) frag_nb = 1; min_rem = seg_nb % frag_nb; - + if (seg_nb % (frag_nb + 1) < min_rem) { min_rem = seg_nb % (frag_nb + 1); *seg = seg_nb; @@ -103,7 +100,7 @@ void optimize_seg_frag_dur(int *seg, int *frag) Bool change_source_thread(void *params) { - int ret = 0; + Bool ret = GF_FALSE; return ret; } @@ -132,26 +129,35 @@ u32 send_frag_event(void *params) static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, const VideoDataConf *video_data_conf, const char *presentation_duration, const char *availability_start_time, const char *time_shift, const int segnum, const int ast_offset) { - u32 i = 0; + u32 i = 0, sec; int audio_seg_dur = 0, video_seg_dur = 0, audio_frag_dur = 0, video_frag_dur = 0; int audio_frame_size = AUDIO_FRAME_SIZE; + time_t gtime; + struct tm *t; FILE *f; char name[GF_MAX_PATH]; + snprintf(name, sizeof(name), "%s/%s", cmddata->out_dir, cmddata->mpd_filename); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Write MPD at UTC "LLU" ms - %s : %s\n", gf_net_get_utc(), (cmddata->mode == ON_DEMAND) ? "mediaPresentationDuration" : "availabilityStartTime", (cmddata->mode == ON_DEMAND) ? presentation_duration : availability_start_time)); + if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { - audio_data_conf = gf_list_get(cmddata->audio_lst, 0); - audio_seg_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->seg_dur / 1000.0)); - audio_frag_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->frag_dur / 1000.0)); - optimize_seg_frag_dur(&audio_seg_dur, &audio_frag_dur); + audio_data_conf = (const AudioDataConf*)gf_list_get(cmddata->audio_lst, 0); + if (audio_data_conf) { + audio_seg_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->seg_dur / 1000.0)); + audio_frag_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->frag_dur / 1000.0)); + optimize_seg_frag_dur(&audio_seg_dur, &audio_frag_dur); + } } if (strcmp(cmddata->video_data_conf.filename, "") != 0) { - video_data_conf = gf_list_get(cmddata->video_lst, 0); - video_seg_dur = (int)(video_data_conf->framerate * (cmddata->seg_dur / 1000.0)); - video_frag_dur = (int)(video_data_conf->framerate * (cmddata->frag_dur / 1000.0)); - optimize_seg_frag_dur(&video_seg_dur, &video_frag_dur); + video_data_conf = (VideoDataConf*)gf_list_get(cmddata->video_lst, 0); + if (video_data_conf) { + video_seg_dur = (int)(video_data_conf->framerate * (cmddata->seg_dur / 1000.0)); + video_frag_dur = (int)(video_data_conf->framerate * (cmddata->frag_dur / 1000.0)); + optimize_seg_frag_dur(&video_seg_dur, &video_frag_dur); + } } f = gf_fopen(name, "w"); @@ -166,20 +172,28 @@ static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, // fprintf(stdout, "%s \n", availability_start_time); fprintf(f, "\n"); - fprintf(f, "mode == ON_DEMAND) ? "mediaPresentationDuration" : "availabilityStartTime", - (cmddata->mode == ON_DEMAND) ? presentation_duration : availability_start_time, - cmddata->min_buffer_time, time_shift, - (cmddata->mode == ON_DEMAND) ? "static" : "dynamic"); - if (cmddata->minimum_update_period > 0 ) { - fprintf(f, " minimumUpdatePeriod=\"PT%dS\"", cmddata->minimum_update_period); + fprintf(f, "min_buffer_time); + + if (cmddata->mode == ON_DEMAND) { + fprintf(f, " type=\"static\" mediaPresentationDuration=\"%s\"", presentation_duration); + } else { + fprintf(f, " type=\"dynamic\" availabilityStartTime=\"%s\"", availability_start_time); + if (time_shift) fprintf(f, " timeShiftBufferDepth=\"%s\"", time_shift); + + if (cmddata->minimum_update_period > 0) + fprintf(f, " minimumUpdatePeriod=\"PT%dS\"", cmddata->minimum_update_period); + + gf_net_get_ntp(&sec, NULL); + gtime = sec - GF_NTP_SEC_1900_TO_1970; + t = gmtime(>ime); + fprintf(f, " publishTime=\"%d-%02d-%02dT%02d:%02d:%02dZ\"", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + } + fprintf(f, ">\n"); + fprintf(f, - " \n" + " \n" " %s\n" " \n", cmddata->mpd_filename); @@ -209,11 +223,11 @@ static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, for (i = 0; i < gf_list_count(cmddata->audio_lst); i++) { - audio_data_conf = gf_list_get(cmddata->audio_lst, i); + audio_data_conf = (const AudioDataConf*)gf_list_get(cmddata->audio_lst, i); fprintf(f, - " \n" - " \n", audio_data_conf->filename, audio_data_conf->samplerate, audio_data_conf->bitrate); + " \n", audio_data_conf->filename, audio_data_conf->codec6381, audio_data_conf->samplerate, audio_data_conf->bitrate); } fprintf(f, " \n"); @@ -234,7 +248,7 @@ static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, fprintf(f, "/>\n"); for (i = 0; i < gf_list_count(cmddata->video_lst); i++) { - video_data_conf = gf_list_get(cmddata->video_lst, i); + video_data_conf = (VideoDataConf*)gf_list_get(cmddata->video_lst, i); fprintf(f, " \n" " \n", video_data_conf->filename, @@ -264,12 +278,15 @@ static u32 mpd_thread(void *params) AudioDataConf *audio_data_conf = NULL; VideoDataConf *video_data_conf = NULL; struct tm ast_time; - + int dur = 0; + int h, m, s, ms; + segtime last_seg_time; segtime main_seg_time; Bool first = GF_TRUE; main_seg_time.segnum = 0; main_seg_time.utc_time = 0; main_seg_time.ntpts = 0; + last_seg_time = main_seg_time; if (cmddata->mode == LIVE_CAMERA || cmddata->mode == LIVE_MEDIA) { while (1) { @@ -278,49 +295,53 @@ static u32 mpd_thread(void *params) segtime seg_time; seg_time.segnum = 0; seg_time.utc_time = 0; + seg_time.ntpts = 0; if (cmddata->exit_signal) { break; } - - if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { - dc_message_queue_get(mq, &seg_time); - } - + if (strcmp(cmddata->video_data_conf.filename, "") != 0) { - if (dc_message_queue_get(mq, &seg_time)<0) { + if (dc_message_queue_get(mq, &seg_time) < 0) { continue; } - - if (cmddata->ast_offset>0) { - seg_time.utc_time += cmddata->ast_offset; + } + + if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { + if (dc_message_queue_get(mq, &seg_time) < 0) { + continue; } + } + assert(seg_time.ntpts); - if (cmddata->use_dynamic_ast) { + if (cmddata->use_dynamic_ast) { + main_seg_time = seg_time; + } else { + //get the last notification of AST + if (first) { main_seg_time = seg_time; - } else { - //get the last notification of AST - if (first) { - if (seg_time.segnum) { - first = GF_FALSE; - } else { - main_seg_time = seg_time; - } - } else { - assert(seg_time.segnum); - } + first = GF_FALSE; } + assert(main_seg_time.ntpts); } - + last_seg_time = seg_time; + assert(main_seg_time.ntpts <= seg_time.ntpts); + t = (seg_time.ntpts >> 32) - GF_NTP_SEC_1900_TO_1970; msecs = (u32) ( (seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) ); ast_time = *gmtime(&t); fprintf(stdout, "Generating MPD at %d-%02d-%02dT%02d:%02d:%02d.%03dZ\n", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Generating MPD at %d-%02d-%02dT%02d:%02d:%02d.%03dZ - UTC "LLU" ms - AST UTC "LLU" ms\n", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs, seg_time.utc_time, main_seg_time.utc_time)); t = (main_seg_time.ntpts >> 32) - GF_NTP_SEC_1900_TO_1970; + if (cmddata->ast_offset>0) { + t += cmddata->ast_offset/1000; + } msecs = (u32) ( (main_seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) ); ast_time = *gmtime(&t); + assert(ast_time.tm_year); + sprintf(availability_start_time, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs); fprintf(stdout, "StartTime: %s - startNumber %d - last number %d\n", availability_start_time, main_seg_time.segnum+1, seg_time.segnum+1); @@ -331,13 +352,27 @@ static u32 mpd_thread(void *params) ts = ts % 3600; m = ts / 60; s = ts % 60; - snprintf(time_shift, sizeof(time_shift), "timeShiftBufferDepth=\"PT%02dH%02dM%02dS\"", h, m, s); + snprintf(time_shift, sizeof(time_shift), "PT%02dH%02dM%02dS", h, m, s); } dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, time_shift, main_seg_time.segnum+1, cmddata->ast_offset); } + + if (cmddata->no_mpd_rewrite) return 0; + + //finally rewrite the MPD to static + dur = cmddata->seg_dur * (last_seg_time.segnum - main_seg_time.segnum); + if (cmddata->time_shift) { + if (dur > cmddata->time_shift * 1000) { + u32 nb_seg = cmddata->time_shift*1000 / cmddata->seg_dur; + main_seg_time.segnum = last_seg_time.segnum - nb_seg; + //dur = cmddata->time_shift; + } + dur = cmddata->seg_dur * (last_seg_time.segnum - main_seg_time.segnum); + } + cmddata->mode = ON_DEMAND; + } else { - int a_dur = 0; int v_dur = 0; @@ -348,22 +383,22 @@ static u32 mpd_thread(void *params) if (strcmp(cmddata->video_data_conf.filename, "") != 0) { dc_message_queue_get(mq, &v_dur); } - - { - int dur, h, m, s, ms; - dur = v_dur > a_dur ? v_dur : a_dur; - h = dur / 3600000; - dur = dur % 3600000; - m = dur / 60000; - dur = dur % 60000; - s = dur / 1000; - ms = dur % 1000; - snprintf(presentation_duration, sizeof(presentation_duration), "PT%02dH%02dM%02d.%03dS", h, m, s, ms); - fprintf(stdout, "Duration: %s\n", presentation_duration); - } - - dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, time_shift, 0, cmddata->ast_offset); + + dur = v_dur > a_dur ? v_dur : a_dur; } + + + h = dur / 3600000; + dur = dur % 3600000; + m = dur / 60000; + dur = dur % 60000; + s = dur / 1000; + ms = dur % 1000; + snprintf(presentation_duration, sizeof(presentation_duration), "PT%02dH%02dM%02d.%03dS", h, m, s, ms); + fprintf(stdout, "Duration: %s\n", presentation_duration); + + + dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, 0, main_seg_time.segnum+1, 0); return 0; } @@ -381,7 +416,6 @@ u32 delete_seg_thread(void *params) ret = dc_message_queue_get(mq, (void*) buff); if (ret > 0) { int status; - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Message received: %s\n", buff)); status = unlink(buff); if (status != 0) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unable to delete the file %s\n", buff)); @@ -398,7 +432,7 @@ u32 delete_seg_thread(void *params) Bool fragmenter_thread(void *params) { - int ret; +// int ret; ThreadParam *th_param = (ThreadParam*)params; CmdData *cmd_data = th_param->in_data; MessageQueue *mq = th_param->mq; @@ -406,145 +440,13 @@ Bool fragmenter_thread(void *params) char buff[GF_MAX_PATH]; while (1) { - ret = dc_message_queue_get(mq, (void*) buff); - if (ret > 0) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Message received: %s\n", buff)); - } - + /*ret = */dc_message_queue_get(mq, (void*) buff); if (cmd_data->exit_signal) { break; } } - return 0; -} - -Bool dasher_thread(void *params) -{ -// int i; -// ThreadParam *th_param = (ThreadParam *) params; -// CmdData *cmd_data = th_param->in_data; -// -// char sz_mpd[GF_MAX_PATH]; -// GF_DashSegmenterInput *dash_inputs; -// u32 nb_dash_inputs = 0; -// Bool use_url_template = 0; -// GF_Err e; -// s32 subsegs_per_sidx = 0; -// Bool daisy_chain_sidx = 0; -// char *seg_ext = NULL; -// const char *dash_title = NULL; -// const char *dash_source = NULL; -// const char *dash_more_info = NULL; -// char *tmpdir = NULL, *cprt = NULL, *seg_name = NULL; -// char **mpd_base_urls = NULL; -// u32 nb_mpd_base_urls = 0; -// Bool single_segment = 0; -// -// Bool single_file = 0; -// GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_INBAND; -// Bool seg_at_rap = 0; -// Bool frag_at_rap = 0; -// -// Double interleaving_time = 0.0; -// u32 time_shift_depth = 0; -// Double dash_duration = 0.0, dash_subduration = 0.0; -// u32 mpd_update_time = 0; -// -// -// GF_DashProfile dash_profile = GF_DASH_PROFILE_UNKNOWN; -// u32 dash_dynamic = 0; -// GF_Config *dash_ctx = NULL; -// -// int video_list_size = gf_list_count(cmd_data->video_lst); -// int audio_list_size = gf_list_count(cmd_data->audio_lst); -// nb_dash_inputs = video_list_size + audio_list_size; -// -// dash_inputs = gf_malloc(nb_dash_inputs * sizeof(GF_DashSegmenterInput)); -// -// for (i = 0; i < video_list_size; i++) { -// -// VideoDataConf *video_data_conf = gf_list_get(cmd_data->video_lst, i); -// dash_inputs[i].file_name = video_data_conf->filename; -// snprintf(dash_inputs[i].representationID, "%d", i); -// strcpy(dash_inputs[i].periodID, ""); -// strcpy(dash_inputs[i].role, ""); -// -// } -// -// for (i = 0; i < audio_list_size; i++) { -// -// AudioDataConf *audio_data_conf = gf_list_get(cmd_data->audio_lst, i); -// dash_inputs[i + video_list_size].file_name = audio_data_conf->filename; -// snprintf(dash_inputs[i + video_list_size].representationID, "%d", -// i + video_list_size); -// strcpy(dash_inputs[i + video_list_size].periodID, ""); -// strcpy(dash_inputs[i + video_list_size].role, ""); -// -// } -// -// dash_profile = cmd_data->live ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_MAIN; -// strncpy(sz_mpd, cmd_data->mpd_filename, GF_MAX_PATH-1); -// -// dash_duration = cmd_data->dash_dur ? cmd_data->dash_dur / 1000 : 1; -// -// if (cmd_data->live) { -// dash_ctx = gf_cfg_new(NULL, NULL); -// } -// -// if (!dash_dynamic) { -// 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 = (u32) ( -// dash_subduration ? dash_subduration : dash_duration); -// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Using default MPD refresh of %d seconds\n", -// mpd_update_time); -// } -// -// if (cmd_data->live) -// gf_sleep(dash_duration * 1000); -// -// while (1) { -// -// //TODO Signiture of this API has changed! -// /* -// e = gf_dasher_segment_files(sz_mpd, dash_inputs, nb_dash_inputs, -// dash_profile, dash_title, dash_source, cprt, dash_more_info, -// (const char **) mpd_base_urls, nb_mpd_base_urls, -// use_url_template, single_segment, single_file, -// bitstream_switching_mode, seg_at_rap, dash_duration, seg_name, -// seg_ext, interleaving_time, subsegs_per_sidx, daisy_chain_sidx, -// frag_at_rap, tmpdir, dash_ctx, dash_dynamic, mpd_update_time, -// time_shift_depth, dash_subduration); -// -// if (e) { -// fprintf(stdout, "Error while segmenting.\n"); -// break; -// } -// */ -// -// if (!cmd_data->live) -// break; -// -// u32 sleefor = gf_dasher_next_update_time(dash_ctx, mpd_update_time); -// -// if (cmd_data->exit_signal) { -// break; -// } -// -// if (sleefor) { -// if (dash_dynamic != 2) { -// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("sleep for %d ms\n", sleefor); -// gf_sleep(sleefor); -// } -// } -// -// } - - return 0; + return GF_FALSE; } static u32 keyboard_thread(void *params) @@ -604,9 +506,9 @@ u32 video_decoder_thread(void *params) //fprintf(stdout, "sourcenumber: %d\n", source_number); - if (video_input_file[source_number]->mode == LIVE_MEDIA) { +// if (video_input_file[source_number]->mode == LIVE_MEDIA) { gf_gettimeofday(&time_start, NULL); - } +// } ret = dc_video_decoder_read(video_input_file[source_number], video_input_data, source_number, in_data->use_source_timing, (in_data->mode == LIVE_CAMERA) ? 1 : 0, (const int *) &in_data->exit_signal); #ifdef DASHCAST_PRINT @@ -650,9 +552,6 @@ u32 video_decoder_thread(void *params) u32 audio_decoder_thread(void *params) { -#ifdef DASHCAST_PRINT - int i = 0; -#endif int ret; struct timeval time_start, time_end, time_wait; AudioThreadParam *thread_params = (AudioThreadParam*)params; @@ -677,15 +576,11 @@ u32 audio_decoder_thread(void *params) return 0; while (1) { - if (audio_input_file->mode == LIVE_MEDIA) { +// if (audio_input_file->mode == LIVE_MEDIA) { gf_gettimeofday(&time_start, NULL); - } +// } ret = dc_audio_decoder_read(audio_input_file, audio_input_data); -#ifdef DASHCAST_PRINT - fprintf(stdout, "Read audio frame %d\r", i++); - fflush(stdout); -#endif if (ret == -2) { GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder has no more frame to read.\n")); break; @@ -756,7 +651,7 @@ u32 video_encoder_thread(void *params) Bool init_mpd = GF_FALSE; CmdData *in_data = thread_params->in_data; int video_conf_idx = thread_params->video_conf_idx; - VideoDataConf *video_data_conf = gf_list_get(in_data->video_lst, video_conf_idx); + VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_get(in_data->video_lst, video_conf_idx); VideoScaledData *video_scaled_data = thread_params->video_scaled_data; int video_cb_size = (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) ? 1 : VIDEO_CB_DEFAULT_SIZE; @@ -765,9 +660,6 @@ u32 video_encoder_thread(void *params) MessageQueue *mq = thread_params->mq; MessageQueue *delete_seg_mq = thread_params->delete_seg_mq; MessageQueue *send_seg_mq = thread_params->send_seg_mq; -#ifndef FRAGMENTER - MessageQueue *mq = thread_params->mq; -#endif if (!gf_list_count(in_data->video_lst)) return 0; @@ -783,17 +675,7 @@ u32 video_encoder_thread(void *params) if (seg_frame_max <= 0) seg_frame_max = -1; - shift = 0; - if (in_data->use_source_timing) { - //ugly patch ... - shift = 1000; - while (!video_scaled_data->frame_duration && shift) { - gf_sleep(1); - shift--; - } - shift = (u32) video_scaled_data->frame_duration; - } - if (dc_video_muxer_init(&out_file, video_data_conf, muxer_type, seg_frame_max, frag_frame_max, in_data->seg_marker, in_data->gdr, in_data->seg_dur, in_data->frag_dur, shift, in_data->gop_size, video_cb_size) < 0) { + if (dc_video_muxer_init(&out_file, video_data_conf, muxer_type, seg_frame_max, frag_frame_max, in_data->seg_marker, in_data->gdr, in_data->seg_dur, in_data->frag_dur, (u32) video_scaled_data->vsprop->video_input_data->frame_duration, in_data->gop_size, video_cb_size) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output video file.\n")); in_data->exit_signal = 1; return -1; @@ -812,7 +694,7 @@ u32 video_encoder_thread(void *params) time_at_segment_start.ntpts = 0; start_utc = gf_net_get_utc(); - seg_utc = 0; + while (1) { frame_nb = 0; //log time at segment start, because segment availabilityStartTime is computed from AST anchor + segment duration @@ -845,6 +727,7 @@ u32 video_encoder_thread(void *params) //force writing MPD before any encoding happens (eg don't wait for the end of the first segment) if (init_mpd) { init_mpd = GF_FALSE; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Initial MPD publish at UTC "LLU" ms\n", time_at_segment_start.utc_time)); dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start)); } @@ -857,8 +740,6 @@ u32 video_encoder_thread(void *params) } // fprintf(stdout, "Header size: %d\n", ret); while (1) { - u64 ntpts = gf_net_get_ntp_ts(); - //we have the RAP already encoded, skip coder if (loss_state == 2) { ret = 1; @@ -887,7 +768,7 @@ u32 video_encoder_thread(void *params) break; } - r = dc_video_muxer_write(&out_file, frame_nb, in_data->insert_utc ? ntpts : 0); + r = dc_video_muxer_write(&out_file, frame_nb, in_data->insert_utc ? GF_TRUE : GF_FALSE); if (r < 0) { quit = 1; in_data->exit_signal = 1; @@ -908,10 +789,6 @@ u32 video_encoder_thread(void *params) dc_video_muxer_close(&out_file); -#ifndef FRAGMENTER - dc_message_queue_put(mq, video_data_conf->filename, sizeof(video_data_conf->filename)); -#endif - // If system is live, // Send the time that a segment is available to MPD generator thread. if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) { @@ -956,7 +833,7 @@ u32 video_encoder_thread(void *params) if ((in_data->time_shift != -1)) { shift = 1000 * in_data->time_shift / in_data->seg_dur; - if (seg_nb - shift>=0) { + if (seg_nb > shift) { snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, (seg_nb - shift)); dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete)); } @@ -999,22 +876,21 @@ u32 audio_encoder_thread(void *params) //int audio_frame_size = AUDIO_FRAME_SIZE; char name_to_delete[GF_MAX_PATH]; u64 start_utc, seg_utc; + segtime time_at_segment_start; + Bool check_first_seg_utc = GF_TRUE; AudioMuxerType muxer_type = AUDIO_MUXER; AudioThreadParam *thread_params = (AudioThreadParam *) params; CmdData *in_data = thread_params->in_data; int audio_conf_idx = thread_params->audio_conf_idx; - AudioDataConf *audio_data_conf = gf_list_get(in_data->audio_lst, audio_conf_idx); + AudioDataConf *audio_data_conf = (AudioDataConf*)gf_list_get(in_data->audio_lst, audio_conf_idx); AudioInputData *audio_input_data = thread_params->audio_input_data; AudioOutputFile audio_output_file; MessageQueue *mq = thread_params->mq; MessageQueue *delete_seg_mq = thread_params->delete_seg_mq; -#ifndef FRAGMENTER - MessageQueue *mq = thread_params->mq; -#endif if (!gf_list_count(in_data->audio_lst)) return 0; @@ -1047,10 +923,15 @@ u32 audio_encoder_thread(void *params) start_utc = gf_net_get_utc(); GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[audio_encoder] start_utc="LLU"\n", start_utc)); - seg_utc = 0; + while (1) { + //logging at the end of the segment production will induce one segment delay + time_at_segment_start.utc_time = gf_net_get_utc(); + time_at_segment_start.ntpts = gf_net_get_ntp_ts(); + frame_nb = 0; quit = 0; + if (dc_audio_muxer_open(&audio_output_file, in_data->out_dir, audio_data_conf->filename, seg_nb+1) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio.\n")); in_data->exit_signal = 1; @@ -1072,6 +953,7 @@ u32 audio_encoder_thread(void *params) // } // } + audio_output_file.frame_ntp = gf_net_get_ntp_ts(); ret = dc_audio_encoder_read(&audio_output_file, audio_input_data); if (ret == -2) { GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder has no more data to encode.\n")); @@ -1094,7 +976,7 @@ u32 audio_encoder_thread(void *params) break; } - ret = dc_audio_muxer_write(&audio_output_file, frame_nb); + ret = dc_audio_muxer_write(&audio_output_file, frame_nb, in_data->insert_utc); if (ret == -1) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing audio frame.\n")); quit = 1; @@ -1115,38 +997,61 @@ u32 audio_encoder_thread(void *params) dc_audio_muxer_close(&audio_output_file); -#ifndef FRAGMENTER - dc_message_queue_put(mq, audio_data_conf->filename, sizeof(audio_data_conf->filename)); -#endif - // Send the time that a segment is available to MPD generator thread. if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA) { + int diff; + if (check_first_seg_utc) { + u64 now = gf_net_get_utc(); + check_first_seg_utc = GF_FALSE; + + diff = (int) (now - time_at_segment_start.utc_time); + if (diff < real_audio_seg_dur / 2) { + u32 sec, frac, ms; + s32 left, nb_s; + gf_net_get_ntp(&sec, &frac); + nb_s = real_audio_seg_dur/1000; + sec -= nb_s; + ms = (u32) ((u64) 1000 * frac / 0xFFFFFFFF); + left = ms; + left -= (s32) (real_audio_seg_dur - 1000*nb_s); + while (left<0) { + left += 1000; + sec-=1; + } + time_at_segment_start.ntpts = sec; + time_at_segment_start.ntpts <<= 32; + time_at_segment_start.ntpts |= (u32) ((0xFFFFFFFF*left)/1000); + + start_utc = time_at_segment_start.utc_time = now - real_audio_seg_dur; + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[audio_encoder] First segment produced faster (%d ms) than duration (%d ms) probably due to HW buffers - adjusting ast\n", diff, real_audio_seg_dur)); + } + } if (thread_params->audio_conf_idx == 0) { - segtime t; //check we don't loose sync - int diff; seg_utc = gf_net_get_utc(); diff = (int) (seg_utc - start_utc); //if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers if (diff > (seg_nb+2) * real_audio_seg_dur) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[audio_encoder] UTC diff %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", diff, seg_nb)); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[audio_encoder] UTC dur %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", diff, seg_nb)); while (diff > (seg_nb+2) * real_audio_seg_dur) { seg_nb++; } } - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[audio_encoder] UTC diff %d - cumulated segment duration %d -> %d\n", diff, (seg_nb+1) * real_audio_seg_dur, diff - (seg_nb+1) * real_audio_seg_dur)); - t.segnum = seg_nb; - t.utc_time = gf_net_get_utc(); - //time_t t = time(NULL); - dc_message_queue_put(mq, &t, sizeof(t)); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[audio_encoder] UTC dur %d - cumulated segment duration %d (diff %d ms)\n", diff, (seg_nb+1) * real_audio_seg_dur, diff - (seg_nb+1) * real_audio_seg_dur)); + + + time_at_segment_start.segnum = seg_nb; + dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start)); } } if (in_data->time_shift != -1) { shift = 1000 * in_data->time_shift / in_data->seg_dur; - snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, audio_data_conf->filename, (seg_nb - shift)); - dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete)); + if (seg_nb > shift) { + snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, audio_data_conf->filename, (seg_nb - shift)); + dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete)); + } } seg_nb++; @@ -1190,7 +1095,7 @@ int dc_run_controler(CmdData *in_data) //Video parameters VideoThreadParam vdecoder_th_params; - VideoThreadParam *vencoder_th_params = alloca(gf_list_count(in_data->video_lst) * sizeof(VideoThreadParam)); + VideoThreadParam *vencoder_th_params = (VideoThreadParam*)alloca(gf_list_count(in_data->video_lst) * sizeof(VideoThreadParam)); VideoInputData video_input_data; VideoInputFile *video_input_file[MAX_SOURCE_NUMBER]; VideoScaledDataList video_scaled_data_list; @@ -1198,26 +1103,19 @@ int dc_run_controler(CmdData *in_data) //Audio parameters AudioThreadParam adecoder_th_params; - AudioThreadParam *aencoder_th_params = alloca(gf_list_count(in_data->audio_lst) * sizeof(AudioThreadParam)); + AudioThreadParam *aencoder_th_params = (AudioThreadParam*)alloca(gf_list_count(in_data->audio_lst) * sizeof(AudioThreadParam)); AudioInputData audio_input_data; AudioInputFile audio_input_file; -#ifndef DASHER - ThreadParam dasher_th_params; -#endif - -#ifndef FRAGMENTER - ThreadParam fragmenter_th_params; -#endif - MessageQueue mq; MessageQueue delete_seg_mq; MessageQueue send_frag_mq; + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Controler init at UTC "LLU"\n", gf_net_get_utc() )); dc_register_libav(); for (i = 0; i < MAX_SOURCE_NUMBER; i++) - video_input_file[i] = gf_malloc(sizeof(VideoInputFile)); + video_input_file[i] = (VideoInputFile*)gf_malloc(sizeof(VideoInputFile)); dc_message_queue_init(&mq); dc_message_queue_init(&delete_seg_mq); @@ -1233,7 +1131,7 @@ int dc_run_controler(CmdData *in_data) if (strcmp(in_data->video_data_conf.filename, "") != 0) { dc_video_scaler_list_init(&video_scaled_data_list, in_data->video_lst); - vscaler_th_params = gf_malloc(video_scaled_data_list.size * sizeof(VideoThreadParam)); + vscaler_th_params = (VideoThreadParam*)gf_malloc(video_scaled_data_list.size * sizeof(VideoThreadParam)); /* Open input video */ if (dc_video_decoder_open(video_input_file[0], &in_data->video_data_conf, in_data->mode, in_data->no_loop, video_scaled_data_list.size) < 0) { @@ -1251,7 +1149,7 @@ int dc_run_controler(CmdData *in_data) /* open other input videos for source switching */ for (i = 0; i < gf_list_count(in_data->vsrc); i++) { - VideoDataConf *video_data_conf = gf_list_get(in_data->vsrc, i); + VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_get(in_data->vsrc, i); if (dc_video_decoder_open(video_input_file[i + 1], video_data_conf, LIVE_MEDIA, 1, video_scaled_data_list.size) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n")); ret = -1; @@ -1293,7 +1191,7 @@ int dc_run_controler(CmdData *in_data) if (strcmp(in_data->audio_data_conf.filename, "") != 0) { /* Open input audio */ - if (dc_audio_decoder_open(&audio_input_file, &in_data->audio_data_conf, in_data->mode, in_data->no_loop) < 0) { + if (dc_audio_decoder_open(&audio_input_file, &in_data->audio_data_conf, in_data->mode, in_data->no_loop, in_data->video_data_conf.framerate) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio.\n")); ret = -1; goto exit; @@ -1328,14 +1226,14 @@ int dc_run_controler(CmdData *in_data) //Communication between decoder and audio encoder for (i = 0; i < gf_list_count(in_data->audio_lst); i++) { - AudioDataConf *tmadata = gf_list_get(in_data->audio_lst, i); + AudioDataConf *tmadata = (AudioDataConf*)gf_list_get(in_data->audio_lst, i); tmadata->channels = in_data->audio_data_conf.channels; tmadata->samplerate = in_data->audio_data_conf.samplerate; } //Communication between decoder and video encoder for (i = 0; i < gf_list_count(in_data->video_lst); i++) { - VideoDataConf *tmvdata = gf_list_get(in_data->video_lst, i); + VideoDataConf *tmvdata = (VideoDataConf*)gf_list_get(in_data->video_lst, i); tmvdata->framerate = in_data->video_data_conf.framerate; if (in_data->use_source_timing) { tmvdata->time_base = in_data->video_data_conf.time_base; @@ -1354,12 +1252,37 @@ int dc_run_controler(CmdData *in_data) GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for mpd_thread.\n")); } + + if (strcmp(in_data->video_data_conf.filename, "") != 0) { + /* Create video decoder thread */ + vdecoder_th_params.in_data = in_data; + vdecoder_th_params.video_input_data = &video_input_data; + vdecoder_th_params.video_input_file = video_input_file; + if (gf_th_run(vdecoder_th_params.thread, video_decoder_thread, (void *) &vdecoder_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_decoder_thread.\n")); + } + + while ((in_data->mode == LIVE_CAMERA) && !video_input_data.frame_duration) { + gf_sleep(0); + } + } + + if (strcmp(in_data->audio_data_conf.filename, "") != 0) { + /* Create audio decoder thread */ + adecoder_th_params.in_data = in_data; + adecoder_th_params.audio_input_data = &audio_input_data; + adecoder_th_params.audio_input_file = &audio_input_file; + if (gf_th_run(adecoder_th_params.thread, audio_decoder_thread, (void *) &adecoder_th_params) != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_decoder_thread.\n")); + } + } + /****************************/ if (strcmp(in_data->video_data_conf.filename, "") != 0) { /* Create video encoder threads */ for (i=0; ivideo_lst); i++) { - VideoDataConf * video_data_conf = gf_list_get(in_data->video_lst, i); + VideoDataConf * video_data_conf = (VideoDataConf*)gf_list_get(in_data->video_lst, i); vencoder_th_params[i].in_data = in_data; vencoder_th_params[i].video_conf_idx = i; @@ -1403,26 +1326,6 @@ int dc_run_controler(CmdData *in_data) } } - if (strcmp(in_data->video_data_conf.filename, "") != 0) { - /* Create video decoder thread */ - vdecoder_th_params.in_data = in_data; - vdecoder_th_params.video_input_data = &video_input_data; - vdecoder_th_params.video_input_file = video_input_file; - if (gf_th_run(vdecoder_th_params.thread, video_decoder_thread, (void *) &vdecoder_th_params) != GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_decoder_thread.\n")); - } - } - - if (strcmp(in_data->audio_data_conf.filename, "") != 0) { - /* Create audio decoder thread */ - adecoder_th_params.in_data = in_data; - adecoder_th_params.audio_input_data = &audio_input_data; - adecoder_th_params.audio_input_file = &audio_input_file; - if (gf_th_run(adecoder_th_params.thread, audio_decoder_thread, (void *) &adecoder_th_params) != GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_decoder_thread.\n")); - } - } - if (in_data->time_shift != -1) { /* Initialize delete segment thread */ delete_seg_th_params.thread = gf_th_new("delete_seg_thread"); @@ -1443,29 +1346,6 @@ int dc_run_controler(CmdData *in_data) } } -#ifndef FRAGMENTER - if (strcmp(in_data->mpd_filename, "") != 0) { - /* Initialize keyboard controller thread */ - fragmenter_th_params.thread = gf_th_new("fragmenter_thread"); - fragmenter_th_params.in_data = in_data; - fragmenter_th_params.mq = &mq; - if (gf_th_run(fragmenter_th_params.thread, fragmenter_thread, (void *) &fragmenter_th_params) != GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for fragmenter_thread.\n")); - } - } -#endif - -#ifndef DASHER - if (in_data->live && strcmp(in_data->mpd_filename, "") != 0) { - /* Initialize keyboard controller thread */ - dasher_th_params.thread = gf_th_new("dasher_thread"); - dasher_th_params.in_data = in_data; - if (gf_th_run(dasher_th_params.thread, dasher_thread, (void *) &dasher_th_params) != GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for dasher_thread.\n")); - } - } -#endif - fprintf(stdout, "Press q or Q to exit...\n"); if (strcmp(in_data->audio_data_conf.filename, "") != 0) { @@ -1501,27 +1381,9 @@ int dc_run_controler(CmdData *in_data) gf_th_del(vscaler_th_params[i].thread); } } - -#ifndef DASHER - if (in_data->live && strcmp(in_data->mpd_filename, "") != 0) { - /* Wait for and destroy dasher thread */ - gf_th_stop(dasher_th_params.thread); - gf_th_del(dasher_th_params.thread); - } -#endif - + keyboard_th_params.in_data->exit_signal = 1; -#ifndef FRAGMENTER - dc_message_queue_flush(&mq); - - if (strcmp(in_data->mpd_filename, "") != 0) { - /* Wait for and destroy dasher thread */ - gf_th_stop(fragmenter_th_params.thread); - gf_th_del(fragmenter_th_params.thread); - } -#endif - /********** Keyboard thread ***********/ /* Wait for and destroy keyboard controler thread */ @@ -1551,13 +1413,6 @@ int dc_run_controler(CmdData *in_data) gf_th_del(send_frag_th_params.thread); } -#ifndef DASHER - if (!in_data->live && strcmp(in_data->mpd_filename, "") != 0) { - dasher_th_params.in_data = in_data; - dasher_thread((void*) &dasher_th_params); - } -#endif - exit: if (strcmp(in_data->audio_data_conf.filename, "") != 0) { /* Destroy audio input data */ diff --git a/applications/dashcast/dashcast.c b/applications/dashcast/dashcast.c index 7a56315..342fb2a 100644 --- a/applications/dashcast/dashcast.c +++ b/applications/dashcast/dashcast.c @@ -30,7 +30,7 @@ int main(int argc, char **argv) { #ifdef GPAC_MEMORY_TRACKING - Bool use_mem_track = 0; + GF_MemTrackerType mem_track = GF_MemTrackerNone; #endif s32 res; CmdData cmd_data; @@ -45,7 +45,7 @@ int main(int argc, char **argv) res = dc_run_controler(&cmd_data); #ifdef GPAC_MEMORY_TRACKING - use_mem_track = cmd_data.use_mem_track; + mem_track = cmd_data.mem_track; #endif /* Destroy command data */ @@ -54,8 +54,9 @@ int main(int argc, char **argv) if (res) return res; #ifdef GPAC_MEMORY_TRACKING - if (use_mem_track && (gf_memory_size() || gf_file_handles_count() )) { - gf_memory_print(); + if (mem_track && (gf_memory_size() || gf_file_handles_count() )) { + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); + gf_memory_print(); return 2; } #endif diff --git a/applications/dashcast/message_queue.c b/applications/dashcast/message_queue.c index 6f6cb68..5e223df 100644 --- a/applications/dashcast/message_queue.c +++ b/applications/dashcast/message_queue.c @@ -38,7 +38,7 @@ void dc_message_queue_init(MessageQueue *mq) void dc_message_queue_put(MessageQueue *mq, void *data, u32 size) { - MessageQueueNode *mqn = gf_malloc(sizeof(MessageQueueNode)); + MessageQueueNode *mqn = (MessageQueueNode*)gf_malloc(sizeof(MessageQueueNode)); mqn->data = gf_malloc(size); memcpy(mqn->data, data, size); mqn->size = size; diff --git a/applications/dashcast/register.c b/applications/dashcast/register.c index b62bb3f..a39aa30 100644 --- a/applications/dashcast/register.c +++ b/applications/dashcast/register.c @@ -74,7 +74,7 @@ void dc_unregister_libav() if (av_mutex) { while (gf_list_count(av_mutex)) { - GF_Mutex *mx = gf_list_last(av_mutex); + GF_Mutex *mx = (GF_Mutex*)gf_list_last(av_mutex); gf_list_rem_last(av_mutex); gf_mx_del(mx); } diff --git a/applications/dashcast/task.c b/applications/dashcast/task.c index d21d30f..44cb1db 100644 --- a/applications/dashcast/task.c +++ b/applications/dashcast/task.c @@ -39,7 +39,7 @@ void dc_task_destroy(TaskList *list) void dc_task_add(TaskList *list, int source_number, char *id_name, time_t start, time_t end) { - Task *task = gf_malloc(sizeof(Task)); + Task *task = (Task*)gf_malloc(sizeof(Task)); task->source_number = source_number; strncpy(task->id, id_name, MAX_ID_SIZE-1); task->start_time_t = start; @@ -53,7 +53,7 @@ int dc_task_get_current(TaskList *list, Task *task) u32 i; time_t now_time = time(NULL); for (i = 0; isize; i++) { - Task *cur_task = gf_list_get(list->tasks, i); + Task *cur_task = (Task*)gf_list_get(list->tasks, i); if (now_time > cur_task->start_time_t && now_time < cur_task->end_time_t) { //strncpy(task->id, cur_task->id, MAX_ID_SIZE-1); //memcpy(&task->start_time, &cur_task->start_time, sizeof(struct tm)); diff --git a/applications/dashcast/video_data.c b/applications/dashcast/video_data.c index f960d57..546ddfc 100644 --- a/applications/dashcast/video_data.c +++ b/applications/dashcast/video_data.c @@ -53,13 +53,17 @@ int dc_video_input_data_init(VideoInputData *video_input_data, /*int width, int //video_input_data->height = height; //video_input_data->pix_fmt = pix_fmt; - video_input_data->vprop = gf_malloc(max_source * sizeof(VideoInputProp)); + video_input_data->vprop = (VideoInputProp*)gf_malloc(max_source * sizeof(VideoInputProp)); dc_circular_buffer_create(&video_input_data->circular_buf, video_cb_size, mode, num_consumers); for (i=0; icircular_buf.list[i].data = (void *) video_data_node; video_data_node->vframe = FF_ALLOC_FRAME(); } @@ -82,7 +86,7 @@ void dc_video_input_data_destroy(VideoInputData *video_input_data) int i; for (i=0; i<(int) video_input_data->circular_buf.size; i++) { if (video_input_data->circular_buf.list) { - VideoDataNode *video_data_node = video_input_data->circular_buf.list[i].data; + VideoDataNode *video_data_node = (VideoDataNode*)video_input_data->circular_buf.list[i].data; av_free(video_data_node->vframe); gf_free(video_data_node); } diff --git a/applications/dashcast/video_data.h b/applications/dashcast/video_data.h index c5bc68f..eddcf35 100644 --- a/applications/dashcast/video_data.h +++ b/applications/dashcast/video_data.h @@ -73,6 +73,8 @@ typedef struct { char custom[GF_MAX_PATH]; /*low delay is used*/ int low_delay; + /*demuxer buffer size or 0 if default FFmpeg one is used*/ + int demux_buffer_size; /* used for source switching */ char source_id[GF_MAX_PATH]; @@ -125,6 +127,8 @@ typedef struct { int source_number; uint8_t nb_raw_frames_ref; AVPacket raw_packet; + + u64 frame_ntp, frame_utc; } VideoDataNode; void dc_video_data_set_default(VideoDataConf *video_data_conf); diff --git a/applications/dashcast/video_decoder.c b/applications/dashcast/video_decoder.c index de708f9..566e6cd 100644 --- a/applications/dashcast/video_decoder.c +++ b/applications/dashcast/video_decoder.c @@ -81,7 +81,7 @@ int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video } #endif - if (video_data_conf->format && strcmp(video_data_conf->format, "") != 0) { + if (strcmp(video_data_conf->format, "") != 0) { in_fmt = av_find_input_format(video_data_conf->format); if (in_fmt == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", video_data_conf->format)); @@ -91,6 +91,16 @@ int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video video_input_file->av_fmt_ctx = NULL; + if (video_data_conf->demux_buffer_size) { + char szBufSize[100]; + sprintf(szBufSize, "%d", video_data_conf->demux_buffer_size); + ret = av_dict_set(&options, "buffer_size", szBufSize, 0); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set demuxer's input buffer size.\n")); + return -1; + } + } + /* Open video */ open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL); if ( (open_res < 0) && !stricmp(video_data_conf->filename, "screen-capture-recorder") ) { @@ -158,7 +168,7 @@ int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video video_input_file->pix_fmt = codec_ctx->pix_fmt; if (codec_ctx->time_base.num==1) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("AVCTX give frame duration of %d/%d - keeping requested rate %d, but this may result in unexpected behaviour.\n", codec_ctx->time_base.num, codec_ctx->time_base.den, video_data_conf->framerate )); - + if (codec_ctx->time_base.den==1000000) { codec_ctx->time_base.num = codec_ctx->time_base.den / video_data_conf->framerate; } @@ -227,7 +237,8 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide AVPacket *packet_copy = NULL; if (ret != AVERROR_EOF) { GF_SAFEALLOC(packet_copy, AVPacket); - memcpy(packet_copy, &packet, sizeof(AVPacket)); + if (packet_copy) + memcpy(packet_copy, &packet, sizeof(AVPacket)); } assert(video_input_file->av_pkt_list); @@ -277,16 +288,21 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide /* Is this a packet from the video stream? */ if (packet.stream_index == video_input_file->vstream_idx) { - if (!already_locked) { + u32 nb_retry = 10; + while (!already_locked) { if (dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf) < 0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped a video frame\n")); + if (!nb_retry) break; + gf_sleep(10); + nb_retry--; continue; } - dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf); - already_locked = 1; } + if (!already_locked) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped a video frame\n")); + continue; + } video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf); video_data_node->source_number = source_number; @@ -298,6 +314,9 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide av_frame_unref(video_data_node->vframe); #endif + video_data_node->frame_ntp = gf_net_get_ntp_ts(); + video_data_node->frame_utc = gf_net_get_utc(); + /* Decode video frame */ if (avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet) < 0) { av_free_packet(&packet); @@ -316,19 +335,30 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide video_input_file->utc_at_init = gf_net_get_utc(); video_input_file->first_pts = packet.pts; video_input_file->prev_pts = 0; - video_input_data->frame_duration = codec_ctx->time_base.num; - - video_input_file->sync_tolerance = 9*video_input_data->frame_duration/5; - //TODO - check with audio if sync is OK + video_input_data->frame_duration = 0; } - - //move to 0-based PTS - pts = packet.pts - video_input_file->first_pts; +#if 0 + if (video_input_file->pts_init && (video_input_file->pts_init!=3) ) { + if (packet.pts==AV_NOPTS_VALUE) { + video_input_file->pts_init=1; + } else if (video_input_file->pts_init==1) { + video_input_file->pts_init=2; + video_input_file->pts_dur_estimate = packet.pts; + } else if (video_input_file->pts_init==2) { + video_input_file->pts_init=3; + video_input_data->frame_duration = packet.pts - video_input_file->pts_dur_estimate; + video_input_file->sync_tolerance = 9*video_input_data->frame_duration/5; + //TODO - check with audio if sync is OK + } + } +#endif - if (video_input_file->prev_pts + video_input_data->frame_duration / 2 > pts) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DashCast] Error in PTS , diff too small (previous "LLU" - current "LLU"\n", video_input_file->prev_pts, pts)); - } - + //move to 0-based PTS + if (packet.pts!=AV_NOPTS_VALUE) { + pts = packet.pts - video_input_file->first_pts; + } else { + pts = video_input_file->prev_pts + video_input_data->frame_duration; + } //check for drop frames #ifndef GPAC_DISABLE_LOG @@ -346,6 +376,14 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide } #endif +#if 1 + if ((pts != video_input_file->prev_pts) && (video_input_file->pts_init == 1)) { + video_input_file->pts_init = 2; + video_input_data->frame_duration = pts - video_input_file->prev_pts; + video_input_file->sync_tolerance = 9*video_input_data->frame_duration/5; + } +#endif + video_input_file->prev_pts = pts; video_data_node->vframe->pts = pts; } @@ -359,20 +397,23 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide } video_input_file->frame_decoded++; - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video Frame TS "LLU" decoded at UTC "LLU" ms\n", video_data_node->vframe->pts, gf_net_get_utc() )); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video Frame TS "LLU" decoded at UTC "LLU" ms (frame duration %d)\n", video_data_node->vframe->pts, gf_net_get_utc(), video_input_data->frame_duration)); // For a decode/encode process we must free this memory. //But if the input is raw and there is no need to decode then // the packet is directly passed for decoded frame. We must wait until rescale is done before freeing it if (codec_ctx->codec->id == CODEC_ID_RAWVIDEO) { - video_data_node->nb_raw_frames_ref = video_input_file->nb_consumers; + if (is_live_capture && !video_input_data->frame_duration) { + } else { + video_data_node->nb_raw_frames_ref = video_input_file->nb_consumers; - video_data_node->raw_packet = packet; + video_data_node->raw_packet = packet; - dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); - while (video_data_node->nb_raw_frames_ref && ! *exit_signal_addr) { - gf_sleep(0); + dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); + while (video_data_node->nb_raw_frames_ref && ! *exit_signal_addr) { + gf_sleep(0); + } } } else { dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); diff --git a/applications/dashcast/video_decoder.h b/applications/dashcast/video_decoder.h index 59a6f94..940d704 100644 --- a/applications/dashcast/video_decoder.h +++ b/applications/dashcast/video_decoder.h @@ -57,8 +57,8 @@ typedef struct { int no_loop, nb_consumers; u32 frame_decoded; - Bool pts_init; - u64 first_pts, prev_pts, sync_tolerance; + u32 pts_init; + u64 first_pts, prev_pts, pts_dur_estimate, sync_tolerance; u64 utc_at_init; } VideoInputFile; diff --git a/applications/dashcast/video_encoder.c b/applications/dashcast/video_encoder.c index 1b07cf1..875e0bd 100644 --- a/applications/dashcast/video_encoder.c +++ b/applications/dashcast/video_encoder.c @@ -160,9 +160,12 @@ int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *vid int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData *video_scaled_data) { - VideoDataNode *video_data_node; + VideoScaledDataNode *video_data_node; int ret; - + u64 time_spent; + int got_packet = 0; + AVPacket pkt; + AVCodecContext *video_codec_ctx = video_output_file->codec_ctx; //FIXME: deadlock when pressing 'q' with BigBuckBunny_640x360.m4v @@ -175,7 +178,7 @@ int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData if (video_scaled_data->circular_buf.size > 1) dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf); - video_data_node = (VideoDataNode*)dc_consumer_consume(&video_output_file->consumer, &video_scaled_data->circular_buf); + video_data_node = (VideoScaledDataNode*)dc_consumer_consume(&video_output_file->consumer, &video_scaled_data->circular_buf); /* * Set PTS (method 1) @@ -184,49 +187,48 @@ int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData video_data_node->vframe->pts = video_codec_ctx->frame_number; } + time_spent = gf_sys_clock_high_res(); /* Encoding video */ - { - int got_packet = 0; - AVPacket pkt; - av_init_packet(&pkt); - pkt.data = video_output_file->vbuf; - pkt.size = video_output_file->vbuf_size; - pkt.pts = pkt.dts = video_data_node->vframe->pkt_dts = video_data_node->vframe->pkt_pts = video_data_node->vframe->pts; - video_data_node->vframe->pict_type = 0; - video_data_node->vframe->width = video_codec_ctx->width; - video_data_node->vframe->height = video_codec_ctx->height; - video_data_node->vframe->format = video_codec_ctx->pix_fmt; + av_init_packet(&pkt); + pkt.data = video_output_file->vbuf; + pkt.size = video_output_file->vbuf_size; + pkt.pts = pkt.dts = video_data_node->vframe->pkt_dts = video_data_node->vframe->pkt_pts = video_data_node->vframe->pts; + video_data_node->vframe->pict_type = 0; + video_data_node->vframe->width = video_codec_ctx->width; + video_data_node->vframe->height = video_codec_ctx->height; + video_data_node->vframe->format = video_codec_ctx->pix_fmt; #ifdef LIBAV_ENCODE_OLD - if (!video_output_file->segment_started) - video_data_node->vframe->pict_type = FF_I_TYPE; + if (!video_output_file->segment_started) + video_data_node->vframe->pict_type = FF_I_TYPE; - video_output_file->encoded_frame_size = avcodec_encode_video(video_codec_ctx, video_output_file->vbuf, video_output_file->vbuf_size, video_data_node->vframe); - got_packet = video_output_file->encoded_frame_size>=0 ? 1 : 0; + video_output_file->encoded_frame_size = avcodec_encode_video(video_codec_ctx, video_output_file->vbuf, video_output_file->vbuf_size, video_data_node->vframe); + got_packet = video_output_file->encoded_frame_size>=0 ? 1 : 0; #else - //this is correct but unfortunately doesn't work with some versions of FFMPEG (output is just grey video ...) - - if (!video_output_file->segment_started) - video_data_node->vframe->pict_type = AV_PICTURE_TYPE_I; + //this is correct but unfortunately doesn't work with some versions of FFMPEG (output is just grey video ...) + if (!video_output_file->segment_started) + video_data_node->vframe->pict_type = AV_PICTURE_TYPE_I; - video_output_file->encoded_frame_size = avcodec_encode_video2(video_codec_ctx, &pkt, video_data_node->vframe, &got_packet); + video_output_file->encoded_frame_size = avcodec_encode_video2(video_codec_ctx, &pkt, video_data_node->vframe, &got_packet); #endif - //this is not true with libav ! + time_spent = gf_sys_clock_high_res() - time_spent; + //this is not true with libav ! #ifndef GPAC_USE_LIBAV - if (video_output_file->encoded_frame_size >= 0) - video_output_file->encoded_frame_size = pkt.size; + if (video_output_file->encoded_frame_size >= 0) + video_output_file->encoded_frame_size = pkt.size; #else - if (got_packet) - video_output_file->encoded_frame_size = pkt.size; + if (got_packet) + video_output_file->encoded_frame_size = pkt.size; #endif - if (video_output_file->encoded_frame_size >= 0) { - if (got_packet) { - video_codec_ctx->coded_frame->pts = video_codec_ctx->coded_frame->pkt_pts = pkt.pts; - video_codec_ctx->coded_frame->pkt_dts = pkt.dts; - video_codec_ctx->coded_frame->key_frame = (pkt.flags & AV_PKT_FLAG_KEY) ? 1 : 0; - } + if (video_output_file->encoded_frame_size >= 0) { + if (got_packet) { + video_codec_ctx->coded_frame->pts = video_codec_ctx->coded_frame->pkt_pts = pkt.pts; + video_codec_ctx->coded_frame->pkt_dts = pkt.dts; + video_codec_ctx->coded_frame->key_frame = (pkt.flags & AV_PKT_FLAG_KEY) ? 1 : 0; + video_output_file->frame_ntp = video_data_node->frame_ntp; + video_output_file->frame_utc = video_data_node->frame_utc; } } @@ -240,7 +242,7 @@ int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData return -1; } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video %s Frame TS "LLU" encoded at UTC "LLU" ms\n", video_output_file->rep_id, /*video_data_node->source_number, */video_data_node->vframe->pts, gf_net_get_utc() )); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video %s Frame TS "LLU" encoded at UTC "LLU" ms in "LLU" us\n", video_output_file->rep_id, /*video_data_node->source_number, */video_data_node->vframe->pts, gf_net_get_utc(), time_spent )); /* if zero size, it means the image was buffered */ // if (out_size > 0) { diff --git a/applications/dashcast/video_muxer.c b/applications/dashcast/video_muxer.c index 7f0ae3c..b6693bb 100644 --- a/applications/dashcast/video_muxer.c +++ b/applications/dashcast/video_muxer.c @@ -45,7 +45,7 @@ static GF_Err avc_import_ffextradata(const u8 *extradata, const u64 extradata_si GF_BitStream *bs; if (!extradata || (extradata_size < sizeof(u32))) return GF_BAD_PARAM; - bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ); + bs = gf_bs_new((const char *) extradata, extradata_size, GF_BITSTREAM_READ); if (!bs) return GF_BAD_PARAM; if (gf_bs_read_u32(bs) != 0x00000001) { @@ -150,13 +150,13 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s return GF_OK; #else HEVCState hevc; - GF_HEVCParamArray *vpss = NULL, *spss = NULL, *ppss = NULL; + GF_HEVCParamArray *vpss = NULL, *spss = NULL, *ppss = NULL, *seis = NULL; GF_BitStream *bs; char *buffer = NULL; u32 buffer_size = 0; if (!extradata || (extradata_size < sizeof(u32))) return GF_BAD_PARAM; - bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ); + bs = gf_bs_new((const char *) extradata, extradata_size, GF_BITSTREAM_READ); if (!bs) return GF_BAD_PARAM; @@ -167,11 +167,19 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s s32 idx; GF_AVCConfigSlot *slc; u8 nal_unit_type, temporal_id, layer_id; - u64 nal_start; + u64 nal_start, start_code; u32 nal_size; - if (gf_bs_read_u32(bs) != 0x00000001) { + start_code = gf_bs_read_u32(bs); + if (start_code>>8 == 0x000001) { + nal_start = gf_bs_get_position(bs) - 1; + gf_bs_seek(bs, nal_start); + start_code = 1; + } + if (start_code != 0x00000001) { gf_bs_del(bs); + if (buffer) gf_free(buffer); + if (vpss && spss && ppss) return GF_OK; return GF_BAD_PARAM; } nal_start = gf_bs_get_position(bs); @@ -186,9 +194,8 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s buffer_size = nal_size; } gf_bs_read_data(bs, buffer, nal_size); - gf_bs_seek(bs, nal_start); - gf_media_hevc_parse_nalu(bs, &hevc, &nal_unit_type, &temporal_id, &layer_id); + gf_media_hevc_parse_nalu(buffer, nal_size, &hevc, &nal_unit_type, &temporal_id, &layer_id); if (layer_id) { gf_bs_del(bs); gf_free(buffer); @@ -216,19 +223,25 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s if (!vpss) { GF_SAFEALLOC(vpss, GF_HEVCParamArray); - vpss->nalus = gf_list_new(); - gf_list_add(dst_cfg->param_array, vpss); - vpss->array_completeness = 1; - vpss->type = GF_HEVC_NALU_VID_PARAM; + if (vpss) { + vpss->nalus = gf_list_new(); + gf_list_add(dst_cfg->param_array, vpss); + vpss->array_completeness = 1; + vpss->type = GF_HEVC_NALU_VID_PARAM; + } } slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); - slc->size = nal_size; - slc->id = idx; - slc->data = (char*)gf_malloc(sizeof(char)*slc->size); - memcpy(slc->data, buffer, sizeof(char)*slc->size); - - gf_list_add(vpss->nalus, slc); + if (slc) { + slc->size = nal_size; + slc->id = idx; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + if (slc->data) + memcpy(slc->data, buffer, sizeof(char)*slc->size); + + if (vpss) + gf_list_add(vpss->nalus, slc); + } } break; case GF_HEVC_NALU_SEQ_PARAM: @@ -264,18 +277,24 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s if (!spss) { GF_SAFEALLOC(spss, GF_HEVCParamArray); - spss->nalus = gf_list_new(); - gf_list_add(dst_cfg->param_array, spss); - spss->array_completeness = 1; - spss->type = GF_HEVC_NALU_SEQ_PARAM; + if (spss) { + spss->nalus = gf_list_new(); + gf_list_add(dst_cfg->param_array, spss); + spss->array_completeness = 1; + spss->type = GF_HEVC_NALU_SEQ_PARAM; + } } slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); - slc->size = nal_size; - slc->id = idx; - slc->data = (char*)gf_malloc(sizeof(char)*slc->size); - memcpy(slc->data, buffer, sizeof(char)*slc->size); - gf_list_add(spss->nalus, slc); + if (slc) { + slc->size = nal_size; + slc->id = idx; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + if (slc->data) + memcpy(slc->data, buffer, sizeof(char)*slc->size); + if (spss) + gf_list_add(spss->nalus, slc); + } break; case GF_HEVC_NALU_PIC_PARAM: idx = gf_media_hevc_read_pps(buffer, nal_size, &hevc); @@ -292,33 +311,53 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s if (!ppss) { GF_SAFEALLOC(ppss, GF_HEVCParamArray); - ppss->nalus = gf_list_new(); - gf_list_add(dst_cfg->param_array, ppss); - ppss->array_completeness = 1; - ppss->type = GF_HEVC_NALU_PIC_PARAM; + if (ppss) { + ppss->nalus = gf_list_new(); + gf_list_add(dst_cfg->param_array, ppss); + ppss->array_completeness = 1; + ppss->type = GF_HEVC_NALU_PIC_PARAM; + } } slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + if (slc) { + slc->size = nal_size; + slc->id = idx; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + if (slc->data) + memcpy(slc->data, buffer, sizeof(char)*slc->size); + + if (ppss) + gf_list_add(ppss->nalus, slc); + } + } + break; + case GF_HEVC_NALU_SEI_PREFIX: + if (!seis) { + GF_SAFEALLOC(seis, GF_HEVCParamArray); + if (seis) { + seis->nalus = gf_list_new(); + seis->array_completeness = 0; + seis->type = GF_HEVC_NALU_SEI_PREFIX; + } + } + slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + if (slc) { slc->size = nal_size; - slc->id = idx; slc->data = (char*)gf_malloc(sizeof(char)*slc->size); - memcpy(slc->data, buffer, sizeof(char)*slc->size); - - gf_list_add(ppss->nalus, slc); + if (slc->data) + memcpy(slc->data, buffer, sizeof(char)*slc->size); + if (seis) + gf_list_add(seis->nalus, slc); } break; default: break; } - - if (gf_bs_seek(bs, nal_start+nal_size)) { - assert(nal_start+nal_size <= gf_bs_get_size(bs)); - break; - } } gf_bs_del(bs); - gf_free(buffer); + if (buffer) gf_free(buffer); return GF_OK; #endif @@ -398,7 +437,7 @@ int dc_gpac_video_moov_create(VideoOutputFile *video_output_file, char *filename { GF_Err ret; AVCodecContext *video_codec_ctx = video_output_file->codec_ctx; - u32 di, track; + u32 di=1, track; //TODO: For the moment it is fixed //u32 sample_dur = video_output_file->codec_ctx->time_base.den; @@ -786,8 +825,10 @@ GF_Err dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, return -2; } -int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 ntp_timestamp) +int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, Bool insert_ntp) { + Bool segment_close = GF_FALSE; + Bool fragment_close = GF_FALSE; switch (video_output_file->muxer_type) { case FFMPEG_VIDEO_MUXER: return dc_ffmpeg_video_muxer_write(video_output_file); @@ -805,9 +846,10 @@ int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 n if (ret < 0) return -1; + //insert UTC for each fragment - if (ntp_timestamp) { - gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, ntp_timestamp, video_output_file->codec_ctx->coded_frame->pts); + if (insert_ntp) { + gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, video_output_file->frame_ntp, video_output_file->codec_ctx->coded_frame->pts); } video_output_file->first_dts_in_fragment = video_output_file->codec_ctx->coded_frame->pkt_dts; @@ -819,9 +861,9 @@ int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 n } #ifndef GPAC_DISABLE_LOG - if (ntp_timestamp && gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_INFO)) { + if (insert_ntp && gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_INFO)) { if (!video_output_file->ntp_at_first_dts) { - video_output_file->ntp_at_first_dts = ntp_timestamp; + video_output_file->ntp_at_first_dts = video_output_file->frame_ntp; } else { s32 ntp_diff = gf_net_get_ntp_diff_ms(video_output_file->ntp_at_first_dts); s32 ts_diff = (s32) ( 1000 * (video_output_file->codec_ctx->coded_frame->pts - video_output_file->pts_at_first_segment) / video_output_file->timescale ); @@ -840,36 +882,43 @@ int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 n } video_output_file->last_pts = video_output_file->codec_ctx->coded_frame->pts; video_output_file->last_dts = video_output_file->codec_ctx->coded_frame->pkt_dts; - - if (( video_output_file->last_dts - video_output_file->first_dts_in_fragment + video_output_file->frame_dur) * 1000 >= video_output_file->frag_dur * video_output_file->timescale) { - gf_isom_flush_fragments(video_output_file->isof, 1); - video_output_file->fragment_started = 0; - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Flushed fragment at UTC "LLU" ms - First DTS "LLU" last PTS "LLU"\n", gf_net_get_utc(), video_output_file->first_dts_in_fragment, video_output_file->codec_ctx->coded_frame->pts)); - } + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] PTS: "LLU", DTS: "LLU", first DTS in frag: "LLU", timescale: %d, frag dur: %d\n", video_output_file->last_pts, video_output_file->last_dts, video_output_file->first_dts_in_fragment, video_output_file->timescale, video_output_file->frag_dur)); //we may have rounding errors on the input PTS :( add half frame dur safety - //flush segments based on the cumultated duration , to avoid drift - if (1000 * ( video_output_file->last_pts - video_output_file->pts_at_first_segment + 3*video_output_file->frame_dur/2) / video_output_file->timescale >= (video_output_file->nb_segments+1)*video_output_file->seg_dur ) { - return 1; - } + /* Check why segment tests work on PTS while fragment tests work on DTS ? */ + /* Check why fragment closing is not tested based on accumulation of fragment duration to avoid drifts */ + segment_close = ((video_output_file->last_pts - video_output_file->pts_at_first_segment + video_output_file->frame_dur) * 1000 >= + (video_output_file->nb_segments+1)*video_output_file->seg_dur * (u64)video_output_file->timescale); #if 0 - if (1000 * ( video_output_file->last_pts - video_output_file->pts_at_segment_start + 3*video_output_file->frame_dur/2) /video_output_file->timescale >= video_output_file->seg_dur ) { - return 1; - } + segment_close = ((video_output_file->last_pts - video_output_file->pts_at_segment_start + 3*video_output_file->frame_dur/2) * 1000 >= + (video_output_file->seg_dur * (u64)video_output_file->timescale); #endif - return 0; + //flush fragment if adding next frame will exceed target duration by half the frame duration + fragment_close = ((video_output_file->last_dts - video_output_file->first_dts_in_fragment + 3 * video_output_file->frame_dur / 2) * 1000 >= + (video_output_file->frag_dur * (u64)video_output_file->timescale)); + + if (segment_close || fragment_close) { + gf_isom_flush_fragments(video_output_file->isof, 1); + video_output_file->fragment_started = 0; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Flushed fragment at UTC "LLU" ms - First DTS "LLU" last PTS "LLU" - First Segment PTS "LLU" timescale %d\n", gf_net_get_utc(), video_output_file->first_dts_in_fragment, video_output_file->codec_ctx->coded_frame->pts, video_output_file->pts_at_segment_start, video_output_file->timescale)); + } + + if (segment_close) { + return 1; } + return 0; + } - if (frame_nb % video_output_file->frame_per_fragment == 0) { + if (frame_nb % video_output_file->frame_per_fragment == 0) { gf_isom_start_fragment(video_output_file->isof, 1); if (!video_output_file->segment_started) { video_output_file->pts_at_segment_start = video_output_file->codec_ctx->coded_frame->pts; video_output_file->segment_started = 1; - if (ntp_timestamp) { - gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, ntp_timestamp, video_output_file->pts_at_segment_start); + if (insert_ntp) { + gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, video_output_file->frame_ntp, video_output_file->pts_at_segment_start); } } diff --git a/applications/dashcast/video_muxer.h b/applications/dashcast/video_muxer.h index 08ded74..0d7c852 100644 --- a/applications/dashcast/video_muxer.h +++ b/applications/dashcast/video_muxer.h @@ -99,6 +99,8 @@ typedef struct { u32 nb_segments; Bool fragment_started, segment_started; const char *rep_id; + + u64 frame_ntp, frame_utc; } VideoOutputFile; int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, VideoMuxerType muxer_type, int frame_per_segment, int frame_per_fragment, u32 seg_marker, int gdr, int seg_dur, int frag_dur, int frame_dur, int gop_size, int video_cb_size); @@ -107,7 +109,7 @@ int dc_video_muxer_free(VideoOutputFile *video_output_file); int dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, char *id_name, int seg); -int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 ntp_timestamp); +int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, Bool insert_ntp_timestamp); int dc_video_muxer_close(VideoOutputFile *video_output_file); diff --git a/applications/dashcast/video_scaler.c b/applications/dashcast/video_scaler.c index 0135d9d..bfe7800 100644 --- a/applications/dashcast/video_scaler.c +++ b/applications/dashcast/video_scaler.c @@ -32,25 +32,25 @@ VideoScaledDataNode * dc_video_scaler_node_create(int width, int height, int crop_x, int crop_y, int pix_fmt) { - VideoScaledDataNode *video_scaled_data_node = gf_malloc(sizeof(VideoDataNode)); + VideoScaledDataNode *video_scaled_data_node = (VideoScaledDataNode*)gf_malloc(sizeof(VideoDataNode)); if (video_scaled_data_node) { - video_scaled_data_node->v_frame = FF_ALLOC_FRAME(); + video_scaled_data_node->vframe = FF_ALLOC_FRAME(); if (crop_x || crop_y) { video_scaled_data_node->cropped_frame = FF_ALLOC_FRAME(); } else { video_scaled_data_node->cropped_frame = NULL; } } - if (!video_scaled_data_node || !video_scaled_data_node->v_frame || ((crop_x || crop_y) && !video_scaled_data_node->cropped_frame)) { + if (!video_scaled_data_node || !video_scaled_data_node->vframe || ((crop_x || crop_y) && !video_scaled_data_node->cropped_frame)) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate VideoNode!\n")); - av_frame_free(&video_scaled_data_node->v_frame); + av_frame_free(&video_scaled_data_node->vframe); av_frame_free(&video_scaled_data_node->cropped_frame); gf_free(video_scaled_data_node); return NULL; } /* Determine required buffer size and allocate buffer */ - avpicture_alloc((AVPicture*)video_scaled_data_node->v_frame, pix_fmt, width, height); + avpicture_alloc((AVPicture*)video_scaled_data_node->vframe, pix_fmt, width, height); if (video_scaled_data_node->cropped_frame) { avpicture_alloc((AVPicture*)video_scaled_data_node->cropped_frame, pix_fmt, width-crop_x, height-crop_y); } @@ -61,7 +61,7 @@ VideoScaledDataNode * dc_video_scaler_node_create(int width, int height, int cro void dc_video_scaler_node_destroy(VideoScaledDataNode *video_scaled_data_node) { #ifndef GPAC_USE_LIBAV - av_frame_free(&video_scaled_data_node->v_frame); + av_frame_free(&video_scaled_data_node->vframe); #endif gf_free(video_scaled_data_node); } @@ -88,11 +88,15 @@ void dc_video_scaler_list_init(VideoScaledDataList *video_scaled_data_list, GF_L if (!found) { VideoScaledData *video_scaled_data; GF_SAFEALLOC(video_scaled_data, VideoScaledData); + if (!video_scaled_data) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Cannot allocate video rescaler\n")); + return; + } video_scaled_data->out_width = video_data_conf->width; video_scaled_data->out_height = video_data_conf->height; video_scaled_data->num_consumers = 1; - video_scaled_data_list->video_scaled_data = gf_realloc(video_scaled_data_list->video_scaled_data, (video_scaled_data_list->size+1)*sizeof(VideoScaledData*)); + video_scaled_data_list->video_scaled_data = (VideoScaledData**)gf_realloc(video_scaled_data_list->video_scaled_data, (video_scaled_data_list->size+1)*sizeof(VideoScaledData*)); video_scaled_data_list->video_scaled_data[video_scaled_data_list->size] = video_scaled_data; video_scaled_data_list->size++; @@ -134,6 +138,7 @@ int dc_video_scaler_data_init(VideoInputData *video_input_data, VideoScaledData video_scaled_data->circular_buf.list[i].data = dc_video_scaler_node_create(video_scaled_data->out_width, video_scaled_data->out_height, video_input_data->vprop[i].crop_x, video_input_data->vprop[i].crop_y, video_scaled_data->out_pix_fmt); } + video_scaled_data->vsprop->video_input_data = video_input_data; return 0; } @@ -189,8 +194,6 @@ int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *vid video_scaled_data_node = (VideoScaledDataNode*)dc_producer_produce(&video_scaled_data->producer, &video_scaled_data->circular_buf); index = video_data_node->source_number; - video_scaled_data->frame_duration = video_input_data->frame_duration; - //crop if necessary if (video_input_data->vprop[index].crop_x || video_input_data->vprop[index].crop_y) { #if 0 @@ -214,13 +217,16 @@ int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *vid //rescale the cropped frame ret = sws_scale(video_scaled_data->vsprop[index].sws_ctx, (const uint8_t * const *)src_vframe->data, src_vframe->linesize, 0, src_height, - video_scaled_data_node->v_frame->data, video_scaled_data_node->v_frame->linesize); + video_scaled_data_node->vframe->data, video_scaled_data_node->vframe->linesize); if (!ret) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler: error while resizing picture.\n")); return -1; } - video_scaled_data_node->v_frame->pts = video_data_node->vframe->pts; + video_scaled_data_node->vframe->pts = video_data_node->vframe->pts; + video_scaled_data_node->frame_ntp = video_data_node->frame_ntp; + video_scaled_data_node->frame_utc = video_data_node->frame_utc; + if (video_data_node->nb_raw_frames_ref) { if (video_data_node->nb_raw_frames_ref==1) { diff --git a/applications/dashcast/video_scaler.h b/applications/dashcast/video_scaler.h index 3442e59..5090683 100644 --- a/applications/dashcast/video_scaler.h +++ b/applications/dashcast/video_scaler.h @@ -39,6 +39,8 @@ typedef struct { int in_width; int in_height; int in_pix_fmt; + + VideoInputData *video_input_data; } VideoScaledProp; /* @@ -73,8 +75,6 @@ typedef struct { * (Which are the encoders who are using this resolution) */ int num_consumers; int num_producers; - - u64 frame_duration; } VideoScaledData; /* @@ -82,8 +82,9 @@ typedef struct { * To use the circular buffer for scaled video frame we must define the node. This structure contains the data needed to encode a video frame. */ typedef struct { - AVFrame *v_frame; + AVFrame *vframe; AVFrame *cropped_frame; + u64 frame_ntp, frame_utc; } VideoScaledDataNode; /* diff --git a/applications/generators/MPEG4/MPEG4Gen.dsp b/applications/generators/MPEG4/MPEG4Gen.dsp index 2339ae7..e5a7d9c 100644 --- a/applications/generators/MPEG4/MPEG4Gen.dsp +++ b/applications/generators/MPEG4/MPEG4Gen.dsp @@ -1,98 +1,98 @@ -# Microsoft Developer Studio Project File - Name="MPEG4Gen" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=MPEG4Gen - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "MPEG4Gen.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "MPEG4Gen.mak" CFG="MPEG4Gen - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "MPEG4Gen - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "MPEG4Gen - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "MPEG4Gen - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Obj/W32Rel" -# PROP Intermediate_Dir "Obj/W32Rel" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x40c /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "MPEG4Gen - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Obj/W32Deb" -# PROP Intermediate_Dir "Obj/W32Deb" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x40c /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "MPEG4Gen - Win32 Release" -# Name "MPEG4Gen - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\..\..\src\utils\list.c -# End Source File -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="MPEG4Gen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=MPEG4Gen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "MPEG4Gen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MPEG4Gen.mak" CFG="MPEG4Gen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MPEG4Gen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "MPEG4Gen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MPEG4Gen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Obj/W32Rel" +# PROP Intermediate_Dir "Obj/W32Rel" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "MPEG4Gen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Obj/W32Deb" +# PROP Intermediate_Dir "Obj/W32Deb" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "MPEG4Gen - Win32 Release" +# Name "MPEG4Gen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\utils\list.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# End Target +# End Project diff --git a/applications/generators/MPEG4/MPEG4Gen.dsw b/applications/generators/MPEG4/MPEG4Gen.dsw index 15ce429..e3bd23b 100644 --- a/applications/generators/MPEG4/MPEG4Gen.dsw +++ b/applications/generators/MPEG4/MPEG4Gen.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "MPEG4Gen"=.\MPEG4Gen.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "MPEG4Gen"=.\MPEG4Gen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/generators/MPEG4/Makefile b/applications/generators/MPEG4/Makefile index 4bf4ec6..e739047 100644 --- a/applications/generators/MPEG4/Makefile +++ b/applications/generators/MPEG4/Makefile @@ -30,7 +30,7 @@ SRCS := $(OBJS:.o=.c) all: $(PROG) $(PROG): $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac + $(CC) -o $@ $(OBJS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac $(LDFLAGS) %.o: %.c diff --git a/applications/generators/MPEG4/main.c b/applications/generators/MPEG4/main.c index a3f7b0e..e4a143b 100644 --- a/applications/generators/MPEG4/main.c +++ b/applications/generators/MPEG4/main.c @@ -869,6 +869,7 @@ void WriteNodeCode(GF_List *BNodes) || !strcmp(bf->familly, "SFString") || !strcmp(bf->familly, "SFURL") || !strcmp(bf->familly, "SFImage") + || !strcmp(bf->familly, "MFAttrRef") ) { char szName[500]; strcpy(szName, bf->familly); diff --git a/applications/generators/SVG/Makefile b/applications/generators/SVG/Makefile index 53a8be6..6cd7dd3 100644 --- a/applications/generators/SVG/Makefile +++ b/applications/generators/SVG/Makefile @@ -35,7 +35,7 @@ SRCS := $(OBJS:.o=.c) all: $(PROG) SVGGen$(EXE): $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(XML2_LIBS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac -lz + $(CC) -o $@ $(OBJS) $(XML2_LIBS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac -lz $(LDFLAGS) %.o: %.c diff --git a/applications/generators/SVG/SVGGen.dsp b/applications/generators/SVG/SVGGen.dsp index 8d95fcb..c76b774 100644 --- a/applications/generators/SVG/SVGGen.dsp +++ b/applications/generators/SVG/SVGGen.dsp @@ -1,126 +1,126 @@ -# Microsoft Developer Studio Project File - Name="SVGGen" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=SVGGen - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SVGGen.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SVGGen.mak" CFG="SVGGen - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SVGGen - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "SVGGen - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SVGGen - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x40c /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 libxml2.lib zlib.lib iconv.lib /nologo /subsystem:console /machine:I386 /libpath:"../../../extra_lib/lib/w32_release" - -!ELSEIF "$(CFG)" == "SVGGen - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include/" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x40c /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 libxml2.lib zlib.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" - -!ENDIF - -# Begin Target - -# Name "SVGGen - Win32 Release" -# Name "SVGGen - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\..\..\src\utils\error.c -# End Source File -# Begin Source File - -SOURCE=.\html.c -# End Source File -# Begin Source File - -SOURCE=.\laser.c -# End Source File -# Begin Source File - -SOURCE=..\..\..\src\utils\list.c -# End Source File -# Begin Source File - -SOURCE=.\main.c -# End Source File -# Begin Source File - -SOURCE=.\v1.c -# End Source File -# Begin Source File - -SOURCE=.\v2.c -# End Source File -# Begin Source File - -SOURCE=.\v3.c -# End Source File -# End Group -# Begin Source File - -SOURCE=.\svggen.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="SVGGen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=SVGGen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SVGGen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SVGGen.mak" CFG="SVGGen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SVGGen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "SVGGen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SVGGen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libxml2.lib zlib.lib iconv.lib /nologo /subsystem:console /machine:I386 /libpath:"../../../extra_lib/lib/w32_release" + +!ELSEIF "$(CFG)" == "SVGGen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include/" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libxml2.lib zlib.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "SVGGen - Win32 Release" +# Name "SVGGen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\utils\error.c +# End Source File +# Begin Source File + +SOURCE=.\html.c +# End Source File +# Begin Source File + +SOURCE=.\laser.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\src\utils\list.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +SOURCE=.\v1.c +# End Source File +# Begin Source File + +SOURCE=.\v2.c +# End Source File +# Begin Source File + +SOURCE=.\v3.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\svggen.h +# End Source File +# End Target +# End Project diff --git a/applications/generators/SVG/SVGGen.dsw b/applications/generators/SVG/SVGGen.dsw index 170c054..1b31b26 100644 --- a/applications/generators/SVG/SVGGen.dsw +++ b/applications/generators/SVG/SVGGen.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SVGGen"=.\SVGGen.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SVGGen"=.\SVGGen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/generators/SVG/v3.c b/applications/generators/SVG/v3.c index 9af75c3..292844d 100644 --- a/applications/generators/SVG/v3.c +++ b/applications/generators/SVG/v3.c @@ -181,23 +181,23 @@ void generateSVGCode_V3(GF_List *svg_elements) if (!strcmp(att->svg_name, "x") || !strcmp(att->svg_name, "y")) { fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); fprintf(output, "\t\tif (element_tag == TAG_SVG_text) return TAG_SVG_ATT_text_%s;\n", att->implementation_name); - fprintf(output, "\t\telse if (element_tag == TAG_SVG_cursorManager) return TAG_SVG_ATT_cursorManager_%s;\n", att->svg_name, att->implementation_name); - fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t\telse if (element_tag == TAG_SVG_cursorManager) return TAG_SVG_ATT_cursorManager_%s;\n", att->implementation_name); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->implementation_name); fprintf(output, "\t}\n"); } else if (!strcmp(att->svg_name, "rotate")) { fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); fprintf(output, "\t\tif (element_tag == TAG_SVG_text) return TAG_SVG_ATT_text_%s;\n", att->implementation_name); - fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->implementation_name); fprintf(output, "\t}\n"); } else if (!strcmp(att->svg_name, "type")) { fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); fprintf(output, "\t\tif (element_tag == TAG_SVG_animateTransform) return TAG_SVG_ATT_transform_type;\n"); - fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->implementation_name); fprintf(output, "\t}\n"); } else if (!strcmp(att->svg_name, "fill")) { fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) {\n", att->svg_name); - fprintf(output, "\t\tif (element_tag == TAG_SVG_animate || element_tag == TAG_SVG_animateColor || element_tag == TAG_SVG_animateMotion || element_tag == TAG_SVG_animateTransform || element_tag == TAG_SVG_animation || element_tag == TAG_SVG_audio || element_tag == TAG_SVG_video || element_tag == TAG_SVG_set) return TAG_SVG_ATT_smil_fill;\n", att->svg_name, att->implementation_name); - fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); + fprintf(output, "\t\tif (element_tag == TAG_SVG_animate || element_tag == TAG_SVG_animateColor || element_tag == TAG_SVG_animateMotion || element_tag == TAG_SVG_animateTransform || element_tag == TAG_SVG_animation || element_tag == TAG_SVG_audio || element_tag == TAG_SVG_video || element_tag == TAG_SVG_set) return TAG_SVG_ATT_smil_fill;\n"); + fprintf(output, "\t\telse return TAG_SVG_ATT_%s;\n", att->implementation_name); fprintf(output, "\t}\n"); } else { fprintf(output, "\tif (!stricmp(attribute_name, \"%s\")) return TAG_SVG_ATT_%s;\n", att->svg_name, att->implementation_name); diff --git a/applications/generators/X3D/Makefile b/applications/generators/X3D/Makefile index 1a96c0e..56f2c2d 100644 --- a/applications/generators/X3D/Makefile +++ b/applications/generators/X3D/Makefile @@ -30,7 +30,7 @@ SRCS := $(OBJS:.o=.c) all: $(PROG) $(PROG): $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac + $(CC) -o $@ $(OBJS) $(EXTRALIBS) -L../../../bin/gcc -L../../../extra_lib/lib/gcc -lgpac $(LDFLAGS) %.o: %.c diff --git a/applications/generators/X3D/X3DGen.dsp b/applications/generators/X3D/X3DGen.dsp index b16b8dd..7afd243 100644 --- a/applications/generators/X3D/X3DGen.dsp +++ b/applications/generators/X3D/X3DGen.dsp @@ -1,98 +1,98 @@ -# Microsoft Developer Studio Project File - Name="X3DGen" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=X3DGen - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "X3DGen.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "X3DGen.mak" CFG="X3DGen - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "X3DGen - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "X3DGen - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "X3DGen - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x40c /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "X3DGen - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Obj/W32Deb" -# PROP Intermediate_Dir "Obj/W32Deb" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x40c /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "X3DGen - Win32 Release" -# Name "X3DGen - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\..\..\src\utils\list.c -# End Source File -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="X3DGen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=X3DGen - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "X3DGen.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "X3DGen.mak" CFG="X3DGen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "X3DGen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "X3DGen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "X3DGen - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "X3DGen - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Obj/W32Deb" +# PROP Intermediate_Dir "Obj/W32Deb" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "X3DGen - Win32 Release" +# Name "X3DGen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\utils\list.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# End Target +# End Project diff --git a/applications/generators/X3D/X3DGen.dsw b/applications/generators/X3D/X3DGen.dsw index 2c265c5..2aca071 100644 --- a/applications/generators/X3D/X3DGen.dsw +++ b/applications/generators/X3D/X3DGen.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "X3DGen"=.\X3DGen.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "X3DGen"=.\X3DGen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/generators/X3D/main.c b/applications/generators/X3D/main.c index 339819a..72e3670 100644 --- a/applications/generators/X3D/main.c +++ b/applications/generators/X3D/main.c @@ -395,6 +395,7 @@ void WriteNodeCode(GF_List *BNodes, FILE *vrml_code) || !strcmp(bf->familly, "SFString") || !strcmp(bf->familly, "SFURL") || !strcmp(bf->familly, "SFImage") + || !strcmp(bf->familly, "MFColorRGBA") ) { char szName[500]; diff --git a/applications/m3u82mpd/m3u82mpd.vcproj b/applications/m3u82mpd/m3u82mpd.vcproj deleted file mode 100644 index b139419..0000000 --- a/applications/m3u82mpd/m3u82mpd.vcproj +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/m3u82mpd/main.c b/applications/m3u82mpd/main.c deleted file mode 100644 index 2c161d5..0000000 --- a/applications/m3u82mpd/main.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * GPAC - Multimedia Framework C SDK - * - * Copyright (c) Telecom ParisTech 2010 - - * All rights reserved - * - * This file is part of GPAC / m3u82mpd application - * - * GPAC is gf_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 - - -int main(int argc, char **argv) -{ - GF_Err e; - VariantPlaylist * pl = NULL; - char *url = argv[1]; - //char *cache_m3u8_file; - u32 i, count; - FILE *fmpd; - Bool verbose = 0; - u32 update_interval = 0; - char *m3u8_local_name = "file.m3u8"; - Bool is_local = 0; - - gf_sys_init(0); - - gf_log_set_tool_level(GF_LOG_NETWORK, verbose ? GF_LOG_DEBUG : GF_LOG_INFO); - - while (1) { - - if (gf_url_is_local(url)) { - m3u8_local_name = url; - is_local = 1; - } else { - e = gf_dm_wget(url, m3u8_local_name, 0, 0); - if (e != GF_OK) return -1; - } - - e = parse_root_playlist(m3u8_local_name, &pl, "."); - if (e != GF_OK) return -1; - - fmpd = gf_fopen(argv[2], "wt"); - - fprintf(fmpd, "\n"); - fprintf(fmpd, " \n"); - fprintf(fmpd, " Media Presentation Description for file %s\n", url); - fprintf(fmpd, " Generated by GPAC %s\n", GPAC_FULL_VERSION); - - fprintf(fmpd, " \n"); - fprintf(fmpd, " \n"); - - count = gf_list_count(pl->programs); - for (i=0; iprograms, i); - count2 = gf_list_count(prog->bitrates); - for (j = 0; jbitrates, j); - fprintf(stdout, "%d, %d, %s, %s, %d\n", pe->durationInfo, pe->bandwidth, pe->title, pe->url, pe->elementType); - if (pe->elementType == TYPE_PLAYLIST) { - u32 k, count3; - char *tmp; - char c; - char baseURL[GF_MAX_PATH]; - tmp = strrchr(url, '/'); - if (tmp) { - tmp++; - c = tmp[0]; - tmp[0] = 0; - strcpy(baseURL, url); - tmp[0] = c; - } else { - baseURL[0] = 0; - } - fprintf(fmpd, " \n"); - fprintf(fmpd, " durationInfo); - if (baseURL[0]) fprintf(fmpd, "baseURL=\"%s\"", baseURL); - fprintf(fmpd, ">\n"); - count3 = gf_list_count(pe->element.playlist.elements); - update_interval = (count3 - 1) * pe->durationInfo * 1000; - for (k=0; kelement.playlist.elements, k); - if (k) fprintf(fmpd, " \n", elt->url); - else fprintf(fmpd, " \n", elt->url); - } - fprintf(fmpd, " \n"); - fprintf(fmpd, " \n"); - } else if (pe->elementType == TYPE_STREAM) { - fprintf(stdout, "Stream\n"); - } - } - } - fprintf(fmpd, " \n"); - fprintf(fmpd, ""); - gf_fclose(fmpd); - variant_playlist_del(pl); - if (is_local) break; - gf_sleep(update_interval); - } - - gf_sys_close(); - return 0; -} diff --git a/applications/mp42avi/Makefile b/applications/mp42avi/Makefile index ebaf44c..ab7c02c 100644 --- a/applications/mp42avi/Makefile +++ b/applications/mp42avi/Makefile @@ -31,7 +31,7 @@ SRCS := $(OBJS:.o=.c) all: $(PROG) $(PROG): $(OBJS) - $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/$(TARGET_BIN_DIR) -lgpac -lz + $(CC) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/$(TARGET_BIN_DIR) -lgpac -lz $(LDFLAGS) clean: rm -f $(OBJS) ../../bin/gcc/$(PROG) diff --git a/applications/mp42avi/main.c b/applications/mp42avi/main.c index 4b6c057..619ff34 100644 --- a/applications/mp42avi/main.c +++ b/applications/mp42avi/main.c @@ -753,7 +753,7 @@ int main (int argc, char **argv) PrintUsage(); return 0; } - gf_sys_init(); + gf_sys_init(GF_MemTrackerNone); file = gf_isom_open(inName, GF_ISOM_OPEN_READ, NULL); if (!file) { diff --git a/applications/mp42ts/Makefile b/applications/mp42ts/Makefile index c8b88db..4565894 100644 --- a/applications/mp42ts/Makefile +++ b/applications/mp42ts/Makefile @@ -14,9 +14,6 @@ CFLAGS+=-pg LDFLAGS+=-pg endif -#common obj -OBJS= main.o - LINKFLAGS=-L../../bin/gcc ifeq ($(CONFIG_WIN32),yes) EXE=.exe @@ -25,15 +22,32 @@ else EXT= PROG=MP42TS endif + +ifeq ($(STATICBUILD),yes) +##include static modules and other deps for libgpac +include ../../static.mak + +#FIXME we have to disable AAC+bifs support in mp42ts since it reuses things from aac_in already in libgpac ... +ifeq ($(STATIC_MODULES), yes) +CFLAGS+=-DGPAC_DISABLE_PLAYER +endif + +LINKFLAGS+=-lgpac_static +LINKFLAGS+= $(GPAC_SH_FLAGS) +LINKFLAGS+=$(EXTRALIBS) +else LINKFLAGS+=-lgpac +endif +#common objs - insert after ../static if any to overwrite list of objects +OBJS= main.o SRCS := $(OBJS:.o=.c) all: $(PROG) $(PROG): $(OBJS) - $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + $(CC) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) $(LDFLAGS) clean: rm -f $(OBJS) ../../bin/gcc/$(PROG) diff --git a/applications/mp42ts/main.c b/applications/mp42ts/main.c index eba445d..90664d7 100644 --- a/applications/mp42ts/main.c +++ b/applications/mp42ts/main.c @@ -48,14 +48,18 @@ #define MP42TS_PRINT_TIME_MS 500 /*refresh printed info every CLOCK_REFRESH ms*/ #define MP42TS_VIDEO_FREQ 1000 /*meant to send AVC IDR only every CLOCK_REFRESH ms*/ + +s32 temi_id_1 = -1; +s32 temi_id_2 = -1; + u32 temi_url_insertion_delay = 1000; u32 temi_offset = 0; -Bool temi_disable_loop = 0; +Bool temi_disable_loop = GF_FALSE; FILE *logfile = NULL; -static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +static void on_gpac_log(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *fmt, va_list list) { - FILE *logs = cbk; + FILE *logs = (FILE*)cbk; vfprintf(logs, fmt, list); fflush(logs); } @@ -106,17 +110,22 @@ static GFINLINE void usage() " * This should be set to 0 for DASH streams.\n" "-time n request the muxer to stop after n ms\n" "-single-au forces 1 PES = 1 AU (disabled by default)\n" + "-multi-au forces 1 PES = N AU for all streams (disabled by default).\n" + " By default, audio streams pack N AUs in one PES but video and systems data use 1 AU per PES.\n" "-rap forces RAP/IDR to be aligned with PES start for video streams (disabled by default)\n" " in this mode, PAT, PMT and PCR will be inserted before the first TS packet of the RAP PES\n" "-flush-rap same as -rap but flushes all other streams (sends remaining PES packets) before inserting PAT/PMT\n" "-nb-pack N specifies to pack up to N TS packets together before sending on network or writing to file\n" - "-pcr-ms N sets max interval in ms between 2 PCR. Default is 100 ms\n" + "-pcr-ms N sets max interval in ms between 2 PCR. Default is 100 ms or at each PES header\n" + "-force-pcr-only allows sending PCR-only packets to enforce the requested PCR rate - STILL EXPERIMENTAL.\n" "-ttl N specifies Time-To-Live for multicast. Default is 1.\n" "-ifce IPIFCE specifies default IP interface to use. Default is IF_ANY.\n" - "-temi [URL] Inserts TEMI time codes in adaptation field. URL is optionnal\n" + "-temi [URL] Inserts TEMI time codes in adaptation field. URL is optional, and can be a number for external timeline IDs\n" "-temi-delay DelayMS Specifies delay between two TEMI url descriptors (default is 1000)\n" "-temi-offset OffsetMS Specifies an offset in ms to add to TEMI (by default TEMI starts at 0)\n" "-temi-noloop Do not restart the TEMI timeline at the end of the source\n" + "-temi2 ID Inserts a secondary TEMI time codes in adaptation field of the audio PID if any. ID shall be set to the desired external timeline IDs\n" + "-insert-ntp Inserts NTP timestamp in TEMI timeline descriptor\n" "-sdt-rate MS Gives the SDT carrousel rate in milliseconds. If 0 (default), SDT is not sent\n" "\n" "MPEG-4/T-DMB options:\n" @@ -131,7 +140,8 @@ static GFINLINE void usage() "\n" "Misc options\n" #ifdef GPAC_MEMORY_TRACKING - "-mem-track enables memory tracker\n" + "-mem-track enables memory tracker\n" + "-mem-track-stack enables memory tracker stack dumping\n" #endif "-logs set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" "-h or -help print this screen\n" @@ -190,12 +200,11 @@ typedef struct void *dsi_and_rap; Bool loop; Bool is_repeat; - s64 ts_offset; + s64 ts_offset, cts_dts_shift; M2TSSource *source; const char *temi_url; - u32 last_temi_url; - Bool insert_temi; + u32 last_temi_url, timeline_id; Bool insert_ntp; } GF_ESIMP4; @@ -238,7 +247,7 @@ enum #endif }; -static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 ntp, const char *temi_url, u32 *last_url_time) +static u32 format_af_descriptor(char *af_data, u32 timeline_id, u64 timecode, u32 timescale, u64 ntp, const char *temi_url, u32 *last_url_time) { u32 res; u32 len; @@ -262,7 +271,7 @@ static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 gf_bs_write_int(bs, 0, 1); //splicing_flag gf_bs_write_int(bs, 0, 1); //use_base_temi_url gf_bs_write_int(bs, 0xFF, 5); //reserved - gf_bs_write_int(bs, 0, 7); //timeline_id + gf_bs_write_int(bs, timeline_id, 7); //timeline_id if (strlen(temi_url)) { char *url = (char *)temi_url; @@ -285,7 +294,7 @@ static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 } if (timescale || ntp) { - Bool use64 = (timecode > 0xFFFFFFFFUL) ? 1 : 0; + Bool use64 = (timecode > 0xFFFFFFFFUL) ? GF_TRUE : GF_FALSE; len = 3; //3 bytes flags if (timescale) len += 4 + (use64 ? 8 : 4); @@ -303,7 +312,7 @@ static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 gf_bs_write_int(bs, 0, 1); //paused gf_bs_write_int(bs, 0, 1); //discontinuity gf_bs_write_int(bs, 0xFF, 7); //reserved - gf_bs_write_int(bs, temi_url ? 0 : 150, 8); //timeline_id + gf_bs_write_int(bs, timeline_id, 8); //timeline_id if (timescale) { gf_bs_write_u32(bs, timescale); //timescale if (use64) @@ -349,9 +358,9 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) pck.cts = priv->sample->DTS + priv->ts_offset; if (priv->is_repeat) pck.flags |= GF_ESI_DATA_REPEAT; - if (priv->insert_temi) { + if (priv->timeline_id) { u64 ntp=0; - u64 tc = priv->sample->DTS + priv->sample->CTS_Offset; + u64 tc = priv->sample->DTS + priv->sample->CTS_Offset + priv->cts_dts_shift; if (temi_disable_loop) { tc += priv->ts_offset; } @@ -367,7 +376,7 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) ntp <<= 32; ntp |= frac; } - pck.mpeg2_af_descriptors_size = format_af_descriptor(af_data, tc, ifce->timescale, ntp, priv->temi_url, &priv->last_temi_url); + pck.mpeg2_af_descriptors_size = format_af_descriptor(af_data, priv->timeline_id - 1, tc, ifce->timescale, ntp, priv->temi_url, &priv->last_temi_url); pck.mpeg2_af_descriptors = af_data; } @@ -376,13 +385,18 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) } pck.dts = pck.cts; + if (priv->cts_dts_shift) { + pck.cts += + priv->cts_dts_shift; + pck.flags |= GF_ESI_DATA_HAS_DTS; + } + if (priv->sample->CTS_Offset) { pck.cts += priv->sample->CTS_Offset; pck.flags |= GF_ESI_DATA_HAS_DTS; } if (priv->sample->IsRAP && priv->dsi && priv->dsi_size) { - pck.data = priv->dsi; + pck.data = (char*)priv->dsi; pck.data_len = priv->dsi_size; ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck); pck.flags &= ~GF_ESI_DATA_AU_START; @@ -415,7 +429,7 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck); GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS Muxer] Track %d: sample %d CTS %d\n", priv->track, priv->sample_number+1, pck.cts)); -#ifndef GPAC_DISABLE_TTXT +#ifndef GPAC_DISABLE_VTT if (cues) { while (gf_list_count(cues)) { GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, 0); @@ -444,12 +458,12 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) duration = (u64) (gf_isom_get_duration(priv->mp4) * scale); priv->ts_offset += duration; priv->sample_number = 0; - priv->is_repeat = (priv->sample_count==1) ? 1 : 0; + priv->is_repeat = (priv->sample_count==1) ? GF_TRUE : GF_FALSE; } else if (priv->image_repeat_ms && priv->source->nb_real_streams) { priv->nb_repeat_last++; priv->sample_number--; - priv->is_repeat = 1; + priv->is_repeat = GF_TRUE; } else { if (!(ifce->caps & GF_ESI_STREAM_IS_OVER)) { ifce->caps |= GF_ESI_STREAM_IS_OVER; @@ -482,17 +496,22 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi GF_ESIMP4 *priv; char *_lan; GF_ESD *esd; + Bool is_hevc=GF_FALSE; u64 avg_rate, duration; s32 ref_count; s64 mediaOffset; GF_SAFEALLOC(priv, GF_ESIMP4); + if (!priv) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate MP4 input handler\n")); + return; + } priv->mp4 = mp4; priv->track = track_num; priv->mtype = gf_isom_get_media_type(priv->mp4, priv->track); priv->mstype = gf_isom_get_media_subtype(priv->mp4, priv->track, 1); - priv->loop = source->real_time ? 1 : 0; + priv->loop = source->real_time ? GF_TRUE : GF_FALSE; priv->sample_count = gf_isom_get_sample_count(mp4, track_num); source->samples_count += priv->sample_count; if (priv->sample_count>1) @@ -517,11 +536,18 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi ifce->decoder_config = (char *)gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength); ifce->decoder_config_size = esd->decoderConfig->decoderSpecificInfo->dataLength; memcpy(ifce->decoder_config, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); + if (esd->decoderConfig->objectTypeIndication == GPAC_OTI_VIDEO_MPEG4_PART2) { + priv->dsi = (char *)gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength); + priv->dsi_size = esd->decoderConfig->decoderSpecificInfo->dataLength; + memcpy(priv->dsi, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); + } break; case GPAC_OTI_VIDEO_HEVC: - case GPAC_OTI_VIDEO_SHVC: + case GPAC_OTI_VIDEO_LHVC: + is_hevc=GF_TRUE; case GPAC_OTI_VIDEO_AVC: case GPAC_OTI_VIDEO_SVC: + case GPAC_OTI_VIDEO_MVC: gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG | GF_ISOM_NALU_EXTRACT_VDRD_FLAG); break; case GPAC_OTI_SCENE_VTT_MP4: @@ -557,8 +583,12 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi ifce->duration /= ifce->timescale; GF_SAFEALLOC(ifce->sl_config, GF_SLConfig); + if (!ifce->sl_config) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate interface SLConfig\n")); + return; + } + ifce->sl_config->tag = GF_ODF_SLC_TAG; -// ifce->sl_config->predefined = 3; ifce->sl_config->useAccessUnitStartFlag = 1; ifce->sl_config->useAccessUnitEndFlag = 1; ifce->sl_config->useRandomAccessPointFlag = 1; @@ -590,12 +620,19 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi priv->ts_offset = mediaOffset; } + if (gf_isom_has_time_offset(mp4, track_num)==2) { + priv->cts_dts_shift = gf_isom_get_cts_to_dts_shift(mp4, track_num); + } + + ifce->depends_on_stream = 0; ref_count = gf_isom_get_reference_count(mp4, track_num, GF_ISOM_REF_SCAL); if (ref_count > 0) { gf_isom_get_reference_ID(mp4, track_num, GF_ISOM_REF_SCAL, (u32) ref_count, &ifce->depends_on_stream); - } - else { - ifce->depends_on_stream = 0; + } else if (is_hevc) { + ref_count = gf_isom_get_reference_count(mp4, track_num, GF_ISOM_REF_BASE); + if (ref_count > 0) { + gf_isom_get_reference_ID(mp4, track_num, GF_ISOM_REF_BASE, (u32) ref_count, &ifce->depends_on_stream); + } } if (compute_max_size) { @@ -670,7 +707,7 @@ static GF_Err rtp_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) case GF_ESI_INPUT_DATA_FLUSH: /*flush rtcp channel*/ while (1) { - Bool has_sr=0; + Bool has_sr = GF_FALSE; size = gf_rtp_read_rtcp(rtp->rtp_ch, buffer, 8000); if (!size) break; e = gf_rtp_decode_rtcp(rtp->rtp_ch, buffer, size, &has_sr); @@ -690,7 +727,7 @@ static GF_Err rtp_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) } rtp->ts_offset = rtp->rtp_ch->last_SR_rtp_time; rtp->ts_offset -= (s64) (time * rtp->rtp_ch->TimeScale); - rtp->rtcp_init = 1; + rtp->rtcp_init = GF_TRUE; } } /*flush rtp channel*/ @@ -781,7 +818,7 @@ static void rtp_sl_packet_cbk(void *udta, char *payload, u32 size, GF_SLHeader * /*since we don't inspect the RTP content, we can only concatenate SPS and PPS indicated in SDP*/ if (hdr->randomAccessPointFlag && rtp->dsi_and_rap) { - rtp->pck.data = rtp->dsi_and_rap; + rtp->pck.data = (char*)rtp->dsi_and_rap; rtp->pck.data_len = rtp->avc_dsi_size; rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck); @@ -799,7 +836,7 @@ static void rtp_sl_packet_cbk(void *udta, char *payload, u32 size, GF_SLHeader * rtp->dsi_and_rap = gf_malloc(sizeof(char)*(rtp->pck.data_len)); memcpy(rtp->dsi_and_rap, rtp->depacketizer->sl_map.config, rtp->depacketizer->sl_map.configSize); memcpy((char *) rtp->dsi_and_rap + rtp->depacketizer->sl_map.configSize, payload, size); - rtp->pck.data = rtp->dsi_and_rap; + rtp->pck.data = (char*)rtp->dsi_and_rap; } rtp->ifce->output_ctrl(rtp->ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &rtp->pck); } @@ -822,6 +859,10 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf /*check payload type*/ map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0); GF_SAFEALLOC(rtp, GF_ESIRTP); + if (!rtp) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate RTP input handler\n")); + return; + } memset(ifce, 0, sizeof(GF_ESInterface)); rtp->rtp_ch = gf_rtp_new(); @@ -833,7 +874,7 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf memset(&trans, 0, sizeof(GF_RTSPTransport)); trans.Profile = media->Profile; trans.source = conn ? conn->host : sdp->o_address; - trans.IsUnicast = gf_sk_is_multicast_address(trans.source) ? 0 : 1; + trans.IsUnicast = gf_sk_is_multicast_address(trans.source) ? GF_FALSE : GF_TRUE; if (!trans.IsUnicast) { trans.port_first = media->PortNumber; trans.port_last = media->PortNumber + 1; @@ -868,11 +909,12 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf if (rtp->depacketizer->sl_map.config) { switch (ifce->object_type_indication) { case GPAC_OTI_VIDEO_MPEG4_PART2: - rtp->cat_dsi = 1; + rtp->cat_dsi = GF_TRUE; break; case GPAC_OTI_VIDEO_AVC: case GPAC_OTI_VIDEO_SVC: - rtp->is_264 = 1; + case GPAC_OTI_VIDEO_MVC: + rtp->is_264 = GF_TRUE; rtp->depacketizer->flags |= GF_RTP_AVC_USE_ANNEX_B; { #ifndef GPAC_DISABLE_AV_PARSERS @@ -884,12 +926,12 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); for (i=0; isequenceParameterSets); i++) { - slc = gf_list_get(avccfg->sequenceParameterSets, i); + slc = (GF_AVCConfigSlot*)gf_list_get(avccfg->sequenceParameterSets, i); gf_bs_write_u32(bs, 1); gf_bs_write_data(bs, slc->data, slc->size); } for (i=0; ipictureParameterSets); i++) { - slc = gf_list_get(avccfg->pictureParameterSets, i); + slc = (GF_AVCConfigSlot*)gf_list_get(avccfg->pictureParameterSets, i); gf_bs_write_u32(bs, 1); gf_bs_write_data(bs, slc->data, slc->size); } @@ -901,22 +943,22 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf } break; case GPAC_OTI_AUDIO_AAC_MPEG4: - ifce->decoder_config = gf_malloc(sizeof(char) * rtp->depacketizer->sl_map.configSize); + ifce->decoder_config = (char*)gf_malloc(sizeof(char) * rtp->depacketizer->sl_map.configSize); ifce->decoder_config_size = rtp->depacketizer->sl_map.configSize; memcpy(ifce->decoder_config, rtp->depacketizer->sl_map.config, rtp->depacketizer->sl_map.configSize); break; } } if (rtp->depacketizer->sl_map.StreamStateIndication) { - rtp->use_carousel = 1; + rtp->use_carousel = GF_TRUE; rtp->au_sn=0; } /*DTS signaling is only supported for MPEG-4 visual*/ if (rtp->depacketizer->sl_map.DTSDeltaLength) ifce->caps |= GF_ESI_SIGNAL_DTS; - gf_rtp_depacketizer_reset(rtp->depacketizer, 1); - e = gf_rtp_initialize(rtp->rtp_ch, 0x100000ul, 0, 0, 10, 200, NULL); + gf_rtp_depacketizer_reset(rtp->depacketizer, GF_TRUE); + e = gf_rtp_initialize(rtp->rtp_ch, 0x100000ul, GF_FALSE, 0, 10, 200, NULL); if (e!=GF_OK) { gf_rtp_del(rtp->rtp_ch); fprintf(stderr, "Cannot initialize RTP channel: %s\n", gf_error_to_string(e)); @@ -1016,8 +1058,12 @@ static void SampleCallBack(void *calling_object, u16 ESID, char *data, u32 size, GF_Err e; source->streams[i].timescale = esd->slConfig->timestampResolution; e = gf_m2ts_program_stream_update_ts_scale(&source->streams[i], esd->slConfig->timestampResolution); - assert(!e); - if (!source->streams[i].sl_config) source->streams[i].sl_config = (GF_SLConfig *)gf_odf_desc_new(GF_ODF_SLC_TAG); + if (e != GF_OK) { + fprintf(stderr, "Failed updating TS program timescale\n"); + } + else if (!source->streams[i].sl_config) + source->streams[i].sl_config = (GF_SLConfig *)gf_odf_desc_new(GF_ODF_SLC_TAG); + memcpy(source->streams[i].sl_config, esd->slConfig, sizeof(GF_SLConfig)); break; } @@ -1030,6 +1076,10 @@ static void SampleCallBack(void *calling_object, u16 ESID, char *data, u32 size, { /*audio OD descriptor: rap=1 and vers_inc=0*/ GF_SAFEALLOC(source->streams[audio_OD_stream_id].input_udta, GF_ESIStream); + if (!source->streams[audio_OD_stream_id].input_udta) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate aac input handler\n")); + return; + } ((GF_ESIStream*)source->streams[audio_OD_stream_id].input_udta)->rap = 1; /*we have the descriptor; now call this callback recursively so that a player gets the audio descriptor before audio data.*/ @@ -1173,7 +1223,9 @@ static u32 seng_output(void *param) u64 last_src_modif, mod_time; M2TSSource *source = (M2TSSource *)param; GF_SceneEngine *seng = source->seng; +#ifndef GPAC_DISABLE_PLAYER GF_SimpleDataDescriptor *audio_desc; +#endif Bool update_context=0; Bool force_rap, adjust_carousel_time, discard_pending, signal_rap, signal_critical, version_inc, aggregate_au; u32 period, ts_delta; @@ -1185,6 +1237,7 @@ static u32 seng_output(void *param) last_src_modif = source->bifs_src_name ? gf_file_modification_time(source->bifs_src_name) : 0; /*send the audio descriptor*/ +#ifndef GPAC_DISABLE_PLAYER if (source->mpeg4_signaling==GF_M2TS_MPEG4_SIGNALING_FULL && audio_OD_stream_id!=(u32)-1) { audio_desc = source->streams[audio_OD_stream_id].input_udta; if (audio_desc && audio_desc->data) /*RTP/UDP + MP3 case*/ @@ -1199,6 +1252,7 @@ static u32 seng_output(void *param) source->streams[audio_OD_stream_id].input_udta = NULL; } } +#endif while (run) { if (!gf_prompt_has_input()) { @@ -1361,7 +1415,11 @@ void fill_seng_es_ifce(GF_ESInterface *ifce, u32 i, GF_SceneEngine *seng, u32 pe ifce->repeat_rate = period; GF_SAFEALLOC(stream, GF_ESIStream); - memset(stream, 0, sizeof(GF_ESIStream)); + if (!stream) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate SENG input handler\n")); + return; + } + stream->rap = 1; if (ifce->input_udta) gf_free(ifce->input_udta); @@ -1382,7 +1440,6 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp #ifndef GPAC_DISABLE_STREAMING GF_SDPInfo *sdp; #endif - s64 min_offset = 0; memset(source, 0, sizeof(M2TSSource)); source->mpeg4_signaling = mpeg4_signaling; @@ -1393,8 +1450,11 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp u32 i; u32 nb_tracks; Bool has_bifs_od = 0; + Bool temi_assigned = 0; u32 first_audio = 0; u32 first_other = 0; + s64 min_offset = 0; + u32 min_offset_timescale = 0; source->mp4 = gf_isom_open(src, GF_ISOM_OPEN_READ, 0); source->nb_streams = 0; source->real_time = force_real_time; @@ -1408,8 +1468,10 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp continue; fill_isom_es_ifce(source, &source->streams[i], source->mp4, i+1, bifs_use_pes, compute_max_size); - if (min_offset > ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset) + if (min_offset > ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset) { min_offset = ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset; + min_offset_timescale = source->streams[i].timescale; + } switch(source->streams[i].stream_type) { case GF_STREAM_OD: @@ -1433,12 +1495,16 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp /*get first visual stream as PCR*/ if (!source->pcr_idx) { source->pcr_idx = i+1; - if (temi_url) { - ((GF_ESIMP4 *)source->streams[i].input_udta)->insert_temi = GF_TRUE; - if (insert_ntp) - ((GF_ESIMP4 *)source->streams[i].input_udta)->insert_ntp = GF_TRUE; - if (strcmp(temi_url, "NOTEMIURL")) + if ((temi_id_1>=0) || (temi_id_2>=0)) { + temi_assigned = GF_TRUE; + ((GF_ESIMP4 *)source->streams[i].input_udta)->timeline_id = (u32) ( (temi_id_1>=0) ? temi_id_1 + 1 : temi_id_2 + 1 ); + ((GF_ESIMP4 *)source->streams[i].input_udta)->insert_ntp = insert_ntp; + + if (temi_url && (temi_id_1>=0)) ((GF_ESIMP4 *)source->streams[i].input_udta)->temi_url = temi_url; + + if (temi_id_1>=0) temi_id_1 = -1; + else temi_id_2 = -1; } } } @@ -1475,6 +1541,16 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } } if (has_bifs_od && !source->mpeg4_signaling) source->mpeg4_signaling = GF_M2TS_MPEG4_SIGNALING_FULL; + if ( !temi_assigned && first_audio && ((temi_id_1>=0) || (temi_id_2>=0) ) ) { + ((GF_ESIMP4 *)source->streams[first_audio-1].input_udta)->timeline_id = (u32) ( (temi_id_1>=0) ? temi_id_1 + 1 : temi_id_2 + 1 ); + ((GF_ESIMP4 *)source->streams[first_audio-1].input_udta)->insert_ntp = insert_ntp; + + if (temi_url && (temi_id_1>=0) ) + ((GF_ESIMP4 *)source->streams[first_audio-1].input_udta)->temi_url = temi_url; + + if (temi_id_1>=0) temi_id_1 = -1; + else temi_id_2 = -1; + } /*if no visual PCR found, use first audio*/ if (!source->pcr_idx) source->pcr_idx = first_audio; @@ -1488,7 +1564,9 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp if (min_offset < 0) { for (i=0; inb_streams; i++) { - ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset += -min_offset; + Double scale = source->streams[i].timescale; + scale /= min_offset_timescale; + ((GF_ESIMP4 *)source->streams[i].input_udta)->ts_offset += (s64) (-min_offset * scale); } } @@ -1658,6 +1736,7 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } } +#ifndef GPAC_DISABLE_PLAYER /*when an audio input is present, declare it and store OD + ESD_U*/ if (audio_input_ip) { /*add the audio program*/ @@ -1674,6 +1753,11 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp source->streams[source->nb_streams].timescale = 1000; GF_SAFEALLOC(source->streams[source->nb_streams].input_udta, GF_ESIStream); + if (!source->streams[source->nb_streams].input_udta) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate audio input handler\n")); + return 0; + } + ((GF_ESIStream*)source->streams[source->nb_streams].input_udta)->vers_inc = 1; /*increment version number at every audio update*/ assert( source ); //assert( source->iod); @@ -1715,6 +1799,7 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } source->nb_streams++; } +#endif /*when an audio input is present, declare it and store OD + ESD_U*/ if (video_buffer) { @@ -1726,6 +1811,10 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp source->streams[source->nb_streams].timescale = 1000; GF_SAFEALLOC(source->streams[source->nb_streams].input_udta, GF_ESIStream); + if (!source->streams[source->nb_streams].input_udta) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to allocate video input handler\n")); + return 0; + } ((GF_ESIStream*)source->streams[source->nb_streams].input_udta)->vers_inc = 1; /*increment version number at every video update*/ assert(source); @@ -1783,7 +1872,7 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } #ifdef GPAC_MEMORY_TRACKING -static Bool enable_mem_tracker = GF_FALSE; +GF_MemTrackerType mem_track = GF_MemTrackerNone; #endif /*macro to keep retro compatibility with '=' and spaces in parse_args*/ @@ -1792,12 +1881,12 @@ static Bool enable_mem_tracker = GF_FALSE; || ((strlen(arg) == strlen(param)) && ++i && (i 150) { - fprintf(stderr, "URLs longer than 150 bytes are not currently supported\n"); - return GF_NOT_SUPPORTED; + u32 temi_id = 0; + if (sscanf(next_arg, "%d", &temi_id) == 1) { + if (temi_id < 0x80 || temi_id>0xFF) { + fprintf(stderr, "TEMI external timeline IDs shall be in the range [0x80, 0xFF], but %d was specified\n", temi_id); + return GF_BAD_PARAM; + } + } + if (!temi_id) { + *temi_url = next_arg; + if (strlen(next_arg) > 150) { + fprintf(stderr, "URLs longer than 150 bytes are not currently supported\n"); + return GF_NOT_SUPPORTED; + } + temi_id_1 = 0; + } else { + temi_id_1 = temi_id; + *temi_url = NULL; } } - } - else if (CHECK_PARAM("-temi-delay")) { + } else if (CHECK_PARAM("-temi2")) { + u32 temi_id = 0; + if (next_arg[0]=='-') { + fprintf(stderr, "No ID for secondary external TEMI timeline specified\n"); + return GF_BAD_PARAM; + } + if (sscanf(next_arg, "%d", &temi_id) == 1) { + if (temi_id < 0x80 || temi_id>0xFF) { + fprintf(stderr, "TEMI external timeline IDs shall be in the range [0x80, 0xFF], but %d was specified\n", temi_id); + return GF_BAD_PARAM; + } + temi_id_2 = temi_id; + } else { + fprintf(stderr, "No ID for secondary external TEMI timeline specified\n"); + return GF_BAD_PARAM; + } + } else if (CHECK_PARAM("-temi-delay")) { temi_url_insertion_delay = atoi(next_arg); } else if (CHECK_PARAM("-temi-offset")) { temi_offset = atoi(next_arg); @@ -2061,7 +2183,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car if (*real_time) force_real_time = 1; rate_found = 1; - /*second pass: other*/ + /*second pass: open sources*/ for (i=1; i=0) gf_m2ts_mux_set_initial_pcr(muxer, (u64) pcr_init_val); gf_m2ts_mux_set_pcr_max_interval(muxer, pcr_ms); + gf_m2ts_mux_enable_pcr_only_packets(muxer, enable_forced_pcr); + if (ts_out != NULL) { if (segment_duration) { @@ -2400,7 +2528,7 @@ int main(int argc, char **argv) fprintf(stderr, "Error initializing UDP socket for %s:%d : %s\n", audio_input_ip, audio_input_port, gf_error_to_string(e)); goto exit; } - gf_sk_set_buffer_size(audio_input_udp_sk, 0, UDP_BUFFER_SIZE); + gf_sk_set_buffer_size(audio_input_udp_sk, 0, GF_M2TS_UDP_BUFFER_SIZE); gf_sk_set_block_mode(audio_input_udp_sk, 0); /*allocate data buffer*/ @@ -2647,7 +2775,7 @@ call_flush: u32 now=gf_sys_clock(); if (now > last_print_time + MP42TS_PRINT_TIME_MS) { last_print_time = now; - fprintf(stderr, "M2TS: time % 6d - TS time % 6d - avg bitrate % 8d\r", gf_m2ts_get_sys_clock(muxer), gf_m2ts_get_ts_clock(muxer), muxer->average_birate_kbps); + fprintf(stderr, "M2TS: time % 6d - TS time % 6d - bitrate % 8d\r", gf_m2ts_get_sys_clock(muxer), gf_m2ts_get_ts_clock(muxer), muxer->average_birate_kbps); if (gf_prompt_has_input()) { char c = gf_prompt_get_char(); @@ -2683,10 +2811,10 @@ call_flush: { u64 bits = muxer->tot_pck_sent*8*188; - u32 dur_sec = gf_m2ts_get_ts_clock(muxer) / 1000; - if (!dur_sec) dur_sec = 1; - fprintf(stderr, "Done muxing - %d sec - average rate %d kbps "LLD" packets written\n", dur_sec, (u32) (bits/dur_sec/1000), muxer->tot_pck_sent); - fprintf(stderr, "\tPadding: "LLD" packets - "LLD" PES padded bytes (%g kbps)\n", muxer->tot_pad_sent, muxer->tot_pes_pad_bytes, (Double) (muxer->tot_pes_pad_bytes*8.0/dur_sec/1000) ); + u64 dur_ms = gf_m2ts_get_ts_clock(muxer); + if (!dur_ms) dur_ms = 1; + fprintf(stderr, "Done muxing - %.02f sec - %sbitrate %d kbps "LLD" packets written\n", ((Double) dur_ms)/1000.0,mux_rate ? "" : "average ", (u32) (bits/dur_ms), muxer->tot_pck_sent); + fprintf(stderr, " Padding: "LLD" packets (%g kbps) - "LLD" PES padded bytes (%g kbps)\n", muxer->tot_pad_sent, (Double) (muxer->tot_pad_sent*188*8.0/dur_ms) , muxer->tot_pes_pad_bytes, (Double) (muxer->tot_pes_pad_bytes*8.0/dur_ms) ); } exit: @@ -2745,8 +2873,9 @@ exit: gf_sys_close(); #ifdef GPAC_MEMORY_TRACKING - if (enable_mem_tracker && (gf_memory_size() || gf_file_handles_count() )) { - gf_memory_print(); + if (mem_track && (gf_memory_size() || gf_file_handles_count() )) { + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); + gf_memory_print(); return 2; } #endif diff --git a/applications/mp42ts/mp42ts.h b/applications/mp42ts/mp42ts.h deleted file mode 100644 index e1038a8..0000000 --- a/applications/mp42ts/mp42ts.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * GPAC - Multimedia Framework C SDK - * - * Authors: Jean Le Feuvre, Cyril Concolato, Romain Bouqueau - * Copyright (c) Telecom ParisTech 2005-2012 - * All rights reserved - * - * This file is part of GPAC / mp42ts application - * - * 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 -#include -#include -#include - - -typedef struct __m2ts_mux_program M2TS_Mux_Program; -typedef struct __m2ts_mux M2TS_Mux; - -enum { - LOG_NO_LOG = 0, - LOG_PES = 1, - LOG_SECTION = 2, - LOG_TS = 3 -}; - - -typedef struct __m2ts_section { - struct __m2ts_section *next; - u8 *data; - u32 length; -} M2TS_Mux_Section; - -typedef struct __m2ts_table { - struct __m2ts_table *next; - u8 table_id; - u8 version_number; - struct __m2ts_section *section; -} M2TS_Mux_Table; - -typedef struct -{ - u32 sec; - u32 nanosec; -} M2TS_Time; - - -typedef struct __m2ts_mux_pck -{ - struct __m2ts_mux_pck *next; - char *data; - u32 data_len; - u32 flags; - u64 cts, dts; -} M2TS_Packet; - - -typedef struct __m2ts_mux_stream { - struct __m2ts_mux_stream *next; - - u32 pid; - u8 continuity_counter; - struct __m2ts_mux_program *program; - - /*average stream bit-rate in bit/sec*/ - u32 bit_rate; - - /*multiplexer time - NOT THE PCR*/ - M2TS_Time time; - - - /* MPEG-4 SL Config */ - GF_SLConfig sl_config; - - /*table tools*/ - M2TS_Mux_Table *tables; - /*total table sizes for bitrate estimation (PMT/PAT/...)*/ - u32 total_table_size; - /* used for on-the-fly packetization of sections */ - M2TS_Mux_Table *current_table; - M2TS_Mux_Section *current_section; - u32 current_section_offset; - u32 refresh_rate_ms; - Bool table_needs_update; - - Bool (*process)(struct __m2ts_mux *muxer, struct __m2ts_mux_stream *stream); - - /*PES tools*/ - void *pes_packetizer; - u32 mpeg2_stream_type; - u32 mpeg2_stream_id; - - GF_ESIPacket pck; - u32 pck_offset; - Bool force_new; - - struct __elementary_stream_ifce *ifce; - Double ts_scale; - u64 initial_ts; - - /*packet fifo*/ - M2TS_Packet *pck_first, *pck_last; - /*packet reassembler (PES packets are most of the time full frames)*/ - M2TS_Packet *pck_reassembler; - GF_Mutex *mx; - /*avg bitrate compute*/ - u64 last_br_time; - u32 bytes_since_last_time; - - /*MPEG-4 over MPEG-2*/ - u8 table_id; - GF_SLHeader sl_header; - //GF_SLConfig sl_config; - - u32 last_aac_time; -} M2TS_Mux_Stream; - - -struct __m2ts_mux_program { - struct __m2ts_mux_program *next; - - struct __m2ts_mux *mux; - u16 number; - /*all streams but PMT*/ - M2TS_Mux_Stream *streams; - /*PMT*/ - M2TS_Mux_Stream *pmt; - /*pointer to PCR stream*/ - M2TS_Mux_Stream *pcr; - - /*TS time at pcr init*/ - M2TS_Time ts_time_at_pcr_init; - u64 pcr_init_time, num_pck_at_pcr_init; - u64 last_pcr; - u32 last_sys_clock; - - GF_Descriptor *iod; -}; - -struct __m2ts_mux { - M2TS_Mux_Program *programs; - M2TS_Mux_Stream *pat; - - u16 ts_id; - - Bool needs_reconfig; - - /* used to indicate that the input data is pushed to the muxer (i.e. not read from a file) - or that the output data is sent on sockets (not written to a file) */ - Bool real_time; - - /* indicates if the multiplexer shall target a fix bit rate (monitoring timing and produce padding packets) - or if the output stream will contain only input data*/ - Bool fixed_rate; - - /*output bit-rate in bit/sec*/ - u32 bit_rate; - - char dst_pck[188], null_pck[188]; - - /*multiplexer time, incremented each time a packet is sent - used to monitor the sending of muxer related data (PAT, ...) */ - M2TS_Time time; - - /* Time of the muxer when the first call to process is made (first packet sent?) */ - M2TS_Time init_ts_time; - - /* System time when the muxer is started */ - u32 init_sys_time; - - Bool eos_found; - u32 pck_sent_over_br_window, last_br_time, avg_br; - u64 tot_pck_sent, tot_pad_sent; - - Bool mpeg4_signaling; -}; - - -enum -{ - GF_M2TS_STATE_IDLE, - GF_M2TS_STATE_DATA, - GF_M2TS_STATE_PADDING, - GF_M2TS_STATE_EOS, -}; - diff --git a/applications/mp4box/Makefile b/applications/mp4box/Makefile index fde035a..83f7bad 100644 --- a/applications/mp4box/Makefile +++ b/applications/mp4box/Makefile @@ -14,26 +14,26 @@ CFLAGS+=-pg LDFLAGS+=-pg endif -#common obj -OBJS=main.o filedump.o fileimport.o -ifeq ($(DISABLE_STREAMING),no) -OBJS+=live.o +LINKFLAGS=-L../../bin/gcc -L../../extra_lib/lib/gcc + +ifeq ($(STATICBUILD),yes) +##include static modules and other deps for libgpac +include ../../static.mak +LINKFLAGS+=-lgpac_static +LINKFLAGS+= $(GPAC_SH_FLAGS) +LINKFLAGS+=$(EXTRALIBS) +else +LINKFLAGS+=-lgpac endif -LINKFLAGS=-L../../bin/gcc -L../../extra_lib/lib/gcc ifeq ($(CONFIG_WIN32),yes) EXE=.exe PROG=MP4Box$(EXE) +LINKFLAGS+=$(UNICODEFLAGS) -ifeq ($(MP4BOX_STATIC),yes) -LINKFLAGS+=-lgpac_static $(EXTRALIBS) -ifneq ($(CONFIG_ZLIB),no) -LINKFLAGS+=-lz -endif - -else -LINKFLAGS+=-lgpac +ifeq ($(HAS_WMAIN),no) +CFLAGS+=-DNO_WMAIN endif else @@ -42,36 +42,26 @@ EXT= PROG=MP4Box ifeq ($(MP4BOX_STATIC),yes) - -LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) - -ifneq ($(CONFIG_ZLIB),no) -LINKFLAGS+=-lz +LINKFLAGS+= $(GPAC_SH_FLAGS) endif -# spidermonkey support -ifeq ($(CONFIG_JS),no) -else -SCENEGRAPH_CFLAGS+=$(JS_FLAGS) -ifeq ($(CONFIG_JS),local) -NEED_LOCAL_LIB="yes" -endif -LINKFLAGS+=$(JS_LIBS) endif -else -LINKFLAGS+=-lgpac -endif +#common obj +OBJS=main.o filedump.o fileimport.o +ifeq ($(DISABLE_STREAMING),no) +OBJS+=live.o endif + SRCS := $(OBJS:.o=.c) all: $(PROG) $(PROG): $(OBJS) - $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) + $(CC) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS) $(LDFLAGS) clean: rm -f $(OBJS) ../../bin/gcc/$(PROG) diff --git a/applications/mp4box/filedump.c b/applications/mp4box/filedump.c index b2ca565..c9499ba 100644 --- a/applications/mp4box/filedump.c +++ b/applications/mp4box/filedump.c @@ -53,12 +53,14 @@ #include #endif #include +#include +#include extern u32 swf_flags; extern Float swf_flatten_angle; extern GF_FileType get_file_type_by_ext(char *inName); -void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist); +void scene_coding_log(void *cbk, GF_LOG_Level log_level, GF_LOG_Tool log_tool, const char *fmt, va_list vlist); #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample); @@ -82,7 +84,7 @@ static const char *GetLanguage(char *lcode) return lcode; } -GF_Err dump_cover_art(GF_ISOFile *file, char *inName) +GF_Err dump_isom_cover_art(GF_ISOFile *file, char *inName, Bool is_final_name) { const char *tag; char szName[1024]; @@ -97,11 +99,23 @@ GF_Err dump_cover_art(GF_ISOFile *file, char *inName) return e; } - sprintf(szName, "%s.%s", inName, (tag_len>>31) ? "png" : "jpg"); - t = gf_fopen(szName, "wb"); + if (inName) { + if (is_final_name) { + strcpy(szName, inName); + } else { + sprintf(szName, "%s.%s", inName, (tag_len>>31) ? "png" : "jpg"); + } + t = gf_fopen(szName, "wb"); + if (!t) { + fprintf(stderr, "Failed to open %s for dumping\n", szName); + return GF_IO_ERR; + } + } else { + t = stdout; + } gf_fwrite(tag, tag_len & 0x7FFFFFFF, 1, t); - gf_fclose(t); + if (inName) gf_fclose(t); return GF_OK; } @@ -132,7 +146,7 @@ GF_Err set_cover_art(GF_ISOFile *file, char *inName) #ifndef GPAC_DISABLE_SCENE_DUMP -GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bool do_log) +GF_Err dump_isom_scene(char *file, char *inName, Bool is_final_name, GF_SceneDumpFormat dump_mode, Bool do_log) { GF_Err e; GF_SceneManager *ctx; @@ -141,7 +155,6 @@ GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bo GF_FileType ftype; gf_log_cbk prev_logs = NULL; FILE *logs = NULL; - e = GF_OK; sg = gf_sg_new(); ctx = gf_sm_new(sg); @@ -208,7 +221,7 @@ GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bo else fprintf(stderr, "Scene loaded - dumping root scene\n"); - e = gf_sm_dump(ctx, inName, dump_mode); + e = gf_sm_dump(ctx, inName, is_final_name, dump_mode); } gf_sm_del(ctx); @@ -343,7 +356,7 @@ static void ReorderAU(GF_List *sample_list, GF_AUContext *au) gf_list_add(sample_list, au); } -void dump_scene_stats(char *file, char *inName, u32 stat_level) +void dump_isom_scene_stats(char *file, char *inName, Bool is_final_name, u32 stat_level) { GF_Err e; FILE *dump; @@ -385,11 +398,15 @@ void dump_scene_stats(char *file, char *inName, u32 stat_level) if (inName) { strcpy(szBuf, inName); - strcat(szBuf, "_stat.xml"); + 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); + return; + } close = 1; } else { - dump = stderr; + dump = stdout; close = 0; } @@ -462,6 +479,7 @@ exit: if (sm) gf_sm_stats_del(sm); gf_sm_del(ctx); gf_sg_del(scene_graph); + if (load.isom) gf_isom_delete(load.isom); if (e) { fprintf(stderr, "%s\n", gf_error_to_string(e)); } else { @@ -556,11 +574,7 @@ void PrintNode(const char *name, u32 graph_type) is_nodefield = 1; } - tag = 0; - if (graph_type==2) { - fprintf(stderr, "SVG node printing is not supported\n"); - return; - } else if (graph_type==1) { + if (graph_type==1) { #ifndef GPAC_DISABLE_X3D tag = gf_node_x3d_type_by_class_name(name); std_name = "X3D"; @@ -733,29 +747,21 @@ void PrintBuiltInNodes(u32 graph_type) #endif } -#ifndef GPAC_DISABLE_ISOM_DUMP -void dump_isom_xml(GF_ISOFile *file, char *inName) +void PrintBuiltInBoxes() { - FILE *dump; - char szBuf[1024]; - - if (inName) { - strcpy(szBuf, inName); - strcat(szBuf, "_info.xml"); - dump = gf_fopen(szBuf, "wt"); - gf_isom_dump(file, dump); - gf_fclose(dump); - } else { - gf_isom_dump(file, stderr); + u32 i, count=gf_isom_get_num_supported_boxes(); + fprintf(stdout, "\n"); + //index 0 is our internal unknown box handler + for (i=1; i\n"); } -#endif - #if !defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_ISOM_DUMP) -void dump_file_rtp(GF_ISOFile *file, char *inName) +void dump_isom_rtp(GF_ISOFile *file, char *inName, Bool is_final_name) { u32 i, j, size; FILE *dump; @@ -764,10 +770,14 @@ void dump_file_rtp(GF_ISOFile *file, char *inName) if (inName) { strcpy(szBuf, inName); - strcat(szBuf, "_rtp.xml"); + if (!is_final_name) strcat(szBuf, "_rtp.xml"); dump = gf_fopen(szBuf, "wt"); + if (!dump) { + fprintf(stderr, "Failed to open %s\n", szBuf); + return; + } } else { - dump = stderr; + dump = stdout; } fprintf(dump, "\n"); @@ -791,7 +801,8 @@ void dump_file_rtp(GF_ISOFile *file, char *inName) } #endif -void dump_file_timestamps(GF_ISOFile *file, char *inName) + +void dump_isom_timestamps(GF_ISOFile *file, char *inName, Bool is_final_name) { u32 i, j, k, count; Bool has_error; @@ -800,17 +811,23 @@ void dump_file_timestamps(GF_ISOFile *file, char *inName) if (inName) { strcpy(szBuf, inName); - strcat(szBuf, "_ts.txt"); + if (!is_final_name) strcat(szBuf, "_ts.txt"); dump = gf_fopen(szBuf, "wt"); + if (!dump) { + fprintf(stderr, "Failed to open %s\n", szBuf); + return; + } } else { - dump = stderr; + dump = stdout; } has_error = 0; for (i=0; iDTS; cts = dts + (s32) samp->CTS_Offset; fprintf(dump, "Sample %d\tDTS "LLD"\tCTS "LLD"\t%d\t%d\t"LLD"\t%d\t%d\t%d\t%d\t%d\t%d\t%d", j+1, LLD_CAST dts, LLD_CAST cts, samp->dataLength, samp->IsRAP, offset, isLeading, dependsOn, dependedOn, redundant, is_rap, has_roll, roll_distance); if (cts> 1; + res = gf_media_hevc_parse_nalu(ptr, ptr_size, hevc, &type, &temporal_id, &quality_id); + fprintf(dump, "code=\"%d\" type=\"", type); switch (type) { case GF_HEVC_NALU_SLICE_TRAIL_N: @@ -978,16 +1014,20 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ break; case GF_HEVC_NALU_VID_PARAM: + gf_media_hevc_read_vps(ptr, ptr_size, hevc); fputs("Video Parameter Set", dump); break; case GF_HEVC_NALU_SEQ_PARAM: + gf_media_hevc_read_sps(ptr, ptr_size, hevc); fputs("Sequence Parameter Set", dump); break; case GF_HEVC_NALU_PIC_PARAM: + gf_media_hevc_read_pps(ptr, ptr_size, hevc); fputs("Picture Parameter Set", dump); break; case GF_HEVC_NALU_ACCESS_UNIT: fputs("AU Delimiter", dump); + fprintf(dump, "\" primary_pic_type=\"%d", ptr[2] >> 5); break; case GF_HEVC_NALU_END_OF_SEQ: fputs("End of Sequence", dump); @@ -1009,23 +1049,31 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ break; case 49: fputs("HEVCExtractor", dump); - track_ref_index = (u8) ptr[2]; - sample_offset = (s8) ptr[3]; - data_offset = read_nal_size_hdr(&ptr[4], nalh_size); - data_size = read_nal_size_hdr(&ptr[4+nalh_size], nalh_size); + track_ref_index = (u8) ptr[3]; + sample_offset = (s8) ptr[4]; + data_offset = read_nal_size_hdr(&ptr[5], nalh_size); + data_size = read_nal_size_hdr(&ptr[5+nalh_size], nalh_size); fprintf(dump, "\" track_ref_index=\"%d\" sample_offset=\"%d\" data_offset=\"%d\" data_size=\"%d", track_ref_index, sample_offset, data_offset, data_size); break; default: - fputs("UNKNOWN", dump); + fprintf(dump, "UNKNOWN (parsing return %d)", res); break; } fputs("\"", dump); if ((type==GF_HEVC_NALU_SEI_PREFIX) || (type==GF_HEVC_NALU_SEI_SUFFIX)) { - dump_sei(dump, (u8 *) ptr, ptr_size, is_hevc); + dump_sei(dump, (u8 *) ptr, ptr_size, hevc ? GF_TRUE : GF_FALSE); } - fprintf(dump, " layer_id=\"%d\" temporal_id=\"%d\"", ((ptr[0] & 0x1) << 5) | (ptr[1]>>3), (ptr[1] & 0x7) ); + if (types_info.slice_type==GF_HEVC_SLICE_TYPE_I) ? "I" : (hevc->s_info.slice_type==GF_HEVC_SLICE_TYPE_P) ? "P" : (hevc->s_info.slice_type==GF_HEVC_SLICE_TYPE_B) ? "B" : "Unknown", hevc->s_info.poc); + fprintf(dump, " first_slice_in_pic=\"%d\"", hevc->s_info.first_slice_segment_in_pic_flag); + fprintf(dump, " dependent_slice_segment=\"%d\"", hevc->s_info.dependent_slice_segment_flag); + } + + fprintf(dump, " layer_id=\"%d\" temporal_id=\"%d\"", quality_id, temporal_id); + #endif //GPAC_DISABLE_HEVC return; } @@ -1065,15 +1113,45 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ idx = gf_media_avc_read_sps(ptr, ptr_size, avc, 0, NULL); assert (idx >= 0); fprintf(dump, "\" sps_id=\"%d", idx); + fprintf(dump, "\" frame_mbs_only_flag=\"%d", avc->sps->frame_mbs_only_flag); + fprintf(dump, "\" mb_adaptive_frame_field_flag=\"%d", avc->sps->mb_adaptive_frame_field_flag); + fprintf(dump, "\" vui_parameters_present_flag=\"%d", avc->sps->vui_parameters_present_flag); + fprintf(dump, "\" max_num_ref_frames=\"%d", avc->sps->max_num_ref_frames); + fprintf(dump, "\" gaps_in_frame_num_value_allowed_flag=\"%d", avc->sps->gaps_in_frame_num_value_allowed_flag); + fprintf(dump, "\" chroma_format_idc=\"%d", avc->sps->chroma_format); + fprintf(dump, "\" bit_depth_luma_minus8=\"%d", avc->sps->luma_bit_depth_m8); + fprintf(dump, "\" bit_depth_chroma_minus8=\"%d", avc->sps->chroma_bit_depth_m8); + fprintf(dump, "\" width=\"%d", avc->sps->width); + fprintf(dump, "\" height=\"%d", avc->sps->height); + fprintf(dump, "\" crop_top=\"%d", avc->sps->crop.top); + fprintf(dump, "\" crop_left=\"%d", avc->sps->crop.left); + fprintf(dump, "\" crop_bottom=\"%d", avc->sps->crop.bottom); + fprintf(dump, "\" crop_right=\"%d", avc->sps->crop.right); + if (avc->sps->vui_parameters_present_flag) { + fprintf(dump, "\" vui_video_full_range_flag=\"%d", avc->sps->vui.video_full_range_flag); + fprintf(dump, "\" vui_video_signal_type_present_flag=\"%d", avc->sps->vui.video_signal_type_present_flag); + fprintf(dump, "\" vui_aspect_ratio_info_present_flag=\"%d", avc->sps->vui.aspect_ratio_info_present_flag); + fprintf(dump, "\" vui_aspect_ratio_num=\"%d", avc->sps->vui.par_num); + fprintf(dump, "\" vui_aspect_ratio_den=\"%d", avc->sps->vui.par_den); + fprintf(dump, "\" vui_overscan_info_present_flag=\"%d", avc->sps->vui.overscan_info_present_flag); + fprintf(dump, "\" vui_colour_description_present_flag=\"%d", avc->sps->vui.colour_description_present_flag); + fprintf(dump, "\" vui_colour_primaries=\"%d", avc->sps->vui.colour_primaries); + fprintf(dump, "\" vui_transfer_characteristics=\"%d", avc->sps->vui.transfer_characteristics); + fprintf(dump, "\" vui_matrix_coefficients=\"%d", avc->sps->vui.matrix_coefficients); + fprintf(dump, "\" vui_low_delay_hrd_flag=\"%d", avc->sps->vui.low_delay_hrd_flag); + } break; case GF_AVC_NALU_PIC_PARAM: fputs("PictureParameterSet", dump); idx = gf_media_avc_read_pps(ptr, ptr_size, avc); assert (idx >= 0); fprintf(dump, "\" pps_id=\"%d\" sps_id=\"%d", idx, avc->pps[idx].sps_id); + fprintf(dump, "\" entropy_coding_mode_flag=\"%d", avc->pps[idx].entropy_coding_mode_flag); + break; case GF_AVC_NALU_ACCESS_UNIT: fputs("AccessUnit delimiter", dump); + fprintf(dump, "\" primary_pic_type=\"%d", gf_bs_read_u8(bs) >> 5); break; case GF_AVC_NALU_END_OF_SEQ: fputs("EndOfSequence", dump); @@ -1128,7 +1206,7 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ fputs("\"", dump); if (type==GF_AVC_NALU_SEI) { - dump_sei(dump, (u8 *) ptr, ptr_size, is_hevc); + dump_sei(dump, (u8 *) ptr, ptr_size, GF_FALSE); } if (res<0) @@ -1138,44 +1216,35 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ } #endif -void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) +void dump_isom_nal_ex(GF_ISOFile *file, u32 trackID, FILE *dump) { u32 i, count, track, nalh_size, timescale, cur_extract_mode; - FILE *dump; s32 countRef; Bool is_adobe_protection = GF_FALSE; #ifndef GPAC_DISABLE_AV_PARSERS Bool is_hevc = GF_FALSE; AVCState avc; + HEVCState hevc; GF_AVCConfig *avccfg, *svccfg; - GF_HEVCConfig *hevccfg, *shvccfg; + GF_HEVCConfig *hevccfg, *lhvccfg; GF_AVCConfigSlot *slc; #endif track = gf_isom_get_track_by_id(file, trackID); - nalh_size = 0; #ifndef GPAC_DISABLE_AV_PARSERS memset(&avc, 0, sizeof(AVCState)); avccfg = gf_isom_avc_config_get(file, track, 1); svccfg = gf_isom_svc_config_get(file, track, 1); + memset(&hevc, 0, sizeof(HEVCState)); hevccfg = gf_isom_hevc_config_get(file, track, 1); - shvccfg = gf_isom_shvc_config_get(file, track, 1); - if (!avccfg && !svccfg && !hevccfg && !shvccfg) { + lhvccfg = gf_isom_lhvc_config_get(file, track, 1); + if (!avccfg && !svccfg && !hevccfg && !lhvccfg) { fprintf(stderr, "Error: Track #%d is not NALU-based!\n", trackID); return; } #endif - if (inName) { - char szBuf[GF_MAX_PATH]; - strcpy(szBuf, inName); - sprintf(szBuf, "%s_%d_nalu.xml", inName, trackID); - dump = gf_fopen(szBuf, "wt"); - } else { - dump = stderr; - } - count = gf_isom_get_sample_count(file, track); timescale = gf_isom_get_media_timescale(file, track); @@ -1193,14 +1262,16 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) } fprintf(dump, " \n"); -#define DUMP_ARRAY(arr, name)\ +#define DUMP_ARRAY(arr, name, loc)\ if (arr) {\ + fprintf(dump, " <%sArray location=\"%s\">\n", name, loc);\ for (i=0; isize);\ - dump_nalu(dump, slc->data, slc->size, svccfg ? 1 : 0, is_hevc, &avc, nalh_size);\ + fprintf(dump, " size);\ + dump_nalu(dump, slc->data, slc->size, svccfg ? 1 : 0, is_hevc ? &hevc : NULL, &avc, nalh_size);\ fprintf(dump, "/>\n");\ }\ + fprintf(dump, " \n", name);\ }\ nalh_size = 0; @@ -1208,14 +1279,14 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) if (avccfg) { nalh_size = avccfg->nal_unit_size; - DUMP_ARRAY(avccfg->sequenceParameterSets, "AVCSPSArray") - DUMP_ARRAY(avccfg->pictureParameterSets, "AVCPPSArray") - DUMP_ARRAY(avccfg->sequenceParameterSetExtensions, "AVCSPSExArray") + DUMP_ARRAY(avccfg->sequenceParameterSets, "AVCSPS", "avcC") + DUMP_ARRAY(avccfg->pictureParameterSets, "AVCPPS", "avcC") + DUMP_ARRAY(avccfg->sequenceParameterSetExtensions, "AVCSPSEx", "avcC") } if (svccfg) { if (!nalh_size) nalh_size = svccfg->nal_unit_size; - DUMP_ARRAY(svccfg->sequenceParameterSets, "SVCSPSArray") - DUMP_ARRAY(svccfg->pictureParameterSets, "SVCPPSArray") + DUMP_ARRAY(svccfg->sequenceParameterSets, "SVCSPS", "svcC") + DUMP_ARRAY(svccfg->pictureParameterSets, "SVCPPS", "svcC") } if (hevccfg) { #ifndef GPAC_DISABLE_HEVC @@ -1225,32 +1296,32 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) for (idx=0; idxparam_array); idx++) { GF_HEVCParamArray *ar = gf_list_get(hevccfg->param_array, idx); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { - DUMP_ARRAY(ar->nalus, "HEVCSPSArray") + DUMP_ARRAY(ar->nalus, "HEVCSPS", "hvcC") } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { - DUMP_ARRAY(ar->nalus, "HEVCPPSArray") + DUMP_ARRAY(ar->nalus, "HEVCPPS", "hvcC") } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { - DUMP_ARRAY(ar->nalus, "HEVCVPSArray") + DUMP_ARRAY(ar->nalus, "HEVCVPS", "hvcC") } else { - DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray") + DUMP_ARRAY(ar->nalus, "HEVCUnknownPS", "hvcC") } } #endif } - if (shvccfg) { + if (lhvccfg) { #ifndef GPAC_DISABLE_HEVC u32 idx; - nalh_size = shvccfg->nal_unit_size; + nalh_size = lhvccfg->nal_unit_size; is_hevc = 1; - for (idx=0; idxparam_array); idx++) { - GF_HEVCParamArray *ar = gf_list_get(shvccfg->param_array, idx); + for (idx=0; idxparam_array); idx++) { + GF_HEVCParamArray *ar = gf_list_get(lhvccfg->param_array, idx); if (ar->type==GF_HEVC_NALU_SEQ_PARAM) { - DUMP_ARRAY(ar->nalus, "HEVCSPSArray") + DUMP_ARRAY(ar->nalus, "HEVCSPS", "lhcC") } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) { - DUMP_ARRAY(ar->nalus, "HEVCPPSArray") + DUMP_ARRAY(ar->nalus, "HEVCPPS", "lhcC") } else if (ar->type==GF_HEVC_NALU_VID_PARAM) { - DUMP_ARRAY(ar->nalus, "HEVCVPSArray") + DUMP_ARRAY(ar->nalus, "HEVCVPS", "lhcC") } else { - DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray") + DUMP_ARRAY(ar->nalus, "HEVCUnknownPS", "lhcC") } } #endif @@ -1285,6 +1356,10 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) u32 size, nal_size, idx; char *ptr; GF_ISOSample *samp = gf_isom_get_sample(file, track, i+1, NULL); + if (!samp) { + fprintf(dump, "\n", i+1); + continue; + } dts = samp->DTS; cts = dts + (s32) samp->CTS_Offset; @@ -1316,7 +1391,7 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) } else { fprintf(dump, " \n"); } @@ -1333,22 +1408,41 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) fprintf(dump, " \n"); fprintf(dump, "\n"); - if (inName) gf_fclose(dump); #ifndef GPAC_DISABLE_AV_PARSERS if (avccfg) gf_odf_avc_cfg_del(avccfg); if (svccfg) gf_odf_avc_cfg_del(svccfg); #ifndef GPAC_DISABLE_HEVC if (hevccfg) gf_odf_hevc_cfg_del(hevccfg); - if (shvccfg) gf_odf_hevc_cfg_del(shvccfg); + if (lhvccfg) gf_odf_hevc_cfg_del(lhvccfg); #endif #endif gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode); } +void dump_isom_nal(GF_ISOFile *file, u32 trackID, char *inName, Bool is_final_name) +{ + FILE *dump; + if (inName) { + char szBuf[GF_MAX_PATH]; + strcpy(szBuf, inName); + if (!is_final_name) sprintf(szBuf, "%s_%d_nalu.xml", inName, trackID); + dump = gf_fopen(szBuf, "wt"); + if (!dump) { + fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + return; + } + } else { + dump = stdout; + } + dump_isom_nal_ex(file, gf_isom_get_track_id(file, trackID), dump); + + if (inName) gf_fclose(dump); +} + #ifndef GPAC_DISABLE_ISOM_DUMP -void dump_file_ismacryp(GF_ISOFile *file, char *inName) +void dump_isom_ismacryp(GF_ISOFile *file, char *inName, Bool is_final_name) { u32 i, j; FILE *dump; @@ -1356,10 +1450,14 @@ void dump_file_ismacryp(GF_ISOFile *file, char *inName) if (inName) { strcpy(szBuf, inName); - strcat(szBuf, "_ismacryp.xml"); + 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); + return; + } } else { - dump = stderr; + dump = stdout; } fprintf(dump, "\n"); @@ -1383,7 +1481,7 @@ void dump_file_ismacryp(GF_ISOFile *file, char *inName) } -void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_convert, GF_TextDumpType dump_type) +void dump_isom_timed_text(GF_ISOFile *file, u32 trackID, char *inName, Bool is_final_name, Bool is_convert, GF_TextDumpType dump_type) { FILE *dump; GF_Err e; @@ -1408,11 +1506,18 @@ void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_ if (inName) { char *ext; ext = ((dump_type==GF_TEXTDUMPTYPE_SVG) ? "svg" : ((dump_type==GF_TEXTDUMPTYPE_SRT) ? "srt" : "ttxt")); - if (is_convert) + if (is_final_name) { + strcpy(szBuf, inName) ; + } else if (is_convert) sprintf(szBuf, "%s.%s", inName, ext) ; else sprintf(szBuf, "%s_%d_text.%s", inName, trackID, ext); + dump = gf_fopen(szBuf, "wt"); + if (!dump) { + fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + return; + } } else { dump = stdout; } @@ -1427,7 +1532,7 @@ void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_ #ifndef GPAC_DISABLE_ISOM_HINTING -void DumpSDP(GF_ISOFile *file, char *inName) +void dump_isom_sdp(GF_ISOFile *file, char *inName, Bool is_final_name) { const char *sdp; u32 size, i; @@ -1437,12 +1542,18 @@ void DumpSDP(GF_ISOFile *file, char *inName) if (inName) { char *ext; strcpy(szBuf, inName); - ext = strchr(szBuf, '.'); - if (ext) ext[0] = 0; - strcat(szBuf, "_sdp.txt"); + if (!is_final_name) { + ext = strchr(szBuf, '.'); + if (ext) ext[0] = 0; + strcat(szBuf, "_sdp.txt"); + } dump = gf_fopen(szBuf, "wt"); + if (!dump) { + fprintf(stderr, "Failed to open %s for dumping\n", szBuf); + return; + } } else { - dump = stderr; + dump = stdout; fprintf(dump, "* File SDP content *\n\n"); } //get the movie SDP @@ -1462,6 +1573,107 @@ void DumpSDP(GF_ISOFile *file, char *inName) #endif + +#ifndef GPAC_DISABLE_ISOM_DUMP + +GF_Err dump_isom_xml(GF_ISOFile *file, char *inName, Bool is_final_name, Bool do_track_dump) +{ + GF_Err e; + FILE *dump = stdout; + Bool do_close=GF_FALSE; + char szBuf[1024]; + if (!file) return GF_ISOM_INVALID_FILE; + + if (inName) { + strcpy(szBuf, inName); + if (!is_final_name) { + strcat(szBuf, do_track_dump ? "_dump.xml" : "_info.xml"); + } + dump = gf_fopen(szBuf, "wt"); + if (!dump) { + fprintf(stderr, "Failed to open %s\n", szBuf); + return GF_IO_ERR; + } + do_close=GF_TRUE; + } + + fprintf(dump, "\n"); + if (do_track_dump) { + fprintf(dump, "\n"); + } + e = gf_isom_dump(file, dump); + if (e) { + fprintf(stderr, "Error dumping ISO structure\n"); + } + if ( gf_isom_get_track_count(file) == 0 ) + do_track_dump = GF_FALSE; + + if (do_track_dump) { + u32 i, j; + //because of dump mode we need to reopen in regular read mode to avoid mem leaks + GF_ISOFile *the_file = gf_isom_open(gf_isom_get_filename(file), GF_ISOM_OPEN_READ, NULL); + u32 tcount = gf_isom_get_track_count(the_file); + fprintf(dump, "\n"); + for (i=0; i\n", name, trackID); + + scount=gf_isom_get_sample_count(the_file, i+1); + for (j=0; j\n", name); + fmt_handled = GF_TRUE; + } + else if (gf_isom_get_avc_svc_type(the_file, i+1, 1) || gf_isom_get_hevc_lhvc_type(the_file, i+1, 1)) { + dump_isom_nal_ex(the_file, trackID, dump); + fmt_handled = GF_TRUE; + } else if ((mtype==GF_ISOM_MEDIA_TEXT) || (mtype==GF_ISOM_MEDIA_SUBT) ) { + + if (msubtype==GF_ISOM_SUBTYPE_WVTT) { + gf_webvtt_dump_iso_track(&dumper, NULL, i+1, GF_FALSE, GF_TRUE); + fmt_handled = GF_TRUE; + } else if ((msubtype==GF_ISOM_SUBTYPE_TX3G) || (msubtype==GF_ISOM_SUBTYPE_TEXT)) { + gf_isom_text_dump(the_file, i+1, dump, GF_TEXTDUMPTYPE_TTXT_BOXES); + fmt_handled = GF_TRUE; + } + } + + if (!fmt_handled) { + dumper.nhml_only = GF_TRUE; + dumper.flags = GF_EXPORT_NATIVE | GF_EXPORT_NHML | GF_EXPORT_NHML_FULL; + gf_media_export_nhml(&dumper, GF_FALSE); + } + } + gf_isom_delete(the_file); + fprintf(dump, "\n"); + } + fprintf(dump, "\n"); + if (do_close) gf_fclose(dump); + return e; +} +#endif + + static char *format_duration(u64 dur, u32 timescale, char *szDur) { u32 h, m, s, ms; @@ -1526,7 +1738,7 @@ void print_udta(GF_ISOFile *file, u32 track_number) fprintf(stderr, "\n"); } -GF_Err dump_udta(GF_ISOFile *file, char *inName, u32 dump_udta_type, u32 dump_udta_track) +GF_Err dump_isom_udta(GF_ISOFile *file, char *inName, Bool is_final_name, u32 dump_udta_type, u32 dump_udta_track) { char szName[1024], *data; FILE *t; @@ -1547,16 +1759,24 @@ GF_Err dump_udta(GF_ISOFile *file, char *inName, u32 dump_udta_type, u32 dump_ud if (e) { fprintf(stderr, "Error dumping UDTA %s: %s\n", gf_4cc_to_str(dump_udta_type), gf_error_to_string(e) ); return e; - } - sprintf(szName, "%s_%s.udta", inName, gf_4cc_to_str(dump_udta_type) ); - t = gf_fopen(szName, "wb"); - if (!t) { - gf_free(data); - fprintf(stderr, "Cannot open file %s\n", szName ); - return GF_IO_ERR; + } + if (inName) { + if (is_final_name) + strcpy(szName, inName); + else + sprintf(szName, "%s_%s.udta", inName, gf_4cc_to_str(dump_udta_type) ); + + t = gf_fopen(szName, "wb"); + if (!t) { + gf_free(data); + fprintf(stderr, "Cannot open file %s\n", szName ); + return GF_IO_ERR; + } + } else { + t = stdout; } res = (u32) fwrite(data, 1, count, t); - gf_fclose(t); + if (inName) gf_fclose(t); gf_free(data); if (count != res) { fprintf(stderr, "Error writing udta to file\n"); @@ -1567,25 +1787,27 @@ GF_Err dump_udta(GF_ISOFile *file, char *inName, u32 dump_udta_type, u32 dump_ud } -GF_Err dump_chapters(GF_ISOFile *file, char *inName, Bool dump_ogg) +GF_Err dump_isom_chapters(GF_ISOFile *file, char *inName, Bool is_final_name, Bool dump_ogg) { char szName[1024]; FILE *t; u32 i, count; count = gf_isom_get_chapter_count(file, 0); - strcpy(szName, inName); - if (dump_ogg) { - strcat(szName, ".txt"); - GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Extracting OGG chapters to %s\n", szName)); - } - else { - strcat(szName, ".chap"); - GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Extracting chapters to %s\n", szName)); + if (inName) { + strcpy(szName, inName); + if (!is_final_name) { + if (dump_ogg) { + strcat(szName, ".txt"); + } else { + strcat(szName, ".chap"); + } + } + t = gf_fopen(szName, "wt"); + if (!t) return GF_IO_ERR; + } else { + t = stdout; } - t = gf_fopen(szName, "wt"); - if (!t) return GF_IO_ERR; - for (i=0; iis_shvc ? "SHVC" : "HEVC", gf_hevc_get_profile_name(hevccfg->profile_idc), ((Double)hevccfg->level_idc) / 30.0, hevccfg->chromaFormat); - fprintf(stderr, "\tNAL Unit length bits: %d - general profile compatibility 0x%08X\n", 8*hevccfg->nal_unit_size, hevccfg->general_profile_compatibility_flags); + Bool non_hevc_base_layer=GF_FALSE; + fprintf(stderr, "\t%s Info:", hevccfg->is_lhvc ? "LHVC" : "HEVC"); + if (!hevccfg->is_lhvc) + fprintf(stderr, " Profile %s @ Level %g - Chroma Format %s\n", gf_hevc_get_profile_name(hevccfg->profile_idc), ((Double)hevccfg->level_idc) / 30.0, gf_avc_hevc_get_chroma_format_name(hevccfg->chromaFormat)); + fprintf(stderr, "\n"); + fprintf(stderr, "\tNAL Unit length bits: %d", 8*hevccfg->nal_unit_size); + if (!hevccfg->is_lhvc) + fprintf(stderr, " - general profile compatibility 0x%08X\n", hevccfg->general_profile_compatibility_flags); + fprintf(stderr, "\n"); fprintf(stderr, "\tParameter Sets: "); for (k=0; kparam_array); k++) { GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); @@ -1675,7 +1904,10 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg for (idx=0; idxnalus); idx++) { GF_AVCConfigSlot *vps = gf_list_get(ar->nalus, idx); - gf_media_hevc_read_vps(vps->data, vps->size, hevc_state); + s32 idx=gf_media_hevc_read_vps(vps->data, vps->size, hevc_state); + if (hevccfg->is_lhvc && (idx>=0)) { + non_hevc_base_layer = ! hevc_state->vps[idx].base_layer_internal_flag; + } } } } @@ -1688,22 +1920,30 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg 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); par_n = par_d = -1; - gf_hevc_get_sps_info_with_state(hevc_state, sps->data, sps->size, NULL, &width, &height, &par_n, &par_d); - 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); + 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) { + 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 { + fprintf(stderr, "\nFailed to read SPS: %s\n\n", gf_error_to_string((e) )); } - fprintf(stderr, "\n"); } } - fprintf(stderr, "\tBit Depth luma %d - Chroma %d - %d temporal layers\n", hevccfg->luma_bit_depth, hevccfg->chroma_bit_depth, hevccfg->numTemporalLayers); - if (hevccfg->is_shvc) { - fprintf(stderr, "\t%sNum Layers: %d (scalability mask 0x%02X)%s\n", hevccfg->non_hevc_base_layer ? "Non-HEVC base layer - " : "", hevccfg->num_layers, hevccfg->scalability_mask, hevccfg->complete_representation ? "" : " - no VCL data"); + if (!hevccfg->is_lhvc) + fprintf(stderr, "\tBit Depth luma %d - Chroma %d - %d temporal layers\n", hevccfg->luma_bit_depth, hevccfg->chroma_bit_depth, hevccfg->numTemporalLayers); + else + fprintf(stderr, "\t%d temporal layers\n", hevccfg->numTemporalLayers); + if (hevccfg->is_lhvc) { + fprintf(stderr, "\t%sHEVC base layer - Complete representation %d\n", non_hevc_base_layer ? "Non-" : "", hevccfg->complete_representation); } for (k=0; kparam_array); k++) { @@ -1734,7 +1974,10 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } timescale = gf_isom_get_media_timescale(file, trackNum); - fprintf(stderr, "Track # %d Info - TrackID %d - TimeScale %d - Media Duration %s\n", trackNum, trackID, timescale, format_duration(gf_isom_get_media_duration(file, trackNum), timescale, szDur)); + 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)); + nb_edits = gf_isom_get_edit_segment_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)); @@ -1755,6 +1998,8 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) char *kind_scheme, *kind_value; gf_isom_get_track_kind(file, trackNum, i, &kind_scheme, &kind_value); fprintf(stderr, "Kind: %s - %s\n", kind_scheme, kind_value); + if (kind_scheme) gf_free(kind_scheme); + if (kind_value) gf_free(kind_value); } if (gf_isom_is_track_fragmented(file, trackID) ) { @@ -1796,11 +2041,14 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) || (msub_type==GF_ISOM_SUBTYPE_AVC3_H264) || (msub_type==GF_ISOM_SUBTYPE_AVC4_H264) || (msub_type==GF_ISOM_SUBTYPE_SVC_H264) + || (msub_type==GF_ISOM_SUBTYPE_MVC_H264) || (msub_type==GF_ISOM_SUBTYPE_LSR1) || (msub_type==GF_ISOM_SUBTYPE_HVC1) || (msub_type==GF_ISOM_SUBTYPE_HEV1) - || (msub_type==GF_ISOM_SUBTYPE_SHV1) - || (msub_type==GF_ISOM_SUBTYPE_SHC1) + || (msub_type==GF_ISOM_SUBTYPE_HVC2) + || (msub_type==GF_ISOM_SUBTYPE_HEV2) + || (msub_type==GF_ISOM_SUBTYPE_LHV1) + || (msub_type==GF_ISOM_SUBTYPE_LHE1) || (msub_type==GF_ISOM_SUBTYPE_HVT1) ) { esd = gf_isom_get_esd(file, trackNum, 1); @@ -1845,9 +2093,9 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } } #endif - } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) { + } else if (gf_isom_get_avc_svc_type(file, trackNum, 1) != GF_ISOM_AVCTYPE_NONE) { #ifndef GPAC_DISABLE_AV_PARSERS - GF_AVCConfig *avccfg, *svccfg; + GF_AVCConfig *avccfg, *svccfg, *mvccfg; GF_AVCConfigSlot *slc; s32 par_n, par_d; #endif @@ -1858,7 +2106,8 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) #ifndef GPAC_DISABLE_AV_PARSERS avccfg = gf_isom_avc_config_get(file, trackNum, 1); svccfg = gf_isom_svc_config_get(file, trackNum, 1); - if (!avccfg && !svccfg) { + 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"); } else if (avccfg) { fprintf(stderr, "\tAVC Info: %d SPS - %d PPS", gf_list_count(avccfg->sequenceParameterSets) , gf_list_count(avccfg->pictureParameterSets) ); @@ -1875,7 +2124,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) if (!full_dump) break; } if (avccfg->chroma_bit_depth) { - fprintf(stderr, "\tChroma format %d - Luma bit depth %d - chroma bit depth %d\n", avccfg->chroma_format, avccfg->luma_bit_depth, avccfg->chroma_bit_depth); + fprintf(stderr, "\tChroma format %s - Luma bit depth %d - chroma bit depth %d\n", gf_avc_hevc_get_chroma_format_name(avccfg->chroma_format), avccfg->luma_bit_depth, avccfg->chroma_bit_depth); } print_config_hash(avccfg->sequenceParameterSets, "SPS"); @@ -1891,7 +2140,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) if (slc) { u32 s_w, s_h, sps_id; gf_avc_get_sps_info(slc->data, slc->size, &sps_id, &s_w, &s_h, &par_n, &par_d); - fprintf(stderr, "\t\tSSPS ID %d - Visual Size %d x %d\n", sps_id, s_w, s_h); + fprintf(stderr, "\t\tSPS ID %d - Visual Size %d x %d\n", sps_id, s_w, s_h); if ((par_n>0) && (par_d>0)) { u32 tw, th; gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL); @@ -1905,14 +2154,36 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) gf_odf_avc_cfg_del(svccfg); } + + if (mvccfg) { + fprintf(stderr, "\n\tMVC Info: %d SPS - %d PPS - Profile %s @ Level %g\n", gf_list_count(mvccfg->sequenceParameterSets) , gf_list_count(mvccfg->pictureParameterSets), gf_avc_get_profile_name(mvccfg->AVCProfileIndication), ((Double)mvccfg->AVCLevelIndication)/10.0 ); + fprintf(stderr, "\tMVC NAL Unit length bits: %d\n", 8*mvccfg->nal_unit_size); + for (i=0; isequenceParameterSets); i++) { + slc = gf_list_get(mvccfg->sequenceParameterSets, i); + if (slc) { + u32 s_w, s_h, sps_id; + gf_avc_get_sps_info(slc->data, slc->size, &sps_id, &s_w, &s_h, &par_n, &par_d); + fprintf(stderr, "\t\tSPS ID %d - Visual Size %d x %d\n", sps_id, s_w, s_h); + 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, "\tPixel Aspect Ratio %d:%d - Indicated track size %d x %d\n", par_n, par_d, tw, th); + } + } + } + print_config_hash(mvccfg->sequenceParameterSets, "SPS"); + print_config_hash(mvccfg->pictureParameterSets, "PPS"); + gf_odf_avc_cfg_del(mvccfg); + } #endif /*GPAC_DISABLE_AV_PARSERS*/ } else if ((esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) - || (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_SHVC) + || (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_LHVC) ) { + GF_OperatingPointsInformation *oinf; #if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC) HEVCState hevc_state; - GF_HEVCConfig *hevccfg, *shvccfg; + GF_HEVCConfig *hevccfg, *lhvccfg; memset(&hevc_state, 0, sizeof(HEVCState)); hevc_state.sps_active_idx = -1; #endif @@ -1922,7 +2193,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) fprintf(stderr, "HEVC Video - Visual Size %d x %d\n", w, h); #if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC) hevccfg = gf_isom_hevc_config_get(file, trackNum, 1); - shvccfg = gf_isom_shvc_config_get(file, trackNum, 1); + lhvccfg = gf_isom_lhvc_config_get(file, trackNum, 1); if (msub_type==GF_ISOM_SUBTYPE_HVT1) { const char *data; @@ -1936,17 +2207,42 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } else { fprintf(stderr, "\tHEVC Tile track without tiling info\n"); } - } else if (!hevccfg && !shvccfg) { + } else if (!hevccfg && !lhvccfg) { fprintf(stderr, "\n\n\tNon-compliant HEVC track: No hvcC or shcC found in sample description\n"); } + + if (gf_isom_get_reference_count(file, trackNum, GF_4CC('s','a','b','t'))) { + fprintf(stderr, "\tHEVC Tile base track\n"); + } if (hevccfg) { dump_hevc_track_info(file, trackNum, hevccfg, &hevc_state); gf_odf_hevc_cfg_del(hevccfg); fprintf(stderr, "\n"); } - if (shvccfg) { - dump_hevc_track_info(file, trackNum, shvccfg, &hevc_state); - gf_odf_hevc_cfg_del(shvccfg); + if (lhvccfg) { + dump_hevc_track_info(file, trackNum, lhvccfg, &hevc_state); + gf_odf_hevc_cfg_del(lhvccfg); + } + + if (gf_isom_get_oinf_info(file, trackNum, &oinf)) { + fprintf(stderr, "\n\tOperating Points Information -"); + fprintf(stderr, " scalability_mask %d (", oinf->scalability_mask); + switch (oinf->scalability_mask) { + case 2: + fprintf(stderr, "Multiview"); + break; + case 4: + fprintf(stderr, "Spatial scalability"); + break; + case 8: + fprintf(stderr, "Auxilary"); + break; + default: + fprintf(stderr, "unknown"); + } + //TODO: need to dump more info ? + fprintf(stderr, ") num_profile_tier_level %d ", gf_list_count(oinf->profile_tier_levels) ); + fprintf(stderr, " num_operating_points %d dependency layers %d \n", gf_list_count(oinf->operating_points), gf_list_count(oinf->dependency_layers) ); } #endif /*GPAC_DISABLE_AV_PARSERS && defined(GPAC_DISABLE_HEVC)*/ } @@ -1987,12 +2283,12 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) GF_Err e; u32 oti; #endif - u32 is_mp2 = 0; + Bool is_mp2 = GF_FALSE; switch (esd->decoderConfig->objectTypeIndication) { case GPAC_OTI_AUDIO_AAC_MPEG2_MP: case GPAC_OTI_AUDIO_AAC_MPEG2_LCP: case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP: - is_mp2 = 1; + is_mp2 = GF_TRUE; case GPAC_OTI_AUDIO_AAC_MPEG4: #ifndef GPAC_DISABLE_AV_PARSERS if (!esd->decoderConfig->decoderSpecificInfo) @@ -2002,9 +2298,14 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) if (full_dump) fprintf(stderr, "\t"); if (e) fprintf(stderr, "Corrupted AAC Config\n"); else { - fprintf(stderr, "%s - %d Channel(s) - SampleRate %d", gf_m4a_object_type_name(a_cfg.base_object_type), a_cfg.nb_chan, a_cfg.base_sr); + char *heaac = ""; + if (!is_mp2 && a_cfg.has_sbr) { + if (a_cfg.has_ps) heaac = "(HE-AAC v2) "; + else heaac = "(HE-AAC v1) "; + } + fprintf(stderr, "%s %s- %d Channel(s) - SampleRate %d", gf_m4a_object_type_name(a_cfg.base_object_type), heaac, a_cfg.nb_chan, a_cfg.base_sr); if (is_mp2) fprintf(stderr, " (MPEG-2 Signaling)"); - if (a_cfg.has_sbr) fprintf(stderr, " - SBR SampleRate %d", a_cfg.sbr_sr); + if (a_cfg.has_sbr) fprintf(stderr, " - SBR: SampleRate %d Type %s", a_cfg.sbr_sr, gf_m4a_object_type_name(a_cfg.sbr_object_type)); if (a_cfg.has_ps) fprintf(stderr, " - PS"); fprintf(stderr, "\n"); } @@ -2160,7 +2461,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) if (IV_size) fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8); } else if(gf_isom_is_cenc_media(file, trackNum, 1)) { gf_isom_get_cenc_info(file, trackNum, 1, NULL, &scheme_type, &version, &IV_size); - fprintf(stderr, "\n*Encrypted stream - CENC scheme %s (version %d)\n", gf_4cc_to_str(scheme_type), version); + fprintf(stderr, "\n*Encrypted stream - CENC scheme %s (version: major=%u, minor=%u)\n", gf_4cc_to_str(scheme_type), (version&0xFFFF0000)>>16, version&0xFFFF); if (IV_size) fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8); } else if(gf_isom_is_adobe_protection_media(file, trackNum, 1)) { gf_isom_get_adobe_protection_info(file, trackNum, 1, NULL, &scheme_type, &version); @@ -2313,7 +2614,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } if (schema_loc != NULL) { fprintf(stderr, " - schema-location %s", schema_loc); - } + } fprintf(stderr, "\n"); } else { fprintf(stderr, "Unknown Metadata Stream\n"); @@ -2377,8 +2678,15 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) fprintf(stderr, "\tAll samples are sync\n"); break; case 1: - fprintf(stderr, "\tAverage GOP length: %d samples\n", (u32 ) (gf_isom_get_sample_count(file, trackNum) / gf_isom_get_sync_point_count(file, trackNum) ) ); - break; + { + u32 nb_sync = gf_isom_get_sync_point_count(file, trackNum) - 1; + if (! nb_sync) { + fprintf(stderr, "\tOnly one sync sample\n"); + } else { + fprintf(stderr, "\tAverage GOP length: %d samples\n", gf_isom_get_sample_count(file, trackNum) / nb_sync); + } + } + break; case 2: fprintf(stderr, "\tNo sync sample found\n"); break; @@ -2400,6 +2708,10 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } else { samp = gf_isom_get_sample_info(file, trackNum, j+1, NULL, NULL); } + if (!samp) { + fprintf(stderr, "Failed to fetch sample %d\n", j+1); + return; + } dur = samp->DTS+samp->CTS_Offset; size += samp->dataLength; rate += samp->dataLength; @@ -2517,8 +2829,11 @@ void DumpMovieInfo(GF_ISOFile *file) } timescale = gf_isom_get_timescale(file); - fprintf(stderr, "* Movie Info *\n\tTimescale %d - Duration %s\n\t%d track(s)\n", - timescale, format_duration(gf_isom_get_duration(file), timescale, szDur), gf_isom_get_track_count(file)); + i=gf_isom_get_track_count(file); + fprintf(stderr, "* Movie Info *\n\tTimescale %d - %d track%s\n", timescale, i, i>1 ? "s" : ""); + + 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)); #ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (gf_isom_is_fragmented(file)) { @@ -2531,8 +2846,13 @@ void DumpMovieInfo(GF_ISOFile *file) if (gf_isom_moov_first(file)) fprintf(stderr, "\tFile suitable for progressive download (moov before mdat)\n"); - if (gf_isom_get_brand_info(file, &brand, &min, NULL) == GF_OK) { - fprintf(stderr, "\tFile Brand %s - version %d\n", gf_4cc_to_str(brand), min); + 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); + for (i=0; i=GF_ISOM_AVCTYPE_AVC_SVC) check_track_for_svc = i+1; - if (gf_isom_get_hevc_shvc_type(import.dest, i+1, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC) - check_track_for_shvc = i+1; + switch (gf_isom_get_hevc_lhvc_type(import.dest, i+1, 1)) { + case GF_ISOM_HEVCTYPE_HEVC_LHVC: + case GF_ISOM_HEVCTYPE_LHVC_ONLY: + check_track_for_lhvc = i+1; + break; + case GF_ISOM_HEVCTYPE_HEVC_ONLY: + check_track_for_hevc=1; + break; + } if (txt_flags) { gf_isom_text_set_display_flags(import.dest, i+1, 0, txt_flags, txt_mode); } - if (tile_mode) { + if (split_tile_mode) { switch (gf_isom_get_media_subtype(import.dest, i+1, 1)) { case GF_ISOM_SUBTYPE_HVC1: case GF_ISOM_SUBTYPE_HEV1: - tile_mode = 2; + case GF_ISOM_SUBTYPE_HVC2: + case GF_ISOM_SUBTYPE_HEV2: + break; + default: + split_tile_mode = 0; break; } } @@ -759,6 +814,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc if (new_timescale>1) { gf_isom_set_media_timescale(import.dest, track, new_timescale, 0); } + if (rescale>1) { switch (gf_isom_get_media_type(import.dest, track)) { case GF_ISOM_MEDIA_AUDIO: @@ -781,15 +837,19 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc gf_fseek(f, 0, SEEK_SET); data = gf_malloc(sizeof(char)*size); read = fread(data, 1, size, f); - assert(read); - assert(read == size); gf_fclose(f); + if (read != size) { + fprintf(stderr, "Error: could not read rvc config from %s\n", rvc_config); + e = GF_IO_ERR; + goto exit; + } #ifdef GPAC_DISABLE_ZLIB fprintf(stderr, "Error: no zlib support - RVC not available\n"); e = GF_NOT_SUPPORTED; goto exit; -#endif +#else gf_gz_compress_payload(&data, size, &size); +#endif gf_isom_set_rvc_config(import.dest, track, 1, 0, "application/rvc-config+xml+gz", data, size); gf_free(data); } @@ -802,18 +862,29 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc if (gf_isom_get_avc_svc_type(import.dest, track, 1)>=GF_ISOM_AVCTYPE_AVC_SVC) check_track_for_svc = track; - if (gf_isom_get_hevc_shvc_type(import.dest, track, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC) - check_track_for_shvc = track; + switch (gf_isom_get_hevc_lhvc_type(import.dest, track, 1)) { + case GF_ISOM_HEVCTYPE_HEVC_LHVC: + case GF_ISOM_HEVCTYPE_LHVC_ONLY: + check_track_for_lhvc = i+1; + break; + case GF_ISOM_HEVCTYPE_HEVC_ONLY: + check_track_for_hevc=1; + break; + } if (txt_flags) { gf_isom_text_set_display_flags(import.dest, track, 0, txt_flags, txt_mode); } - if (tile_mode) { + if (split_tile_mode) { switch (gf_isom_get_media_subtype(import.dest, track, 1)) { case GF_ISOM_SUBTYPE_HVC1: case GF_ISOM_SUBTYPE_HEV1: - tile_mode = 2; + case GF_ISOM_SUBTYPE_HVC2: + case GF_ISOM_SUBTYPE_HEV2: + break; + default: + split_tile_mode = 0; break; } } @@ -841,6 +912,17 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc } } + if (max_layer_id_plus_one || max_temporal_id_plus_one) { + for (i = 1; i <= gf_isom_get_track_count(import.dest); i++) + { + e = gf_media_filter_hevc(import.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(import.dest, i)); + e = GF_OK; + } + } + } + if (check_track_for_svc) { if (svc_mode) { e = gf_media_split_svc(import.dest, check_track_for_svc, (svc_mode==2) ? 1 : 0); @@ -850,18 +932,27 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc if (e) goto exit; } } - if (check_track_for_shvc) { +#ifndef GPAC_DISABLE_HEVC + if (check_track_for_lhvc) { if (svc_mode) { - e = gf_media_split_shvc(import.dest, check_track_for_shvc, (svc_mode==1) ? 0 : 1, (svc_mode==3) ? 0 : 1 ); + e = gf_media_split_lhvc(import.dest, check_track_for_lhvc, GF_FALSE, (svc_mode==1) ? 0 : 1, (svc_mode==3) ? 0 : 1 ); if (e) goto exit; } else { - //TODO - merge + //TODO - merge, temporal sublayers } } - if (tile_mode == 2) { - gf_media_split_hevc_tiles(import.dest); + if (check_track_for_hevc) { + if (split_tile_mode) { + e = gf_media_split_hevc_tiles(import.dest, split_tile_mode - 1); + if (e) goto exit; + } + if (temporal_mode) { + e = gf_media_split_lhvc(import.dest, check_track_for_hevc, GF_TRUE, (temporal_mode==1) ? GF_FALSE : GF_TRUE, (temporal_mode==3) ? GF_FALSE : GF_TRUE ); + if (e) goto exit; + } } +#endif /*GPAC_DISABLE_HEVC*/ exit: while (gf_list_count(kinds)) { @@ -871,7 +962,7 @@ exit: } gf_list_del(kinds); if (handler_name) gf_free(handler_name); - if (chapter_name ) gf_free(chapter_name ); + if (chapter_name ) gf_free(chapter_name); if (import.fontName) gf_free(import.fontName); if (import.streamFormat) gf_free(import.streamFormat); if (import.force_ext) gf_free(import.force_ext); @@ -897,7 +988,7 @@ typedef struct u32 stop_state; } TKInfo; -GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, char *inName, Double InterleavingTime, Double chunk_start_time, Bool adjust_split_end, char *outName, const char *tmpdir) +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) { u32 i, count, nb_tk, needs_rap_sync, cur_file, conv_type, nb_tk_done, nb_samp, nb_done, di; Double max_dur, cur_file_time; @@ -912,8 +1003,8 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, chunk_extraction = (chunk_start>=0) ? 1 : 0; split_until_end = 0; rap_split = 0; - if (split_size_kb==(u32) -1) rap_split = 1; - if (split_dur==-1) rap_split = 1; + if (split_size_kb == (u64)-1) rap_split = 1; + if (split_dur == -1) rap_split = 1; else if (split_dur==-2) { split_size_kb = 0; split_until_end = 1; @@ -1043,8 +1134,17 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, return GF_NOT_SUPPORTED; } if (needs_rap_sync) { + Bool has_enough_sync = GF_FALSE; tki = &tks[needs_rap_sync-1]; - if ((gf_isom_get_sync_point_count(mp4, tki->tk)==1) && (chunk_start != 0.0f)) { + + if (chunk_start == 0.0f) + has_enough_sync = GF_TRUE; + else if (gf_isom_get_sync_point_count(mp4, tki->tk) > 1) + has_enough_sync = GF_TRUE; + else if (gf_isom_get_sample_group_info(mp4, tki->tk, 1, GF_4CC('r', 'a', 'p', ' '), NULL, NULL, NULL)) + has_enough_sync = GF_TRUE; + + if (!has_enough_sync) { fprintf(stderr, "Not enough Random Access points in input file - cannot split\n"); gf_free(tks); return GF_NOT_SUPPORTED; @@ -1063,7 +1163,6 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, start /= tki->time_scale; if (startstop_state = 2; - needs_rap_sync = 0; } else { e = gf_isom_get_sample_for_media_time(mp4, tki->tk, (u64) (chunk_start*tki->time_scale), &di, GF_ISOM_SEARCH_SYNC_BACKWARD, &samp, &sample_num); if (e!=GF_OK) { @@ -1120,13 +1219,13 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, if (outName) strcpy(szFile, outName); } else { sprintf(szFile, "%s_%03d%s", szName, cur_file+1, ext); - if (outName) { - char *the_file = gf_url_concatenate(outName, szFile); - if (the_file) { - strcpy(szFile, the_file); - gf_free(the_file); - } - } + if (outName) { + char *the_file = gf_url_concatenate(outName, szFile); + if (the_file) { + strcpy(szFile, the_file); + gf_free(the_file); + } + } } dest = gf_isom_open(szFile, GF_ISOM_WRITE_EDIT, tmpdir); /*clone all tracks*/ @@ -1135,14 +1234,14 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, /*track done - we remove the track from destination, an empty video track could cause pbs to some players*/ if (tki->stop_state==2) continue; - e = gf_isom_clone_track(mp4, tki->tk, dest, 0, &tki->dst_tk); + e = gf_isom_clone_track(mp4, tki->tk, dest, GF_FALSE, &tki->dst_tk); if (e) { fprintf(stderr, "Error cloning track %d\n", tki->tk); goto err_exit; } /*use non-packet CTS offsets (faster add/remove)*/ if (gf_isom_has_time_offset(mp4, tki->tk)) { - gf_isom_set_cts_packing(dest, tki->dst_tk, 1); + gf_isom_set_cts_packing(dest, tki->dst_tk, GF_TRUE); } gf_isom_remove_edit_segments(dest, tki->dst_tk); } @@ -1154,6 +1253,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, size_exceeded = 0; max_dts = 0; while (do_add) { + Bool is_rap; Double time; u32 nb_over, nb_av = 0; /*perfom basic de-interleaving to make sure we're not importing too much of a given track*/ @@ -1179,6 +1279,10 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, samp = gf_isom_get_sample(mp4, tki->tk, tki->last_sample+1, &di); samp->DTS = 0; e = gf_isom_add_sample(dest, tki->dst_tk, di, samp); + if (!e) { + e = gf_isom_copy_sample_info(dest, tki->dst_tk, mp4, tki->tk, tki->last_sample+1); + } + gf_isom_sample_del(&samp); tki->last_sample += 1; dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); @@ -1202,7 +1306,16 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, nb_add += 1; - if (tki->has_non_raps && samp->IsRAP) { + is_rap = GF_FALSE; + if (samp->IsRAP) { + is_rap = GF_TRUE; + } else { + Bool has_roll; + gf_isom_get_sample_rap_roll_info(mp4, tki->tk, tki->last_sample+1, &is_rap, &has_roll, NULL); + } + + + if (tki->has_non_raps && is_rap) { GF_ISOSample *next_rap; u32 next_rap_num, sdi; last_rap_sample_time = (Double) (s64) samp->DTS; @@ -1219,6 +1332,10 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, tki->lastDTS = samp->DTS; e = gf_isom_add_sample(dest, tki->dst_tk, di, samp); gf_isom_sample_del(&samp); + + if (!e) { + e = gf_isom_copy_sample_info(dest, tki->dst_tk, mp4, tki->tk, tki->last_sample+1); + } tki->last_sample += 1; gf_set_progress("Splitting", nb_done, nb_samp); nb_done++; @@ -1265,10 +1382,10 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, ) { nb_over++; tki->stop_state = 1; - if (tki->last_samplesample_count) - is_last_rap = 0; - else if (tki->first_sample_done) - is_last_rap = 0; + if (tki->last_samplesample_count) + is_last_rap = 0; + else if (tki->first_sample_done) + is_last_rap = 0; if (rap_split && tki->next_sample_is_rap) { file_split_dur = (Double) ( gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1) - tki->firstDTS); @@ -1290,7 +1407,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, } if (nb_over==nb_tk) do_add = 0; - if (!nb_av) + if (!nb_av) all_av_done = GF_TRUE; } @@ -1357,9 +1474,9 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, while (1) { last_samp = gf_isom_get_sample_count(dest, tki->dst_tk); - time = (Double) (s64) gf_isom_get_media_duration(dest, tki->dst_tk); - //time could get slightly higher than requests dur due to rounding precision. We use 1/4 of the last sample dur as safety marge - time -= (Double) (s64) gf_isom_get_sample_duration(dest, tki->dst_tk, tki->last_sample) / 4; + time = (Double) (s64) gf_isom_get_media_duration(dest, tki->dst_tk); + //time could get slightly higher than requests dur due to rounding precision. We use 1/4 of the last sample dur as safety marge + time -= (Double) (s64) gf_isom_get_sample_duration(dest, tki->dst_tk, tki->last_sample) / 4; time /= tki->time_scale; if (last_samp<=1) break; @@ -1428,7 +1545,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, continue; } if (gf_isom_has_time_offset(mp4, tki->tk)) { - gf_isom_set_cts_packing(dest, tki->dst_tk, 0); + gf_isom_set_cts_packing(dest, tki->dst_tk, GF_FALSE); } if (is_last_rap && tki->can_duplicate) { gf_isom_set_last_sample_duration(dest, tki->dst_tk, gf_isom_get_sample_duration(mp4, tki->tk, tki->sample_count)); @@ -1568,6 +1685,7 @@ static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 s 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) { u32 i; @@ -1620,6 +1738,7 @@ static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 } return dst_tk; } +#endif /*GPAC_DISABLE_HEVC */ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command) { @@ -1844,6 +1963,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou || (stype == GF_ISOM_SUBTYPE_AVC4_H264) ) { dst_tk = merge_avc_config(dest, tk_id, orig, i+1, force_cat); } +#ifndef GPAC_DISABLE_HEVC /*merge HEVC config if possible*/ else if ((stype == GF_ISOM_SUBTYPE_HVC1) || (stype == GF_ISOM_SUBTYPE_HEV1) @@ -1851,25 +1971,27 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou || (stype == GF_ISOM_SUBTYPE_HEV2)) { dst_tk = merge_hevc_config(dest, tk_id, orig, i+1, force_cat); } +#endif /*GPAC_DISABLE_HEVC*/ } } /*looks like a new track*/ if (!dst_tk) { fprintf(stderr, "No suitable destination track found - creating new one (type %s)\n", gf_4cc_to_str(mtype)); - e = gf_isom_clone_track(orig, i+1, dest, 1, &dst_tk); + e = gf_isom_clone_track(orig, i+1, dest, GF_FALSE, &dst_tk); if (e) goto err_exit; gf_isom_clone_pl_indications(orig, dest); new_track = 1; if (align_timelines) { u32 max_timescale = 0; - u32 dst_timescale = 0; +// u32 dst_timescale = 0; u32 idx; for (idx=0; idxposition3DQuant = 1; qp->textureCoordinateQuant = 1; } - if (0 && stats->count_float && opts->resolution) { + //float quantif is disabled since 2008, check if we want to re-enable it +#if 0 + if (stats->count_float && opts->resolution) { qp->scaleMin = stats->min_fixed; qp->scaleMax = stats->max_fixed; qp->scaleNbBits = 2*opts->resolution; qp->scaleQuant = 1; } +#endif } #endif } @@ -2337,8 +2468,7 @@ GF_Err EncodeBIFSChunk(GF_SceneManager *ctx, char *bifsOutputFile, GF_Err (*AUCa } count = gf_list_count(ctx->streams); - - for (i=0; istreams); i++) { + for (i=0; istreams, i); esd = NULL; @@ -2365,11 +2495,13 @@ GF_Err EncodeBIFSChunk(GF_SceneManager *ctx, char *bifsOutputFile, GF_Err (*AUCa if (!esd) { esd = gf_odf_desc_esd_new(2); + if (!esd) return GF_OUT_OF_MEM; gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = NULL; esd->ESID = sc->ESID; esd->decoderConfig->streamType = GF_STREAM_SCENE; } + if (!esd->decoderConfig) return GF_OUT_OF_MEM; /*should NOT happen (means inputctx is not properly setup)*/ if (!esd->decoderConfig->decoderSpecificInfo) { @@ -2529,7 +2661,7 @@ GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *ou if (e) gf_isom_delete(mp4); else gf_isom_close(mp4); } - else e = gf_sm_dump(ctx, szF, d_mode); + else e = gf_sm_dump(ctx, szF, GF_FALSE, d_mode); } exit: @@ -2700,7 +2832,7 @@ GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool ma if (e) goto exit; /*add self ref*/ if (isom_src) { - e = gf_isom_add_meta_item(file, 1, 0, 1, NULL, isom_src, 0, NULL, NULL, NULL, NULL); + e = gf_isom_add_meta_item(file, 1, 0, 1, NULL, isom_src, 0, 0, NULL, NULL, NULL, NULL, NULL); if (e) goto exit; } e = gf_isom_set_meta_xml(file, 1, 0, file_name, !ascii); @@ -2749,7 +2881,7 @@ GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool ma encoding = "binary-gzip"; } - e = gf_isom_add_meta_item(file, 1, 0, 0, item, name, 0, mime, NULL, NULL, NULL); + e = gf_isom_add_meta_item(file, 1, 0, 0, item, name, 0, GF_4CC('m', 'i', 'm', 'e'), mime, encoding, NULL, NULL, NULL); gf_free(name); if (e) goto exit; } diff --git a/applications/mp4box/live.c b/applications/mp4box/live.c index 8868d28..da512be 100644 --- a/applications/mp4box/live.c +++ b/applications/mp4box/live.c @@ -58,7 +58,8 @@ void PrintStreamerUsage() "MP4Box can stream ISO files to RTP. The streamer currently doesn't support\n" "data carrouselling and will therefore not handle BIFS and OD streams properly.\n" "\n" - "-rtp enables streamer\n" + "-rtp enables streamer\n" + "-run-for=T runs for T seconds of the media then exits\n" "-noloop disables looping when streaming\n" "-mpeg4 forces MPEG-4 ES Generic for all RTP streams\n" "-dst=IP IP destination (uni/multi-cast). Default: 127.0.0.1\n" @@ -71,9 +72,9 @@ void PrintStreamerUsage() ); } -static void on_logs(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +static void on_logs(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *fmt, va_list list) { - FILE *logs = cbk; + FILE *logs = (FILE*)cbk; vfprintf(logs, fmt, list); fflush(logs); } @@ -89,10 +90,11 @@ int stream_file_rtp(int argc, char **argv) FILE *logfile=NULL; u16 port = 7000; u32 ttl = 1; - Bool loop = 1; - Bool mem_track = 0; - Bool force_mpeg4 = 0; - u32 path_mtu = 1450; + Bool loop = GF_TRUE; + GF_MemTrackerType mem_track = GF_MemTrackerNone; + Bool force_mpeg4 = GF_FALSE; + u32 path_mtu = 1450; + Double run_for = -1.0; u32 i; for (i = 1; i < (u32) argc ; i++) { @@ -105,17 +107,19 @@ int stream_file_rtp(int argc, char **argv) } inName = arg; } - else if (!stricmp(arg, "-noloop")) loop = 0; - else if (!stricmp(arg, "-mpeg4")) force_mpeg4 = 1; + else if (!stricmp(arg, "-noloop")) loop = GF_FALSE; + else if (!stricmp(arg, "-mpeg4")) force_mpeg4 = GF_TRUE; else if (!strnicmp(arg, "-port=", 6)) port = atoi(arg+6); else if (!strnicmp(arg, "-mtu=", 5)) path_mtu = atoi(arg+5); else if (!strnicmp(arg, "-dst=", 5)) ip_dest = arg+5; else if (!strnicmp(arg, "-ttl=", 5)) ttl = atoi(arg+5); else if (!strnicmp(arg, "-ifce=", 6)) ifce_addr = arg+6; else if (!strnicmp(arg, "-sdp=", 5)) sdp_file = arg+5; - else if (!stricmp(arg, "-mem-track")) mem_track = 1; + else if (!stricmp(arg, "-mem-track")) mem_track = GF_MemTrackerSimple; + else if (!stricmp(arg, "-mem-track-stack")) mem_track = GF_MemTrackerBackTrace; else if (!strnicmp(arg, "-logs=", 6)) logs = arg+6; else if (!strnicmp(arg, "-lf=", 4)) logfile = gf_fopen(arg+4, "wt"); + else if (!strnicmp(arg, "-run-for=", 9)) run_for = atof(arg+9); } gf_sys_init(mem_track); @@ -138,11 +142,14 @@ int stream_file_rtp(int argc, char **argv) if (!file_streamer) { fprintf(stderr, "Cannot create file streamer\n"); } else { + Bool run = GF_TRUE; u32 check = 50; fprintf(stderr, "Starting streaming %s to %s:%d\n", inName, ip_dest, port); gf_isom_streamer_write_sdp(file_streamer, sdp_file); - while (1) { + if (run_for==0) run=GF_FALSE; + + while (run) { gf_isom_streamer_send_next_packet(file_streamer, 0, 0); check--; if (!check) { @@ -152,6 +159,8 @@ int stream_file_rtp(int argc, char **argv) } check = 50; } + if ((run_for > 0) && (run_for < gf_isom_streamer_get_current_time(file_streamer)) ) + break; } gf_isom_streamer_del(file_streamer); } @@ -232,7 +241,7 @@ RTPChannel *next_carousel(LiveSession *sess, u32 *timeout) time = (u32) -1; count = gf_list_count(sess->streams); for (i=0; istreams, i); + RTPChannel *ch = (RTPChannel*)gf_list_get(sess->streams, i); if (!ch->carousel_period) continue; if (!ch->carousel_size) continue; @@ -262,7 +271,7 @@ static void live_session_callback(void *calling_object, u16 ESID, char *data, u3 RTPChannel *rtpch; u32 i=0; - while ( (rtpch = gf_list_enum(livesess->streams, &i))) { + while ( (rtpch = (RTPChannel*)gf_list_enum(livesess->streams, &i))) { if (rtpch->ESID == ESID) { /*store carousel data*/ @@ -354,6 +363,10 @@ static void live_session_setup(LiveSession *livesess, char *ip, u16 port, u32 pa gf_seng_get_stream_config(livesess->seng, i, &ESID, &config, &config_len, &st, &oti, &ts); GF_SAFEALLOC(rtpch, RTPChannel); + if (!rtpch) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Cannot allocate rtp input handler\n")); + continue; + } rtpch->timescale = ts; rtpch->init_time = gf_sys_clock(); @@ -489,7 +502,7 @@ int live_session(int argc, char **argv) aggregate_au = 1; es_id = 0; no_rap = 0; - gf_sys_init(GF_FALSE); + gf_sys_init(GF_MemTrackerNone); memset(&livesess, 0, sizeof(LiveSession)); @@ -620,6 +633,7 @@ int live_session(int argc, char **argv) e = gf_seng_encode_from_string(livesess.seng, 0, 0, szCom, live_session_callback); if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); e = gf_seng_aggregate_context(livesess.seng, 0); + if (e) fprintf(stderr, "Aggregating context failed: %s\n", gf_error_to_string(e)); livesess.critical = 0; update_context = 1; } @@ -642,6 +656,7 @@ int live_session(int argc, char **argv) if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); livesess.critical = 0; e = gf_seng_aggregate_context(livesess.seng, 0); + if (e) fprintf(stderr, "Aggregating context failed: %s\n", gf_error_to_string(e)); } break; @@ -850,6 +865,8 @@ exit: #endif /*defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE)*/ +#ifndef GPAC_DISABLE_MPEG2TS + u32 grab_live_m2ts(const char *grab_m2ts, const char *grab_ifce, const char *outName) { char data[0x80000]; @@ -862,7 +879,7 @@ u32 grab_live_m2ts(const char *grab_m2ts, const char *grab_ifce, const char *out GF_RTPReorder *ch = NULL; #endif GF_Socket *sock; - GF_Err e = gf_m2ts_get_socket(grab_m2ts, grab_ifce, 0x80000, &sock); + GF_Err e = gf_m2ts_get_socket(grab_m2ts, grab_ifce, GF_M2TS_UDP_BUFFER_SIZE, &sock); if (e) { fprintf(stderr, "Cannot open %s: %s\n", grab_m2ts, gf_error_to_string(e)); @@ -939,5 +956,6 @@ u32 grab_live_m2ts(const char *grab_m2ts, const char *grab_ifce, const char *out return 0; } +#endif /* GPAC_DISABLE_MPEG2TS */ diff --git a/applications/mp4box/main.c b/applications/mp4box/main.c index d199ccf..5611fe5 100644 --- a/applications/mp4box/main.c +++ b/applications/mp4box/main.c @@ -26,6 +26,7 @@ #include #include +#include #ifndef GPAC_DISABLE_SMGR #include @@ -60,6 +61,7 @@ #include #define BUFFSIZE 8192 +#define DEFAULT_INTERLEAVING_IN_SEC 0.5 /*in fileimport.c*/ @@ -70,7 +72,7 @@ void convert_file_info(char *inName, u32 trackID); #ifndef GPAC_DISABLE_ISOM_WRITE GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample); -GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, char *inName, Double interleaving_time, Double chunk_start, Bool adjust_split_end, char *outName, const char *tmpdir); +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); GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command); #if !defined(GPAC_DISABLE_SCENE_ENCODER) @@ -82,41 +84,42 @@ GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool ma #endif -GF_Err dump_cover_art(GF_ISOFile *file, char *inName); -GF_Err dump_chapters(GF_ISOFile *file, char *inName, Bool dump_ogg); -void dump_udta(GF_ISOFile *file, char *inName, u32 dump_udta_type, u32 dump_udta_track); +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); +void 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); u32 id3_get_genre_tag(const char *name); /*in filedump.c*/ #ifndef GPAC_DISABLE_SCENE_DUMP -GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bool do_log); +GF_Err dump_isom_scene(char *file, char *inName, Bool is_final_name, GF_SceneDumpFormat dump_mode, Bool do_log); //void gf_check_isom_files(char *conf_rules, char *inName); #endif #ifndef GPAC_DISABLE_SCENE_STATS -void dump_scene_stats(char *file, char *inName, u32 stat_level); +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); +void PrintBuiltInBoxes(); #ifndef GPAC_DISABLE_ISOM_DUMP -void dump_isom_xml(GF_ISOFile *file, char *inName); +GF_Err dump_isom_xml(GF_ISOFile *file, char *inName, Bool is_final_name, Bool do_track_dump); #endif #ifndef GPAC_DISABLE_ISOM_HINTING #ifndef GPAC_DISABLE_ISOM_DUMP -void dump_file_rtp(GF_ISOFile *file, char *inName); +void dump_isom_rtp(GF_ISOFile *file, char *inName, Bool is_final_name); #endif -void DumpSDP(GF_ISOFile *file, char *inName); +void dump_isom_sdp(GF_ISOFile *file, char *inName, Bool is_final_name); #endif -void dump_file_timestamps(GF_ISOFile *file, char *inName); -void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName); +void dump_isom_timestamps(GF_ISOFile *file, char *inName, Bool is_final_name); +void dump_isom_nal(GF_ISOFile *file, u32 trackID, char *inName, Bool is_final_name); #ifndef GPAC_DISABLE_ISOM_DUMP -void dump_file_ismacryp(GF_ISOFile *file, char *inName); -void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_convert, GF_TextDumpType dump_type); +void dump_isom_ismacryp(GF_ISOFile *file, char *inName, Bool is_final_name); +void dump_isom_timed_text(GF_ISOFile *file, u32 trackID, char *inName, Bool is_final_name, Bool is_convert, GF_TextDumpType dump_type); #endif /*GPAC_DISABLE_ISOM_DUMP*/ @@ -196,12 +199,13 @@ void PrintGeneralUsage() { fprintf(stderr, "General Options:\n" #ifdef GPAC_MEMORY_TRACKING - " -mem-track: enables memory tracker\n" + " -mem-track: enables memory tracker\n" + " -mem-track-stack: enables memory tracker with stack dumping\n" #endif " -strict-error exits after the first error is reported\n" " -inter time_in_ms interleaves file data (track chunks of time_in_ms)\n" " * Note 1: Interleaving is 0.5s by default\n" - " * Note 2: Performs drift checking accross tracks\n" + " * Note 2: Performs drift checking across tracks\n" " * Note 3: a value of 0 disables interleaving\n" " -old-inter time same as -inter but doesn't perform drift checking\n" " -tight performs tight interleaving (sample based) of the file\n" @@ -209,12 +213,12 @@ void PrintGeneralUsage() " -flat stores file with all media data first, non-interleaved\n" " -frag time_in_ms fragments file (track fragments of time_in_ms)\n" " * Note: Always disables interleaving\n" - " -ffspace size inserts free space before moof in fragmented files\n" " -out filename specifies output file name\n" " * Note: By default input (MP4,3GP) file is overwritten\n" " -tmp dirname specifies directory for temporary file creation\n" " * Note: Default temp dir is OS-dependent\n" - " -co64 forces usage of 64-bit chunk offsets for ISOBMF files\n" + " -for-test disables all creation/modif dates and GPAC versions in files\n" + " -co64 forces usage of 64-bit chunk offsets for ISOBMF files\n" " -write-buffer SIZE specifies write buffer in bytes for ISOBMF files\n" " -no-sys removes all MPEG-4 Systems info except IOD (profiles)\n" " * Note: Set by default whith '-add' and '-cat'\n" @@ -232,19 +236,20 @@ void PrintGeneralUsage() " -cprt string adds copyright string to movie\n" " -chap file adds chapter information contained in file\n" " -set-track-id id1:id2 changes the id of a track from id1 to id2\n" + " -swap-track-id id1:id2 swaps the IDs of the identified tracks\n" " -rem trackID removes track from file\n" " -rap trackID removes all non-RAP samples from track\n" " -enable trackID enables track\n" " -disable trackID disables track\n" " -new forces creation of a new destination file\n" - " -timescale VAL sets movie timescale to VAL ticks per second (default is 600).\n" + " -timescale VAL sets movie timescale to VAL ticks per second (default is 600)\n" " -lang [tkID=]LAN sets track language. LAN is the BCP-47 code (eng, en-UK, ...)\n" - " -delay tkID=TIME sets track start delay in ms.\n" + " -delay tkID=TIME sets track start delay in ms\n" " -par tkID=PAR sets visual track pixel aspect ratio (PAR=N:D or \"none\")\n" " -name tkID=NAME sets track handler name\n" " * NAME can indicate a UTF-8 file (\"file://file name\"\n" - " -itags tag1[:tag2] sets iTunes tags to file - more info: MP4Box -tag-list.\n" - " -split time_sec splits in files of time_sec max duration\n" + " -itags tag1[:tag2] sets iTunes tags to file - more info: MP4Box -tag-list\n" + " -split time_sec splits in files of time_sec max duration, starting each file at RAP.\n" " * Note: this removes all MPEG-4 Systems media\n" " -split-size size splits in files of max filesize kB. same as -splits.\n" " * Note: this removes all MPEG-4 Systems media\n" @@ -276,23 +281,31 @@ void PrintGeneralUsage() " -group-single puts all tracks in a single group\n" " -ref id:XXXX:refID adds a reference of type 4CC from track ID to track refID\n" " -keep-utc keeps UTC timing in the file after edit\n" - " -udta ID:[OPTS] sets udta for given track or movie if ID is 0. OPTS is a colon separated list of:\n" - " type=CODE where code is the 4CC code of the UDTA (not needed for box= option)\n" - " box=FILE where FILE is the location of the udta data, formatted as serialized boxes\n" - " box=base64,DATA where DATA is the base64 encoded udta data, formatted as serialized boxes\n" - " src=FILE where FILE is the location of the udta data (will be stored in a single box of type CODE)\n" - " src=base64,DATA where DATA is the base64 encoded udta data (will be stored in a single box of type CODE)\n" - " If no source is set, UDTA of type CODE will be removed\n" + " -udta ID:[OPTS] sets udta for given track or movie if ID is 0. OPTS is a colon separated list of:\n" + " type=CODE where code is the 4CC code of the UDTA (not needed for box= option)\n" + " box=FILE where FILE is the location of the udta data, formatted as serialized boxes\n" +#ifndef GPAC_DISABLE_CORE_TOOLS + " box=base64,DATA where DATA is the base64 encoded udta data, formatted as serialized boxes\n" +#endif + " src=FILE where FILE is the location of the udta data (will be stored in a single box of type CODE)\n" +#ifndef GPAC_DISABLE_CORE_TOOLS + " src=base64,DATA where DATA is the base64 encoded udta data (will be stored in a single box of type CODE)\n" +#endif + " If no source is set, UDTA of type CODE will be removed\n" "\n"); } void PrintDASHUsage() { fprintf(stderr, "DASH Options:\n" + " -mpd m3u8 converts HLS manifest (local or remote http) to MPD \n" + " Note: not compatible with other DASH options (except -out and -tmp) and does not convert associated segments\n" " -dash dur enables DASH-ing of the file(s) with a segment duration of DUR ms\n" " Note: the duration of a fragment (subsegment) is set\n" " using the -frag switch.\n" " Note: for onDemand profile, sets duration of a subsegment\n" + " -dash-strict dur enables DASH-ing of the file(s) with a segment duration of DUR ms (old behaviour)\n" + " Note: the duration will be the closest to \'dur\', and will remain constant\n" " -dash-live[=F] dur generates a live DASH session using dur segment duration, optionally writing live context to F\n" " MP4Box will run the live session until \'q\' is pressed or a fatal error occurs.\n" " -ddbg-live[=F] dur same as -dash-live without time regulation for debug purposes.\n" @@ -312,14 +325,16 @@ void PrintDASHUsage() "Input media files to dash can use the following modifiers\n" " \"#trackID=N\" only uses the track ID N from the source file\n" " \"#video\" only uses the first video track from the source file\n" - " \"#audio\" only uses the first video track from the source file\n" + " \"#audio\" only uses the first audio track from the source file\n" " \":id=NAME\" sets the representation ID to NAME\n" + " \":dur=VALUE\" processes VALUE seconds from the media\n" + " If VALUE is longer than the media duration, the last media duration is lengthen.\n" " \":period=NAME\" sets the representation's period to NAME. Multiple periods may be used\n" " period appear in the MPD in the same order as specified with this option\n" " \":BaseURL=NAME\" sets the BaseURL. Set multiple times for multiple BaseURLs\n" " \":bandwidth=VALUE\" sets the representation's bandwidth to a given value\n" - " \":duration=VALUE\" Increases the duration of this period by the given duration in seconds\n" - " only used when no input media is specified (remote period insertion), eg :period=X:xlink=Z:duration=Y.\n" + " \":period_duration=VALUE\" increases the duration of this period by the given duration in seconds\n" + " only used when no input media is specified (remote period insertion), eg :period=X:xlink=Z:duration=Y.\n" " \":xlink=VALUE\" sets the xlink value for the period containing this element\n" " only the xlink declared on the first rep of a period will be used\n" " \":role=VALUE\" sets the role of this representation (cf DASH spec).\n" @@ -358,12 +373,13 @@ void PrintDASHUsage() " -time-shift TIME specifies MPD time shift buffer depth in seconds (default 0). Specify -1 to keep all files\n" " -subdur DUR specifies maximum duration in ms of the input file to be dashed in LIVE or context mode.\n" " NOTE: This does not change the segment duration: dashing stops once segments produced exceeded the duration.\n" + " -dash-run-for TIME In case of dash live, runs for T ms of the media then exits\n" " -min-buffer TIME specifies MPD min buffer time in milliseconds\n" " -ast-offset TIME specifies MPD AvailabilityStartTime offset in ms if positive, or availabilityTimeOffset of each representation if negative. Default is 0 sec delay\n" " -dash-scale SCALE specifies that timing for -dash and -frag are expressed in SCALE units per seconds\n" " -mem-frags fragments will be produced in memory rather than on disk before flushing to disk\n" " -pssh-moof stores PSSH boxes in first moof of each segments. By default PSSH are stored in movie box.\n" - " -sample-groups-traf stores sample group descriptions in traf (duplicated for each traf) rather than in moof. By default sample group descriptions are stored in movie box.\n" + " -sample-groups-traf stores sample group descriptions in traf (duplicated for each traf). If not used, sample group descriptions are stored in the movie box.\n" "\n" "Advanced Options, should not be needed when using -profile:\n" @@ -381,7 +397,13 @@ void PrintDASHUsage() " -no-frags-default disables default flags in fragments\n" " -single-traf uses a single track fragment per moof (smooth streaming and derived specs may require this)\n" " -dash-ts-prog N program_number to be considered in case of an MPTS input file.\n" - " -frag-rt when using fragments in live mode, flush fragments according to their timing (only supported with a single input).\n" + " -frag-rt when using fragments in live mode, flush fragments according to their timing (only supported with a single input).\n" + " -cp-location=MODE sets ContentProtection element location. Possible values for mode are:\n" + " as: sets ContentProtection in AdaptationSet element\n" + " rep: sets ContentProtection in Representation element\n" + " both: sets ContentProtection in both elements\n" + " -start-date for live mode, sets start date (as xs:date, eg YYYY-MM-DDTHH:MM:SSZ. Default is now.\n" + " !! Do not use with multiple periods, nor when DASH duration is not a multiple of GOP size !!\n" "\n"); } @@ -393,12 +415,14 @@ void PrintFormats() " MPEG-1-2 Video .m1v .m2v\n" " MPEG-4 Video .cmp .m4v\n" " H263 Video .263 .h263\n" - " AVC/H264 Video .h264 .h26L .264 .26L .x264 .svc\n" - " HEVC Video .hevc .h265 .265 .hvc .shvc\n" + " AVC/H264 Video .h264 .h26L .264 .26L .x264 .svc\n" + " HEVC Video .hevc .h265 .265 .hvc .shvc .lhvc .mhvc\n" " JPEG Images .jpg .jpeg\n" + " JPEG-2000 Images .jp2\n" " PNG Images .png\n" - " MPEG 1-2 Audio .mp3, .m1a, .m2a\n" + " MPEG 1-2 Audio .mp3, .mp2, .m1a, .m2a\n" " ADTS-AAC Audio .aac\n" + " Dolby (e)AC-3 Audio .ac3 .ec3\n" " AMR(WB) Audio .amr .awb\n" " EVRC Audio .evc\n" " SMV Audio .smv\n" @@ -414,17 +438,24 @@ void PrintFormats() "Supported text formats:\n" " SRT Subtitles .srt\n" " SUB Subtitles .sub\n" + " VobSub .idx\n" " GPAC Timed Text .ttxt\n" + " VTT .vtt\n" + " TTML .ttml\n" " QuickTime TeXML Text .xml (cf QT documentation)\n" "\n" "Supported Scene formats:\n" " MPEG-4 XMT-A .xmt .xmta .xmt.gz .xmta.gz\n" " MPEG-4 BT .bt .bt.gz\n" + " MPEG-4 SAF .saf .lsr\n" " VRML .wrl .wrl.gz\n" " X3D-XML .x3d .x3d.gz\n" " X3D-VRML .x3dv .x3dv.gz\n" " MacroMedia Flash .swf (very limited import support only)\n" "\n" + "Supported chapter formats:\n" + " Nero chapters .txt .chap\n" + "\n" ); } @@ -458,9 +489,10 @@ void PrintImportUsage() " \":ps\" same as -ps option\n" " \":psx\" same as -psx option\n" " \":mpeg4\" same as -mpeg4 option\n" - " \":svc\" import SVC/SHVC with explicit signaling (no AVC base compatibility)\n" - " \":nosvc\" discard SVC/SHVC data when importing\n" - " \":svcmode=MODE\" sets SVC/SHVC import mode:\n" + " \":nosei\" discard all SEI messages during import\n" + " \":svc\" import SVC/LHVC with explicit signaling (no AVC base compatibility)\n" + " \":nosvc\" discard SVC/LHVC data when importing\n" + " \":svcmode=MODE\" sets SVC/LHVC import mode:\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" @@ -468,7 +500,11 @@ void PrintImportUsage() " \":subsamples\" adds SubSample information for AVC+SVC\n" " \":forcesync\" forces non IDR samples with I slices to be marked as sync points (AVC GDR)\n" " !! RESULTING FILE IS NOT COMPLIANT WITH THE SPEC but will fix seeking in most players\n" - " \":xps_inband\" Sets xPS inband for AVC/H264 and HEVC (for reverse operation, re-import from raw media)\n" + " \":xps_inband\" Sets xPS inband for AVC/H264 and HEVC (for reverse operation, re-import from raw media)\n" + " \":max_lid=N\" sets HEVC max layer ID to be imported to N. Default imports all.\n" + " \":max_tid=N\" sets HEVC max temporal ID to be imported to N. Default imports all.\n" + " \":tiles\" adds HEVC tiles signaling and NALU maps without splitting the tiles into different tile tracks.\n" + " \":split_tiles\" splits HEVC tiles into different tile tracks, one tile (or all tiles of one slice) per track.\n" " \":negctts\" uses negative CTS-DTS offsets (ISO4 brand)\n" " \":stype=4CC\" forces the sample description type to a different value\n" " !! THIS MAY BREAK THE FILE WRITING !!\n" @@ -490,6 +526,7 @@ void PrintImportUsage() " \":fmt=FORMAT\" overrides format detection with given format (cf BT/XMTA doc)\n" " \":profile=INT\" overrides AVC profile\n" " \":level=INT\" overrides AVC level\n" + " \":novpsext\" removes VPS extensions from HEVC VPS\n" " \":font=name\" specifies font name for text import (default \"Serif\")\n" " \":size=s\" specifies font size for text import (default 18)\n" @@ -514,10 +551,10 @@ void PrintImportUsage() " \":swf-same-app\" appearance nodes are reused\n" " \":swf-flatten=ang\" complementary angle below which 2 lines are merged\n" " * Note: angle \'0\' means no flattening\n" - " \":kind=SCHEMA:type\" sets kind for the track\n" - " \":txtflags=flags\" sets display flags (hexa number) of text track\n" - " \":txtflags+=flags\" adds display flags (hexa number) to text track\n" - " \":txtflags-=flags\" removes display flags (hexa number) from text track\n" + " \":kind=schemeURI=value\" sets kind for the track\n" + " \":txtflags=flags\" sets display flags (hexa number) of text track\n" + " \":txtflags+=flags\" adds display flags (hexa number) to text track\n" + " \":txtflags-=flags\" removes display flags (hexa number) from text track\n" "\n" " -add file add file tracks to (new) output file\n" " -cat file concatenates file samples to (new) output file\n" @@ -608,6 +645,7 @@ void PrintEncryptUsage() " * Note: \'self\' writes key and salt in the file\n" " selectiveType selective encryption type - understood values are:\n" " \"None\" all samples encrypted (default)\n" + " \"Clear\" all samples clean (not encrypted)\n" " \"RAP\" only encrypts random access units\n" " \"Non-RAP\" only encrypts non-random access units\n" " \"Rand\" random selection is performed\n" @@ -696,7 +734,8 @@ void PrintDumpUsage() " -x3d scene to X3D/XML format - removes unknown X3D nodes\n" " -x3dv scene to X3D/VRML format - removes unknown X3D nodes\n" " -lsr scene to LASeR format\n" - " -diso scene IsoMedia file boxes in XML output\n" + " -diso dumps IsoMedia file boxes in XML output\n" + " -dxml dumps IsoMedia file boxes and known track samples in XML output\n" " -drtp rtp hint samples structure to XML output\n" " -dts prints sample timing to text output\n" " -dnal trackID prints NAL sample info of given track\n" @@ -704,7 +743,8 @@ void PrintDumpUsage() " -dcr ISMACryp samples structure to XML output\n" " -dump-cover Extracts cover art\n" " -dump-chap Extracts chapter file\n" - " -dump-udta [ID:]4cc Extracts udta for the given 4CC. If ID is given, dumps from UDTA of the given track ID, otherwise moov is used.\n" + " -dump-chap-ogg Extracts chapter file as OGG format\n" + " -dump-udta [ID:]4cc Extracts udta for the given 4CC. If ID is given, dumps from UDTA of the given track ID, otherwise moov is used.\n" "\n" #ifndef GPAC_DISABLE_ISOM_WRITE " -ttxt Converts input subtitle to GPAC TTXT format\n" @@ -720,38 +760,48 @@ void PrintDumpUsage() " -statx generates node/field statistics for scene after each AU\n" "\n" " -hash generates SHA-1 Hash of the input file\n" +#ifndef GPAC_DISABLE_CORE_TOOLS " -bin converts input XML file using NHML bitstream syntax to binary\n" +#endif "\n"); } void PrintMetaUsage() { fprintf(stderr, "Meta handling Options\n" - " -set-meta args sets given meta type - syntax: \"ABCD[:tk=ID]\"\n" - " * ABCD: four char meta type (NULL or 0 to remove meta)\n" - " * [:tk=ID]: if not set use root (file) meta\n" - " if ID is 0 use moov meta\n" - " if ID is not 0 use track meta\n" - " -add-item args adds resource to meta\n" - " * syntax: file_path + options (\':\' separated):\n" - " tk=ID: meta addressing (file, moov, track)\n" - " name=str: item name\n" - " mime=mtype: item mime type\n" - " encoding=enctype: item content-encoding type\n" - " id=id: item ID\n" - " * file_path \"this\" or \"self\": item is the file itself\n" - " -rem-item args removes resource from meta - syntax: item_ID[:tk=ID]\n" - " -set-primary args sets item as primary for meta - syntax: item_ID[:tk=ID]\n" - " -set-xml args sets meta XML data\n" - " * syntax: xml_file_path[:tk=ID][:binary]\n" - " -rem-xml [tk=ID] removes meta XML data\n" - " -dump-xml args dumps meta XML to file - syntax file_path[:tk=ID]\n" - " -dump-item args dumps item to file - syntax item_ID[:tk=ID][:path=fileName]\n" - " -package packages input XML file into an ISO container\n" - " * all media referenced except hyperlinks are added to file\n" - " -mgt packages input XML file into an MPEG-U widget with ISO container.\n" - " * all files contained in the current folder are added to the widget package\n" - "\n"); + " -set-meta args sets given meta type - syntax: \"ABCD[:tk=ID]\"\n" + " * ABCD: four char meta type (NULL or 0 to remove meta)\n" + " * [:tk=ID]: if not set use root (file) meta\n" + " if ID is 0 use moov meta\n" + " if ID is not 0 use track meta\n" + " -add-item args adds resource to meta\n" + " * syntax: file_path + options (\':\' separated):\n" + " file_path \"this\" or \"self\": item is the file itself\n" + " tk=ID: meta location (file, moov, track)\n" + " name=str: item name\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" + " id=id: item ID\n" + " ref=4cc,id: reference of type 4cc to an other item\n" + " Image Item options\n" + " image-size=wxh sets the width and height of the image.\n" + " image-pasp=wxh sets the pixel aspect ratio property of the image.\n" + " image-rloc=wxh sets the location of this image within another image item.\n" + " image-irot=a sets the rotation angle for this image to 90*a degrees anti-clockwise.\n" + " image-hidden indicates that this image item should be hidden.\n" + " -rem-item args removes resource from meta - syntax: item_ID[:tk=ID]\n" + " -set-primary args sets item as primary for meta - syntax: item_ID[:tk=ID]\n" + " -set-xml args sets meta XML data\n" + " * syntax: xml_file_path[:tk=ID][:binary]\n" + " -rem-xml [tk=ID] removes meta XML data\n" + " -dump-xml args dumps meta XML to file - syntax file_path[:tk=ID]\n" + " -dump-item args dumps item to file - syntax item_ID[:tk=ID][:path=fileName]\n" + " -package packages input XML file into an ISO container\n" + " * all media referenced except hyperlinks are added to file\n" + " -mgt packages input XML file into an MPEG-U widget with ISO container.\n" + " * all files contained in the current folder are added to the widget package\n" + ); } void PrintSWFUsage() @@ -801,13 +851,16 @@ void PrintUsage() " -xnodes lists supported X3D nodes\n" " -xnode NodeName gets X3D node syntax\n" " -snodes lists supported SVG nodes\n" - " -snode NodeName gets SVG node syntax\n" " -languages lists supported ISO 639 languages\n" + " -boxes lists all supported ISOBMF boxes and their syntax\n" "\n" " -quiet quiet mode\n" " -noprog disables progress\n" " -v verbose mode\n" " -logs set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" + " -log-file FILE sets output log file. Also works with -lf FILE\n" + " -log-clock or -lc logs time in micro sec since start time of GPAC before each log line.\n" + " -log-utc or -lu logs UTC time in ms before each log line.\n" " -version gets build version\n" " -- INPUT escape option if INPUT starts with - character\n" "\n" @@ -815,7 +868,7 @@ void PrintUsage() } -void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist) +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; @@ -866,7 +919,8 @@ GF_Err HintFile(GF_ISOFile *file, u32 MTUSize, u32 max_ptime, u32 rtp_rate, u32 GF_RTPHinter *hinter; Bool copy, has_iod, single_av; u8 init_payt = BASE_PAYT; - u32 iod_mode, mtype; + u32 mtype; + GF_SDP_IODProfile iod_mode = GF_SDP_IOD_NONE; u32 media_group = 0; u8 media_prio = 0; @@ -1177,6 +1231,7 @@ typedef enum { META_ACTION_REM_XML = 6, META_ACTION_DUMP_ITEM = 7, META_ACTION_DUMP_XML = 8, + META_ACTION_ADD_IMAGE_ITEM = 9, } MetaActionType; typedef struct @@ -1188,6 +1243,10 @@ typedef struct char szPath[GF_MAX_PATH]; char szName[1024], mime_type[1024], enc_type[1024]; u32 item_id; + u32 item_type; + u32 ref_item_id; + u32 ref_type; + GF_ImageItemProperties *image_props; } MetaAction; #ifndef GPAC_DISABLE_ISOM_WRITE @@ -1224,6 +1283,16 @@ static Bool parse_meta_args(MetaAction *meta, MetaActionType act_type, char *opt 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=%u,%s", &meta->ref_item_id, type); + meta->ref_type = GF_4CC(type[0], type[1], type[2], type[3]); + ret = 1; + } else if (!strnicmp(szSlot, "name=", 5)) { strcpy(meta->szName, szSlot+5); ret = 1; @@ -1233,6 +1302,7 @@ static Bool parse_meta_args(MetaAction *meta, MetaActionType act_type, char *opt ret = 1; } else if (!strnicmp(szSlot, "mime=", 5)) { + meta->item_type = GF_4CC('m','i','m','e'); strcpy(meta->mime_type, szSlot+5); ret = 1; } @@ -1240,6 +1310,56 @@ static Bool parse_meta_args(MetaAction *meta, MetaActionType act_type, char *opt strcpy(meta->enc_type, szSlot+9); ret = 1; } + else if (!strnicmp(szSlot, "image-size=", 11)) { + if (!meta->image_props) { + GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); + } + 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); + } + 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); + } + sscanf(szSlot+11, "%dx%d", &meta->image_props->hOffset, &meta->image_props->vOffset); + ret = 1; + } + else if (!strnicmp(szSlot, "image-irot=", 11)) { + if (!meta->image_props) { + GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); + } + meta->image_props->angle = atoi(szSlot+11); + ret = 1; + } + else if (!strnicmp(szSlot, "image-hidden", 12)) { + if (!meta->image_props) { + GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); + } + meta->image_props->hidden = GF_TRUE; + ret = 1; + } + else if (!strnicmp(szSlot, "tilemode=", 9)) { + if (!meta->image_props) { + GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties); + } + if (!strnicmp(szSlot + 9, "nobase", 6)) { + meta->image_props->tile_mode = TILE_ITEM_ALL_NO_BASE; + } else if (!strnicmp(szSlot + 9, "base", 4)) { + meta->image_props->tile_mode = TILE_ITEM_ALL_BASE; + } else if (!strnicmp(szSlot + 9, "grid", 4)) { + meta->image_props->tile_mode = TILE_ITEM_ALL_GRID; + } else { + meta->image_props->tile_mode = TILE_ITEM_SINGLE; + sscanf(szSlot + 9, "%d", &meta->image_props->single_tile_number); + } + } else if (!strnicmp(szSlot, "dref", 4)) { meta->use_dref = 1; ret = 1; @@ -1256,14 +1376,15 @@ static Bool parse_meta_args(MetaAction *meta, MetaActionType act_type, char *opt ret = 1; break; case META_ACTION_ADD_ITEM: + case META_ACTION_ADD_IMAGE_ITEM: case META_ACTION_SET_XML: - case META_ACTION_DUMP_ITEM: + case META_ACTION_DUMP_XML: strcpy(meta->szPath, szSlot); ret = 1; break; case META_ACTION_REM_ITEM: case META_ACTION_SET_PRIMARY_ITEM: - case META_ACTION_DUMP_XML: + case META_ACTION_DUMP_ITEM: meta->item_id = atoi(szSlot); ret = 1; break; @@ -1282,7 +1403,6 @@ typedef enum { TSEL_ACTION_SET_PARAM = 0, TSEL_ACTION_REMOVE_TSEL = 1, TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP = 2, - TSEL_ACTION_REMOVE_ALL_TSEL_IN_FILE = 3, } TSELActionType; typedef struct @@ -1306,7 +1426,7 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a u32 nb_criteria = 0; TSELAction *tsel_act; char szSlot[1024], *next; - TSELAction *tsel_list = *__tsel_list; + TSELAction *tsel_list; has_switch_id = 0; @@ -1322,7 +1442,7 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a if (next) next[0] = 0; - if (!strnicmp(szSlot, "ref=", 4)) refTrackID = atoi(szSlot+4); + if (!strnicmp(szSlot, "refTrack=", 9)) refTrackID = atoi(szSlot+9); else if (!strnicmp(szSlot, "switchID=", 9)) { if (atoi(szSlot+9)<0) { switch_id = 0; @@ -1370,7 +1490,7 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a } -#define CHECK_NEXT_ARG if (i+1==(u32)argc) { fprintf(stderr, "Missing arg - please check usage\n"); MP4BOX_EXIT_WITH_CODE(1); } +#define CHECK_NEXT_ARG if (i+1==(u32)argc) { fprintf(stderr, "Missing arg - please check usage\n"); return mp4box_cleanup(1); } typedef enum { TRAC_ACTION_REM_TRACK = 0, @@ -1388,13 +1508,14 @@ typedef enum { TRAC_ACTION_REM_KIND = 12, TRAC_ACTION_SET_ID = 13, TRAC_ACTION_SET_UDTA = 14, + TRAC_ACTION_SWAP_ID = 15, } TrackActionType; typedef struct { TrackActionType act_type; u32 trackID; - char *lang; + char lang[10]; s32 delay_ms; const char *kms; const char *hdl_name; @@ -1416,90 +1537,26 @@ enum GF_ISOM_CONV_TYPE_PSP }; -#define MP4BOX_EXIT_WITH_CODE(__ret_code) \ - if (mpd_base_urls) gf_free(mpd_base_urls); \ - if (sdp_lines) gf_free(sdp_lines); \ - if (metas) gf_free(metas); \ - if (tracks) { \ - 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->role) gf_free(di->role); \ - }\ - gf_free(dash_inputs); \ - } \ - gf_sys_close(); \ - if (__ret_code) return __ret_code; \ - goto exit; \ - + GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *name, u32 *nb_dash_inputs) { GF_DashSegmenterInput *di; - char *sep; - // skip ./ and ../, and look for first . to figure out extension - if ((name[1]=='/') || (name[2]=='/') || (name[1]=='\\') || (name[2]=='\\') ) sep = strchr(name+3, '.'); - else { + char *sep; + // skip ./ and ../, and look for first . to figure out extension + if ((name[1]=='/') || (name[2]=='/') || (name[1]=='\\') || (name[2]=='\\') ) sep = strchr(name+3, '.'); + else { char *s2 = strchr(name, ':'); sep = strchr(name, '.'); if (sep && s2 && (s2 - sep) < 0) { sep = name; } } - - //then look for our opt separator : - sep = strchr(sep ? sep : name, ':'); - - if (sep && (sep[1]=='\\')) sep = strchr(sep+1, ':'); + + //then look for our opt separator : + sep = strchr(sep ? sep : name, ':'); + + if (sep && (sep[1]=='\\')) sep = strchr(sep+1, ':'); dash_inputs = gf_realloc(dash_inputs, sizeof(GF_DashSegmenterInput) * (*nb_dash_inputs + 1) ); memset(&dash_inputs[*nb_dash_inputs], 0, sizeof(GF_DashSegmenterInput) ); @@ -1507,19 +1564,20 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * (*nb_dash_inputs)++; if (sep) { - char *opts = sep+1; - sep[0] = 0; + char *opts, *first_opt; + opts = first_opt = sep; while (opts) { sep = strchr(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, ":duration=", 10) || + !strnicmp(sep, ":duration=", 10) || /*legacy*/!strnicmp(sep, ":period_duration=", 10) || !strnicmp(sep, ":xlink=", 7)) { break; } else { @@ -1540,14 +1598,18 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error: Duplicate Representation ID \"%s\" in command line\n", di->representationID)); } } - } else if (!strnicmp(opts, "period=", 7)) di->periodID = gf_strdup(opts+7); + } else if (!strnicmp(opts, "dur=", 4)) di->media_duration = (Double)atof(opts+4); + 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 *)); di->baseURL[di->nb_baseURL] = gf_strdup(opts+8); di->nb_baseURL++; } else if (!strnicmp(opts, "bandwidth=", 10)) di->bandwidth = atoi(opts+10); - else if (!strnicmp(opts, "role=", 5)) di->role = gf_strdup(opts+5); - else if (!strnicmp(opts, "desc", 4)) { + else if (!strnicmp(opts, "role=", 5)) { + di->roles = gf_realloc(di->roles, sizeof (char *) * (di->nb_roles+1)); + di->roles[di->nb_roles] = gf_strdup(opts+5); + di->nb_roles++; + } else if (!strnicmp(opts, "desc", 4)) { u32 *nb_descs=NULL; char ***descs=NULL; u32 opt_offset=0; @@ -1581,14 +1643,17 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * } else if (!strnicmp(opts, "xlink=", 6)) di->xlink = gf_strdup(opts+6); - else if (!strnicmp(opts, "duration=", 9)) { - di->period_duration = (Double) atof(opts+9); + else if (!strnicmp(opts, "period_duration=", 16)) { + di->period_duration = (Double) atof(opts+16); + } else if (!strnicmp(opts, "duration=", 9)) { + di->period_duration = (Double) atof(opts+9); /*legacy: use period_duration instead*/ } if (!sep) break; sep[0] = ':'; opts = sep+1; } + first_opt[0] = '\0'; } di->file_name = name; if (!di->representationID) { @@ -1603,6 +1668,8 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * static GF_Err parse_track_action_params(char *string, TrackAction *action) { char *param = string; + if (!action || !string) return GF_BAD_PARAM; + while (param) { param = strchr(param, ':'); if (param) { @@ -1651,6 +1718,7 @@ static u32 create_new_track_action(char *string, TrackAction **actions, u32 *nb_ return dump_type; } +#ifndef GPAC_DISABLE_CORE_TOOLS static GF_Err nhml_bs_to_bin(char *inName, char *outName, u32 dump_std) { GF_Err e; @@ -1660,7 +1728,7 @@ static GF_Err nhml_bs_to_bin(char *inName, char *outName, u32 dump_std) GF_DOMParser *dom = gf_xml_dom_new(); e = gf_xml_dom_parse(dom, inName, NULL, NULL); - if (e) { + if (e) { gf_xml_dom_del(dom); fprintf(stderr, "Failed to parse XML file: %s\n", gf_error_to_string(e)); return e; @@ -1674,7 +1742,7 @@ static GF_Err nhml_bs_to_bin(char *inName, char *outName, u32 dump_std) e = gf_xml_parse_bit_sequence(root, &data, &data_size); gf_xml_dom_del(dom); - if (e) { + if (e) { fprintf(stderr, "Failed to parse binary sequence: %s\n", gf_error_to_string(e)); return e; } @@ -1705,7 +1773,7 @@ static GF_Err nhml_bs_to_bin(char *inName, char *outName, u32 dump_std) gf_free(data); return e; } - +#endif /*GPAC_DISABLE_CORE_TOOLS*/ static GF_Err hash_file(char *name, u32 dump_std) { @@ -1725,1455 +1793,1691 @@ static GF_Err hash_file(char *name, u32 dump_std) return GF_OK; } -static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +Bool log_sys_clock = GF_FALSE; +Bool log_utc_time = GF_FALSE; + +static void on_gpac_log(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *fmt, va_list list) { FILE *logs = cbk; + + if (log_sys_clock) { + fprintf(logs, "At "LLD" ", gf_sys_clock_high_res() ); + } + if (log_utc_time) { + u64 utc_clock = gf_net_get_utc() ; + time_t secs = utc_clock/1000; + struct tm t; + t = *gmtime(&secs); + fprintf(logs, "UTC %d-%02d-%02dT%02d:%02d:%02dZ (TS "LLU") - ", 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, utc_clock); + } + vfprintf(logs, fmt, list); fflush(logs); } -int mp4boxMain(int argc, char **argv) -{ - char outfile[5000]; - GF_Err e; +char outfile[5000]; +GF_Err e; #ifndef GPAC_DISABLE_SCENE_ENCODER - GF_SMEncodeOptions opts; +GF_SMEncodeOptions opts; #endif - SDPLine *sdp_lines = NULL; - Double interleaving_time, split_duration, split_start, import_fps, dash_duration, dash_subduration; - 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; - GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_DEFAULT; - u32 i, stat_level, hint_flags, info_track_id, import_flags, nb_add, nb_cat, crypt, agg_samples, nb_sdp_ex, max_ptime, raw_sample_num, 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; - GF_DashDynamicMode dash_mode=GF_DASH_STATIC; +SDPLine *sdp_lines = NULL; +Double interleaving_time, split_duration, split_start, import_fps, dash_duration, dash_subduration; +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; +GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_DEFAULT; +u32 i, 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; +GF_DashDynamicMode dash_mode=GF_DASH_STATIC; #ifndef GPAC_DISABLE_SCENE_DUMP - GF_SceneDumpFormat dump_mode; +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, force_new, remove_root_od; - Bool print_sdp, print_info, open_edit, dump_isom, dump_cr, force_ocr, encode, do_log, do_flat, dump_srt, dump_ttxt, dump_timestamps, do_saf, dump_m2ts, dump_cart, do_hash, verbose, force_cat, align_cat, pack_wgt, single_group, dash_live, no_fragments_defaults, single_traf_per_moof; - char *inName, *outName, *arg, *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; - u32 track_dump_type; - u32 trackID; - Double min_buffer = 1.5; - s32 ast_offset_ms = 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; +Double mpd_live_duration = 0; +Bool HintIt, needSave, FullInter, Frag, HintInter, dump_rtp, regular_iod, remove_sys_tracks, remove_hint, force_new, remove_root_od; +Bool print_sdp, print_info, open_edit, dump_cr, force_ocr, encode, do_log, do_flat, dump_srt, dump_ttxt, dump_timestamps, 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; +char *inName, *outName, *arg, *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; +u32 track_dump_type, dump_isom; +u32 trackID; +Double min_buffer = 1.5; +s32 ast_offset_ms = 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; #ifndef GPAC_DISABLE_MPD - Bool do_mpd = 0; +Bool do_mpd = GF_FALSE; #endif #ifndef GPAC_DISABLE_SCENE_ENCODER - Bool chunk_mode=0; +Bool chunk_mode = GF_FALSE; #endif #ifndef GPAC_DISABLE_ISOM_HINTING - Bool HintCopy=0; - u32 MTUSize = 1450; -#endif - GF_ISOFile *file; - Bool frag_real_time = 0; - Double mpd_update_time = 0; - Bool stream_rtp=0; - Bool force_co64 = GF_FALSE; - Bool live_scene=0; - Bool enable_mem_tracker = 0; - Bool dump_iod=0; - Bool pssh_in_moof=0; - Bool samplegroups_in_traf=0; - Bool daisy_chain_sidx=0; - Bool single_segment=0; - Bool single_file=0; - Bool segment_timeline=0; - u32 segment_marker = 0; - GF_DashProfile dash_profile = GF_DASH_PROFILE_UNKNOWN; - const char *dash_profile_extension = NULL; - Bool use_url_template=0; - Bool seg_at_rap=0; - Bool frag_at_rap=0; - Bool adjust_split_end = 0; - Bool memory_frags = 1; - Bool keep_utc = 0; - Bool do_bin_nhml = 0; - u32 timescale = 0; - const char *do_wget = NULL; - GF_DashSegmenterInput *dash_inputs = NULL; - u32 nb_dash_inputs = 0; - char *gf_logs = NULL; - char *seg_ext = NULL; - const char *dash_title = NULL; - const char *dash_source = NULL; - const char *dash_more_info = NULL; -#if !defined(GPAC_DISABLE_STREAMING) - const char *grab_m2ts = NULL; - const char *grab_ifce = NULL; -#endif - FILE *logfile = NULL; - - nb_tsel_acts = nb_add = nb_cat = nb_track_act = nb_sdp_ex = max_ptime = raw_sample_num = nb_meta_act = rtp_rate = major_brand = nb_alt_brand_add = nb_alt_brand_rem = car_dur = minor_version = 0; - e = GF_OK; - split_duration = 0.0; - split_start = -1.0; - interleaving_time = 0.0; - dash_duration = dash_subduration = 0.0; - import_fps = 0; - import_flags = 0; - split_size = 0; - movie_time = 0; - dump_nal = 0; - FullInter = HintInter = encode = do_log = old_interleave = do_saf = do_hash = verbose = 0; -#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 = 0; - conv_type = HintIt = needSave = print_sdp = print_info = regular_iod = dump_std = open_edit = dump_isom = dump_rtp = dump_cr = dump_srt = dump_ttxt = force_new = dump_timestamps = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_live = 0; - no_fragments_defaults = 0; - single_traf_per_moof = 0, - /*align cat is the new default behaviour for -cat*/ - align_cat = 1; - 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; - initial_moof_sn = 0; - initial_tfdt = 0; - -#ifndef GPAC_DISABLE_SCENE_ENCODER - memset(&opts, 0, sizeof(opts)); +Bool HintCopy = 0; +u32 MTUSize = 1450; #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 = NULL; - -#ifndef GPAC_DISABLE_SWF_IMPORT - swf_flags = GF_SM_SWF_SPLIT_TIMELINE; +#ifndef GPAC_DISABLE_CORE_TOOLS +Bool do_bin_nhml = GF_FALSE; #endif - swf_flatten_angle = 0.0f; - tmpdir = NULL; - - for (i = 1; i < (u32) argc ; i++) { - if (!strcmp(argv[i], "-mem-track")) { -#ifdef GPAC_MEMORY_TRACKING - enable_mem_tracker = 1; -#else - fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"); +GF_ISOFile *file; +Bool frag_real_time = GF_FALSE; +u64 dash_start_date=0; +GF_DASH_ContentLocationMode cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET; +Double mpd_update_time = GF_FALSE; +Bool stream_rtp = GF_FALSE; +Bool force_test_mode = GF_FALSE; +Bool force_co64 = GF_FALSE; +Bool live_scene = GF_FALSE; +GF_MemTrackerType mem_track = GF_MemTrackerNone; + +Bool dump_iod = GF_FALSE; +Bool pssh_in_moof = GF_FALSE; +Bool samplegroups_in_traf = GF_FALSE; +Bool daisy_chain_sidx = 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_UNKNOWN; +const char *dash_profile_extension = NULL; +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; +const char *do_wget = NULL; +GF_DashSegmenterInput *dash_inputs = NULL; +u32 nb_dash_inputs = 0; +char *gf_logs = NULL; +char *seg_ext = NULL; +const char *dash_title = NULL; +const char *dash_source = NULL; +const char *dash_more_info = NULL; +#if !defined(GPAC_DISABLE_STREAMING) +const char *grab_m2ts = NULL; +const char *grab_ifce = NULL; #endif - break; - } +FILE *logfile = NULL; +static u32 dash_run_for; +static u32 dash_cumulated_time,dash_prev_time,dash_now_time; + +u32 mp4box_cleanup(u32 ret_code) { + if (mpd_base_urls) { + gf_free(mpd_base_urls); + mpd_base_urls = NULL; } - - /*init libgpac*/ - gf_sys_init(enable_mem_tracker); - if (argc < 2) { - PrintUsage(); - MP4BOX_EXIT_WITH_CODE(1); + if (sdp_lines) { + gf_free(sdp_lines); + sdp_lines = NULL; } - - - /*parse our args*/ - for (i = 1; i < (u32) argc ; i++) { - 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 (metas) { + gf_free(metas); + metas = NULL; + } + if (tracks) { + for (i = 0; inb_baseURL) { + for (j = 0; jnb_baseURL; j++) { + gf_free(di->baseURL[j]); + } + gf_free(di->baseURL); } - if (argc < 3) { - fprintf(stderr, "Error - only one input file found as argument, please check usage\n"); - MP4BOX_EXIT_WITH_CODE(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 { - fprintf(stderr, "Error - 2 input names specified, please check usage\n"); - MP4BOX_EXIT_WITH_CODE(1); + if (di->rep_descs) { + for (j = 0; jnb_rep_descs; j++) { + gf_free(di->rep_descs[j]); } - } else { - inName = arg_val; + 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->roles) { + for (j = 0; jnb_roles; j++) { + gf_free(di->roles[j]); + } + gf_free(di->roles); } } - else if (!stricmp(arg, "-?")) { - PrintUsage(); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-version")) { - PrintVersion(); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-sdp")) print_sdp = 1; - else if (!stricmp(arg, "-quiet")) quiet = 2; - else if (!strcmp(argv[i], "-mem-track")) continue; + gf_free(dash_inputs); + dash_inputs = NULL; + } + if (logfile) gf_fclose(logfile); + gf_sys_close(); + return ret_code; +} - else if (!stricmp(arg, "-logs")) { +u32 mp4box_parse_args_continue(int argc, char **argv, u32 *current_index) +{ + u32 i = *current_index; + /*parse our args*/ + { + arg = argv[i]; + if (!stricmp(arg, "-itags")) { CHECK_NEXT_ARG - gf_logs = argv[i+1]; - if (gf_logs) - gf_log_set_tools_levels(gf_logs); + itunes_tags = argv[i + 1]; i++; + open_edit = GF_TRUE; } - else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { - logfile = gf_fopen(argv[i+1], "wt"); - gf_log_set_callback(logfile, on_gpac_log); - i++; +#ifndef GPAC_DISABLE_ISOM_HINTING + else if (!stricmp(arg, "-hint")) { + open_edit = GF_TRUE; + HintIt = 1; } - else if (!stricmp(arg, "-noprog")) quiet = 1; - else if (!stricmp(arg, "-info")) { - 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; - } else { - info_track_id=0; + else if (!stricmp(arg, "-unhint")) { + open_edit = GF_TRUE; + remove_hint = 1; + } + else if (!stricmp(arg, "-copy")) HintCopy = 1; + 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")) { + 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 = TRAC_ACTION_REM_NON_RAP; + tracks[nb_track_act].trackID = trackID; + nb_track_act++; + i++; + open_edit = GF_TRUE; + } } + hint_flags |= GP_RTP_PCK_SIGNAL_RAP; + seg_at_rap = 1; } -#if !defined(GPAC_DISABLE_STREAMING) - else if (!stricmp(arg, "-grab-ts")) { - CHECK_NEXT_ARG - grab_m2ts = argv[i+1]; - i++; + else if (!stricmp(arg, "-frag-rap")) { + frag_at_rap = 1; } - else if (!stricmp(arg, "-ifce")) { - CHECK_NEXT_ARG - grab_ifce = argv[i+1]; - i++; + 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; + } } - #endif -#if !defined(GPAC_DISABLE_CORE_TOOLS) - else if (!stricmp(arg, "-wget")) { - CHECK_NEXT_ARG - do_wget = argv[i+1]; - i++; - } + 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 - /*******************************************************************************/ - else if (!stricmp(arg, "-dvbhdemux")) { - dvbhdemux = 1; } - /********************************************************************************/ -#ifndef GPAC_DISABLE_MEDIA_EXPORT - else if (!stricmp(arg, "-raw")) { +#ifndef GPAC_DISABLE_ISOM_HINTING + else if (!stricmp(arg, "-mtu")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE); + MTUSize = atoi(argv[i + 1]); i++; } - else if (!stricmp(arg, "-raw-layer")) { + else if (!stricmp(arg, "-cardur")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER); + car_dur = atoi(argv[i + 1]); i++; } - else if (!stricmp(arg, "-qcp")) { + else if (!stricmp(arg, "-rate")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP); + rtp_rate = atoi(argv[i + 1]); i++; } - else if (!stricmp(arg, "-aviraw")) { +#ifndef GPAC_DISABLE_SENG + else if (!stricmp(arg, "-add-sdp") || !stricmp(arg, "-sdp_ex")) { + char *id; 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); + 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 { + id[0] = ':'; + sdp_lines[nb_sdp_ex].line = argv[i + 1]; + sdp_lines[nb_sdp_ex].trackID = 0; + } } else { - fprintf(stderr, "Usage: \"-aviraw video\" or \"-aviraw audio\"\n"); - MP4BOX_EXIT_WITH_CODE(1); + sdp_lines[nb_sdp_ex].line = argv[i + 1]; + sdp_lines[nb_sdp_ex].trackID = 0; } - track_dump_type = GF_EXPORT_AVI_NATIVE; + open_edit = GF_TRUE; + nb_sdp_ex++; i++; } - else if (!stricmp(arg, "-raws")) { +#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 = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_RAW_SAMPLES); + 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 } - else if (!stricmp(arg, "-nhnt")) { + else if (!stricmp(arg, "-iod")) regular_iod = 1; + else if (!stricmp(arg, "-flat")) { + open_edit = GF_TRUE; + do_flat = GF_TRUE; + } + else if (!stricmp(arg, "-keep-utc")) keep_utc = GF_TRUE; + else if (!stricmp(arg, "-new")) force_new = GF_TRUE; + else if (!stricmp(arg, "-timescale")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NHNT); + timescale = atoi(argv[i + 1]); + open_edit = GF_TRUE; i++; } - else if (!stricmp(arg, "-nhml")) { + else if (!stricmp(arg, "-udta")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NHML); + 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, "-webvtt-raw")) { + else if (!stricmp(arg, "-add") || !stricmp(arg, "-import") || !stricmp(arg, "-convert")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_WEBVTT_META); + 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, "-six")) { + else if (!stricmp(arg, "-cat") || !stricmp(arg, "-catx")) { CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_SIX); + nb_cat++; i++; } - else if (!stricmp(arg, "-avi")) { + else if (!stricmp(arg, "-time")) { + struct tm time; CHECK_NEXT_ARG - track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_AVI); + 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++; } -#endif /*GPAC_DISABLE_MEDIA_EXPORT*/ -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - else if (!stricmp(arg, "-rtp")) { - stream_rtp = 1; - } - else if (!stricmp(arg, "-live")) { - live_scene = 1; - } -#endif - else if (!stricmp(arg, "-diod")) { - dump_iod = 1; - } -#ifndef GPAC_DISABLE_VRML - else if (!stricmp(arg, "-node")) { - CHECK_NEXT_ARG PrintNode(argv[i+1], 0); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-xnode")) { - CHECK_NEXT_ARG PrintNode(argv[i+1], 1); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-nodes")) { - PrintBuiltInNodes(0); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-xnodes")) { - PrintBuiltInNodes(1); - MP4BOX_EXIT_WITH_CODE(0); + 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++; } -#endif -#ifndef GPAC_DISABLE_SVG - else if (!stricmp(arg, "-snode")) { - CHECK_NEXT_ARG PrintNode(argv[i+1], 2); - MP4BOX_EXIT_WITH_CODE(0); + 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++; } - else if (!stricmp(arg, "-snodes")) { - PrintBuiltInNodes(2); - MP4BOX_EXIT_WITH_CODE(0); + 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]); + return 2; + } + *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++; } -#endif - else if (!stricmp(arg, "-std")) dump_std = 2; - else if (!stricmp(arg, "-stdb")) dump_std = 1; - -#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_SCENE_DUMP) - 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, "-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)); - 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, "-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, "-hash")) do_hash = 1; - else if (!stricmp(arg, "-bin")) do_bin_nhml = 1; - 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]; - } else { - code = argv[i+1]; + 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 ID=PAR_NUM:PAR_DEN got %s\n", argv[i + 1]); + return 2; } - dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]); + if (!stricmp(ext + 1, "none")) { + tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = -1; + } + else { + sscanf(ext + 1, "%d", &tracks[nb_track_act].par_num); + ext = strchr(ext + 1, ':'); + if (!ext) { + fprintf(stderr, "Bad format for track par - expecting ID=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, "-lang")) { + 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)); - -#if 0 - else if (!stricmp(arg, "-conf")) { - if (i+1==(u32)argc) { - fprintf(stderr, "Missing arg - please check usage\n"); - MP4BOX_EXIT_WITH_CODE(1); + tracks[nb_track_act].act_type = TRAC_ACTION_SET_LANGUAGE; + tracks[nb_track_act].trackID = 0; + strcpy(szTK, argv[i + 1]); + ext = strchr(szTK, '='); + if (!strnicmp(argv[i + 1], "all=", 4)) { + strncpy(tracks[nb_track_act].lang, argv[i + 1] + 4, 10); } - if (i+2==(u32)argc) { - gf_check_isom_files(NULL, argv[i+1]); - } else { - gf_check_isom_files(argv[i+1], argv[i+2]); + else if (!ext) { + strncpy(tracks[nb_track_act].lang, argv[i + 1], 10); } - MP4BOX_EXIT_WITH_CODE(0); - } -#endif - 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 (argv[i+1][0] != '-') program_number = atoi(argv[i+1]); - i++; + else { + strncpy(tracks[nb_track_act].lang, ext + 1, 10); + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + ext[0] = '='; } - } else if (!stricmp(arg, "-dnal")) { - CHECK_NEXT_ARG - dump_nal = atoi(argv[i+1]); + open_edit = GF_TRUE; + nb_track_act++; 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 { - trackID = 0; + else if (!stricmp(arg, "-kind") || !stricmp(arg, "-kind-rem")) { + char szTK[200], *ext; + char *scheme_start = NULL; + Bool has_track_id = GF_FALSE; + CHECK_NEXT_ARG + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); + + if (!stricmp(arg, "-kind")) { + tracks[nb_track_act].act_type = TRAC_ACTION_SET_KIND; } -#ifdef GPAC_DISABLE_ISOM_WRITE - if (trackID) { - fprintf(stderr, "Error: Read-Only version - subtitle conversion not available\n"); - MP4BOX_EXIT_WITH_CODE(1); + else { + tracks[nb_track_act].act_type = TRAC_ACTION_REM_KIND; } -#endif - 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++; + tracks[nb_track_act].trackID = 0; + if (!strnicmp(argv[i + 1], "all=", 4)) { + scheme_start = argv[i + 1] + 4; + has_track_id = GF_TRUE; } + 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; + } + else { + scheme_start = szTK; + } + ext[0] = '='; + } + else { + scheme_start = szTK; + } + } + 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++; } - -#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")) { + else if (!stricmp(arg, "-delay")) { + char szTK[20], *ext; CHECK_NEXT_ARG - swf_flatten_angle = (Float) atof(argv[i+1]); + tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act + 1)); + memset(&tracks[nb_track_act], 0, sizeof(TrackAction)); + + strcpy(szTK, argv[i + 1]); + ext = strchr(szTK, '='); + if (!ext) { + fprintf(stderr, "Bad format for track delay - expecting ID=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++; } -#endif -#ifndef GPAC_DISABLE_ISOM_WRITE - else if (!stricmp(arg, "-isma")) { - conv_type = GF_ISOM_CONV_TYPE_ISMA; - open_edit = 1; - } - else if (!stricmp(arg, "-3gp")) { - conv_type = GF_ISOM_CONV_TYPE_3GPP; - open_edit = 1; - } - else if (!stricmp(arg, "-ipod")) { - conv_type = GF_ISOM_CONV_TYPE_IPOD; - open_edit = 1; - } - else if (!stricmp(arg, "-psp")) { - conv_type = GF_ISOM_CONV_TYPE_PSP; - open_edit = 1; - } - else if (!stricmp(arg, "-ismax")) { - conv_type = GF_ISOM_CONV_TYPE_ISMA_EX; - open_edit = 1; + 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)); + + szTK = argv[i + 1]; + ext = strchr(szTK, ':'); + if (!ext) { + fprintf(stderr, "Bad format for track reference - expecting ID: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 ID: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++; } + 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)); - else if (!stricmp(arg, "-no-sys") || !stricmp(arg, "-nosys")) { - remove_sys_tracks = 1; - open_edit = 1; + strcpy(szTK, argv[i + 1]); + ext = strchr(szTK, '='); + if (!ext) { + fprintf(stderr, "Bad format for track name - expecting ID=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++; } - else if (!stricmp(arg, "-no-iod")) { - remove_root_od = 1; - open_edit = 1; +#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")) import_fps = GF_IMPORT_AUTO_FPS; + 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 = ticks; + import_fps /= dts_inc; + } + else import_fps = atof(argv[i + 1]); + i++; } - else if (!stricmp(arg, "-out")) { - CHECK_NEXT_ARG outName = argv[i+1]; + else if (!stricmp(arg, "-agg")) { + CHECK_NEXT_ARG agg_samples = atoi(argv[i + 1]); i++; } - else if (!stricmp(arg, "-tmp")) { - CHECK_NEXT_ARG tmpdir = argv[i+1]; + else if (!stricmp(arg, "-keep-all") || !stricmp(arg, "-keepall")) import_flags |= GF_IMPORT_KEEP_ALL_TRACKS; +#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, "-co64")) { - force_co64 = GF_TRUE; - open_edit = 1; + else if (!stricmp(arg, "-mp4")) { + encode = GF_TRUE; + open_edit = GF_TRUE; } - else if (!stricmp(arg, "-write-buffer")) { + else if (!stricmp(arg, "-saf")) { + do_saf = GF_TRUE; + } + else if (!stricmp(arg, "-log")) { + do_log = GF_TRUE; + } +#ifndef GPAC_DISABLE_MPD + else if (!stricmp(arg, "-mpd")) { + do_mpd = GF_TRUE; CHECK_NEXT_ARG - gf_isom_set_output_buffering(NULL, atoi(argv[i+1])); + inName = argv[i + 1]; i++; } - else if (!stricmp(arg, "-cprt")) { - CHECK_NEXT_ARG cprt = argv[i+1]; +#endif + +#ifndef GPAC_DISABLE_SCENE_ENCODER + else if (!stricmp(arg, "-def")) opts.flags |= GF_SM_ENCODE_USE_NAMES; + else if (!stricmp(arg, "-sync")) { + CHECK_NEXT_ARG + opts.flags |= GF_SM_ENCODE_RAP_INBAND; + opts.rap_freq = atoi(argv[i + 1]); i++; - if (!dash_duration) open_edit = 1; } - else if (!stricmp(arg, "-chap")) { - CHECK_NEXT_ARG chap_file = argv[i+1]; + else if (!stricmp(arg, "-shadow")) { + CHECK_NEXT_ARG + opts.flags &= ~GF_SM_ENCODE_RAP_INBAND; + opts.flags |= GF_SM_ENCODE_RAP_SHADOW; + opts.rap_freq = atoi(argv[i + 1]); i++; - open_edit = 1; } - else if (!strcmp(arg, "-strict-error")) { - gf_log_set_strict_error(1); - } else if (!stricmp(arg, "-inter") || !stricmp(arg, "-old-inter")) { + else if (!stricmp(arg, "-carousel")) { CHECK_NEXT_ARG - interleaving_time = atof(argv[i+1]) / 1000; - open_edit = 1; - needSave = 1; - if (!stricmp(arg, "-old-inter")) old_interleave = 1; + opts.flags &= ~(GF_SM_ENCODE_RAP_INBAND | GF_SM_ENCODE_RAP_SHADOW); + opts.rap_freq = atoi(argv[i + 1]); i++; - } else if (!stricmp(arg, "-frag")) { + } + /*LASeR options*/ + else if (!stricmp(arg, "-resolution")) { CHECK_NEXT_ARG - interleaving_time = atof(argv[i+1]) / 1000; - needSave = 1; + opts.resolution = atoi(argv[i + 1]); i++; - Frag = 1; - } else if (!stricmp(arg, "-dash")) { + } +#ifndef GPAC_DISABLE_SCENE_STATS + else if (!stricmp(arg, "-auto-quant")) { 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]); - MP4BOX_EXIT_WITH_CODE(1); - } + opts.resolution = atoi(argv[i + 1]); + opts.auto_quant = 1; i++; - } else if (!stricmp(arg, "-subdur")) { + } +#endif + else if (!stricmp(arg, "-coord-bits")) { CHECK_NEXT_ARG - dash_subduration = atof(argv[i+1]) / 1000; + opts.coord_bits = atoi(argv[i + 1]); i++; - } else if (!stricmp(arg, "-dash-scale")) { + } + else if (!stricmp(arg, "-scale-bits")) { CHECK_NEXT_ARG - dash_scale = atoi(argv[i+1]); - if (!dash_scale) { - fprintf(stderr, "\tERROR: \"-dash-scale\": invalid parameter %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); - } + opts.scale_bits = atoi(argv[i + 1]); i++; - } else if (!stricmp(arg, "-dash-ts-prog")) { + } + else if (!stricmp(arg, "-global-quant")) { CHECK_NEXT_ARG - program_number = atoi(argv[i+1]); + opts.resolution = atoi(argv[i + 1]); + opts.auto_quant = 2; i++; - } else if (!stricmp(arg, "-subsegs-per-sidx") || !stricmp(arg, "-frags-per-sidx")) { + } + /*chunk encoding*/ + else if (!stricmp(arg, "-ctx-out") || !stricmp(arg, "-outctx")) { CHECK_NEXT_ARG - subsegs_per_sidx = atoi(argv[i+1]); + output_ctx = argv[i + 1]; i++; - } else if (!stricmp(arg, "-segment-name")) { + } + else if (!stricmp(arg, "-ctx-in") || !stricmp(arg, "-inctx")) { CHECK_NEXT_ARG - seg_name = argv[i+1]; + chunk_mode = GF_TRUE; + input_ctx = argv[i + 1]; i++; - } else if (!stricmp(arg, "-segment-ext")) { + } +#endif /*GPAC_DISABLE_SCENE_ENCODER*/ + else if (!strcmp(arg, "-crypt")) { CHECK_NEXT_ARG - seg_ext = argv[i+1]; - i++; - } else if (!stricmp(arg, "-bs-switching")) { + crypt = 1; + drm_file = argv[i + 1]; + open_edit = GF_TRUE; + i += 1; + } + else if (!strcmp(arg, "-decrypt")) { 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; + 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 { - fprintf(stderr, "\tWARNING: Unrecognized bitstream switchin mode \"%s\" - please check usage\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); + tracks[nb_track_act].kms = ext + 1; + ext[0] = 0; + tracks[nb_track_act].trackID = atoi(szTK); + ext[0] = '='; } + open_edit = GF_TRUE; + nb_track_act++; i++; } - else if (!stricmp(arg, "-dynamic")) { - dash_mode = GF_DASH_DYNAMIC; - } - else if (!stricmp(arg, "-last-dynamic")) { - dash_mode = GF_DASH_DYNAMIC_LAST; + 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, "-frag-rt")) { - frag_real_time = GF_TRUE; + else if (!stricmp(arg, "-split-rap") || !stricmp(arg, "-splitr")) { + CHECK_NEXT_ARG + split_duration = -1; + split_size = -1; } - 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; - } + else if (!stricmp(arg, "-split-size") || !stricmp(arg, "-splits")) { CHECK_NEXT_ARG - dash_duration = atof(argv[i+1]) / 1000; + split_size = (u32)atoi(argv[i + 1]); i++; + split_duration = 0; } - else if (!stricmp(arg, "-mpd-duration")) { - CHECK_NEXT_ARG mpd_live_duration = atof(argv[i+1]); + 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; + } + if (strstr(argv[i + 1], "end")) { + sscanf(argv[i + 1], "%lf:end", &split_start); + split_duration = -2; + } + else { + sscanf(argv[i + 1], "%lf:%lf", &split_start, &split_duration); + split_duration -= split_start; + } + split_size = 0; + if (!stricmp(arg, "-splitz")) adjust_split_end = 1; i++; } - else if (!stricmp(arg, "-mpd-refresh")) { - CHECK_NEXT_ARG mpd_update_time = atof(argv[i+1]); + /*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, "-time-shift")) { - CHECK_NEXT_ARG - time_shift_depth = (u32) atoi(argv[i+1]); + 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, "-min-buffer")) { - CHECK_NEXT_ARG - min_buffer = atoi(argv[i+1]); - min_buffer /= 1000; + 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, "-ast-offset")) { - CHECK_NEXT_ARG - ast_offset_ms = atoi(argv[i+1]); + 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, "-moof-sn")) { - CHECK_NEXT_ARG - initial_moof_sn = (u32) atoi(argv[i+1]); + 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, "-tfdt")) { - CHECK_NEXT_ARG - sscanf(argv[i+1], LLU, &initial_tfdt); + 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, "-no-frags-default")) { - no_fragments_defaults = 1; + 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, "-single-traf")) { - single_traf_per_moof = 1; + 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, "-mpd-title")) { - CHECK_NEXT_ARG dash_title = argv[i+1]; + 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, "-mpd-source")) { - CHECK_NEXT_ARG dash_source = argv[i+1]; + else if (!stricmp(arg, "-group-add") || !stricmp(arg, "-group-rem-track") || !stricmp(arg, "-group-rem") || !stricmp(arg, "-group-clean")) { + 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, "-mpd-info-url")) { - CHECK_NEXT_ARG dash_more_info = argv[i+1]; + 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, "-base-url")) { + else if (!stricmp(arg, "-mgt")) { CHECK_NEXT_ARG - dash_more_info = argv[i+1]; - mpd_base_urls = gf_realloc(mpd_base_urls, (nb_mpd_base_urls+1)*sizeof(char**)); - mpd_base_urls[nb_mpd_base_urls] = argv[i+1]; - nb_mpd_base_urls++; + pack_file = argv[i + 1]; + pack_wgt = GF_TRUE; i++; } - else if (!stricmp(arg, "-dash-ctx")) { + else if (!stricmp(arg, "-brand")) { + char *b = argv[i + 1]; CHECK_NEXT_ARG - dash_ctx_file = argv[i+1]; + major_brand = GF_4CC(b[0], b[1], b[2], b[3]); + open_edit = GF_TRUE; + if (b[4] == ':') minor_version = atoi(b + 5); i++; - } else if (!stricmp(arg, "-daisy-chain")) { - daisy_chain_sidx = 1; - } else if (!stricmp(arg, "-single-segment")) { - single_segment = 1; - } else if (!stricmp(arg, "-single-file")) { - single_file = 1; - } else if (!stricmp(arg, "-pssh-moof")) { - pssh_in_moof = 1; - } else if (!stricmp(arg, "-sample-groups-traf")) { - samplegroups_in_traf = 1; - } else if (!stricmp(arg, "-dash-profile") || !stricmp(arg, "-profile")) { + } + else if (!stricmp(arg, "-ab")) { + char *b = argv[i + 1]; CHECK_NEXT_ARG - if (!stricmp(argv[i+1], "live") || !stricmp(argv[i+1], "simple")) dash_profile = GF_DASH_PROFILE_LIVE; - else if (!stricmp(argv[i+1], "onDemand")) dash_profile = GF_DASH_PROFILE_ONDEMAND; - else if (!stricmp(argv[i+1], "hbbtv1.5:live")) { - dash_profile = GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE; - } else if (!stricmp(argv[i+1], "dashavc264:live")) { - dash_profile = GF_DASH_PROFILE_AVC264_LIVE; - } else if (!stricmp(argv[i+1], "dashavc264:onDemand")) { - dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND; - } else if (!stricmp(argv[i+1], "main")) dash_profile = GF_DASH_PROFILE_MAIN; - else dash_profile = GF_DASH_PROFILE_FULL; + 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, "-profile-ext")) { + } + else if (!stricmp(arg, "-rb")) { + char *b = argv[i + 1]; CHECK_NEXT_ARG - dash_profile_extension = argv[i+1]; + 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++; - } 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; + } +#endif +else if (!stricmp(arg, "-languages")) { + PrintLanguages(); + return 1; +} +else if (!stricmp(arg, "-h")) { + 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")) PrintFormats(); + 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")) PrintStreamerUsage(); + else if (!strcmp(argv[i + 1], "live")) PrintLiveUsage(); +#endif + else if (!strcmp(argv[i + 1], "all")) { + PrintGeneralUsage(); + PrintExtractUsage(); + PrintDASHUsage(); + PrintDumpUsage(); + PrintImportUsage(); + PrintFormats(); + PrintHintUsage(); + PrintEncodeUsage(); + PrintEncryptUsage(); + PrintMetaUsage(); + PrintSWFUsage(); +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + PrintStreamerUsage(); + PrintLiveUsage(); +#endif + } + else PrintUsage(); + return 1; +} +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); + } + return 1; +} +else if (!live_scene && !stream_rtp) { + fprintf(stderr, "Option %s unknown. Please check usage\n", arg); + return 2; +} +} +*current_index = i; +return 0; +} + +Bool mp4box_parse_args(int argc, char **argv) +{ + u32 i; + /*parse our args*/ + for (i = 1; i < (u32)argc; i++) { + 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; + } + 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 { + fprintf(stderr, "Error - 2 input names specified, please check usage\n"); + return 2; + } } - } 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; + else { + inName = arg_val; + } + } + 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 (!stricmp(arg, "-quiet")) quiet = 2; + else if (!strcmp(argv[i], "-mem-track")) continue; + else if (!strcmp(argv[i], "-mem-track-stack")) continue; + + else if (!stricmp(arg, "-logs")) { CHECK_NEXT_ARG - m = argv[i+1]; - segment_marker = GF_4CC(m[0], m[1], m[2], m[3]); + gf_logs = argv[i + 1]; + if (gf_logs) + gf_log_set_tools_levels(gf_logs); i++; - } else if (!stricmp(arg, "-insert-utc")) { - insert_utc = GF_TRUE; - } else if (!stricmp(arg, "-itags")) { - CHECK_NEXT_ARG itunes_tags = argv[i+1]; + } + else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { + logfile = gf_fopen(argv[i + 1], "wt"); + gf_log_set_callback(logfile, on_gpac_log); i++; - open_edit = 1; } -#ifndef GPAC_DISABLE_ISOM_HINTING - else if (!stricmp(arg, "-hint")) { - open_edit = 1; - HintIt = 1; + else if (!strcmp(arg, "-lc") || !strcmp(arg, "-log-clock")) { + log_sys_clock = GF_TRUE; } - else if (!stricmp(arg, "-unhint")) { - open_edit = 1; - remove_hint = 1; + else if (!strcmp(arg, "-lu") || !strcmp(arg, "-log-utc")) { + log_utc_time = GF_TRUE; } - else if (!stricmp(arg, "-copy")) HintCopy = 1; - else if (!stricmp(arg, "-tight")) { - FullInter = 1; - open_edit = 1; - needSave = 1; - } 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")) { - 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 = TRAC_ACTION_REM_NON_RAP; - tracks[nb_track_act].trackID = trackID; - nb_track_act++; - i++; - open_edit = 1; - } + else if (!stricmp(arg, "-noprog")) quiet = 1; + else if (!stricmp(arg, "-info")) { + 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; } - 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, "-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; + else { + info_track_id = 0; } } -#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]); +#if !defined(GPAC_DISABLE_STREAMING) + else if (!stricmp(arg, "-grab-ts")) { + CHECK_NEXT_ARG + grab_m2ts = argv[i + 1]; i++; } -#ifndef GPAC_DISABLE_SENG - else if (!stricmp(arg, "-add-sdp") || !stricmp(arg, "-sdp_ex")) { - char *id; + else if (!stricmp(arg, "-ifce")) { 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 { - id[0] = ':'; - sdp_lines[nb_sdp_ex].line = argv[i+1]; - sdp_lines[nb_sdp_ex].trackID = 0; - } - } else { - sdp_lines[nb_sdp_ex].line = argv[i+1]; - sdp_lines[nb_sdp_ex].trackID = 0; - } - open_edit = 1; - nb_sdp_ex++; + grab_ifce = argv[i + 1]; i++; } -#endif /*GPAC_DISABLE_SENG*/ -#endif /*GPAC_DISABLE_ISOM_HINTING*/ - else if (!stricmp(arg, "-single")) { -#ifndef GPAC_DISABLE_MEDIA_EXPORT +#endif +#if !defined(GPAC_DISABLE_CORE_TOOLS) + else if (!stricmp(arg, "-wget")) { 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++; + do_wget = argv[i + 1]; i++; -#endif } - else if (!stricmp(arg, "-iod")) regular_iod = 1; - else if (!stricmp(arg, "-flat")) { - open_edit = 1; - do_flat = 1; +#endif + /*******************************************************************************/ + else if (!stricmp(arg, "-dvbhdemux")) { + dvbhdemux = GF_TRUE; } - else if (!stricmp(arg, "-keep-utc")) keep_utc = 1; - else if (!stricmp(arg, "-new")) force_new = 1; - else if (!stricmp(arg, "-timescale")) { + /********************************************************************************/ +#ifndef GPAC_DISABLE_MEDIA_EXPORT + else if (!stricmp(arg, "-raw")) { CHECK_NEXT_ARG - timescale = atoi(argv[i+1]); - open_edit = 1; + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NATIVE); i++; } - else if (!stricmp(arg, "-udta")) { + else if (!stricmp(arg, "-raw-layer")) { 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 = 1; + 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, "-add") || !stricmp(arg, "-import") || !stricmp(arg, "-convert")) { + else if (!stricmp(arg, "-qcp")) { 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++; + 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, "-cat") || !stricmp(arg, "-catx")) { + else if (!stricmp(arg, "-aviraw")) { CHECK_NEXT_ARG - nb_cat++; + 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; + } + track_dump_type = GF_EXPORT_AVI_NATIVE; i++; } - else if (!stricmp(arg, "-time")) { - struct tm time; + else if (!stricmp(arg, "-raws")) { 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 = 1; - movie_time = 2082758400; - movie_time += mktime(&time); + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_RAW_SAMPLES); i++; } - 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")) { + else if (!stricmp(arg, "-nhnt")) { CHECK_NEXT_ARG - raw_cat = argv[i+1]; + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NHNT); i++; } - else if (!stricmp(arg, "-rem") || !stricmp(arg, "-disable") || !stricmp(arg, "-enable")) { + else if (!stricmp(arg, "-nhml")) { 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 = 1; - nb_track_act++; + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_NHML); i++; } - else if (!stricmp(arg, "-set-track-id")) { - char *sep; + else if (!stricmp(arg, "-webvtt-raw")) { 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_ID; - sep = strchr(argv[i+1], ':'); - *sep = 0; - tracks[nb_track_act].trackID = atoi(argv[i+1]); - *sep = ':'; - sep++; - tracks[nb_track_act].newTrackID = atoi(sep); - open_edit = 1; - nb_track_act++; + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_WEBVTT_META); i++; } - else if (!stricmp(arg, "-par")) { - char szTK[20], *ext; + else if (!stricmp(arg, "-six")) { 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_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 ID=PAR_NUM:PAR_DEN got %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); - } - if (!stricmp(ext+1, "none")) { - tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = -1; - } else { - sscanf(ext+1, "%d", &tracks[nb_track_act].par_num); - ext = strchr(ext+1, ':'); - if (!ext) { - fprintf(stderr, "Bad format for track par - expecting ID=PAR_NUM:PAR_DEN got %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); - } - sscanf(ext+1, "%d", &tracks[nb_track_act].par_den); - } - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - open_edit = 1; - nb_track_act++; + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_SIX); i++; } - else if (!stricmp(arg, "-lang")) { - char szTK[20], *ext; + else if (!stricmp(arg, "-avi")) { 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_LANGUAGE; - tracks[nb_track_act].trackID = 0; - strcpy(szTK, argv[i+1]); - ext = strchr(szTK, '='); - if (!strnicmp(argv[i+1], "all=", 4)) { - tracks[nb_track_act].lang = gf_strdup(argv[i+1]+4); - } else if (!ext) { - tracks[nb_track_act].lang = gf_strdup(argv[i+1]); - } else { - tracks[nb_track_act].lang = gf_strdup(ext+1); - ext[0] = 0; - tracks[nb_track_act].trackID = atoi(szTK); - ext[0] = '='; - } - open_edit = 1; - nb_track_act++; + track_dump_type = create_new_track_action(argv[i + 1], &tracks, &nb_track_act, GF_EXPORT_AVI); i++; } - else if (!stricmp(arg, "-kind") || !stricmp(arg, "-kind-rem")) { - char szTK[200], *ext; - char *scheme_start = NULL; - Bool has_track_id = GF_FALSE; +#endif /*GPAC_DISABLE_MEDIA_EXPORT*/ +#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) + else if (!stricmp(arg, "-rtp")) { + stream_rtp = GF_TRUE; + } + 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 - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); + PrintNode(argv[i + 1], 1); + return 1; + } + else if (!stricmp(arg, "-nodes")) { + PrintBuiltInNodes(0); + return 1; + } + else if (!stricmp(arg, "-xnodes")) { + PrintBuiltInNodes(1); + return 1; + } +#endif +#ifndef GPAC_DISABLE_SVG + else if (!stricmp(arg, "-snodes")) { + PrintBuiltInNodes(2); + return 1; + } +#endif + else if (!stricmp(arg, "-boxes")) { + PrintBuiltInBoxes(); + return 1; + } + else if (!stricmp(arg, "-std")) dump_std = 2; + else if (!stricmp(arg, "-stdb")) dump_std = 1; - if (!stricmp(arg, "-kind")) { - tracks[nb_track_act].act_type = TRAC_ACTION_SET_KIND; - } else { - tracks[nb_track_act].act_type = TRAC_ACTION_REM_KIND; - } - tracks[nb_track_act].trackID = 0; - if (!strnicmp(argv[i+1], "all=", 4)) { - scheme_start = argv[i+1]+4; - has_track_id = GF_TRUE; - } - 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; - } else { - scheme_start = szTK; - } - ext[0] = '='; - } else { - scheme_start = szTK; - } +#if !defined(GPAC_DISABLE_MEDIA_EXPORT) && !defined(GPAC_DISABLE_SCENE_DUMP) + 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, "-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, "-hash")) do_hash = GF_TRUE; +#ifndef GPAC_DISABLE_CORE_TOOLS + else if (!stricmp(arg, "-bin")) do_bin_nhml = 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]; } - 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); + else { + code = argv[i + 1]; } - open_edit = 1; - nb_track_act++; + dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]); i++; } - 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) ); - - strcpy(szTK, argv[i+1]); - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track delay - expecting ID=DLAY got %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); + 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++; + } } - 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 = 1; - nb_track_act++; - i++; } - else if (!stricmp(arg, "-ref")) { - char *szTK, *ext; + else if (!stricmp(arg, "-dnal")) { CHECK_NEXT_ARG - tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); - memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); - - szTK = argv[i+1]; - ext = strchr(szTK, ':'); - if (!ext) { - fprintf(stderr, "Bad format for track reference - expecting ID:XXXX:refID got %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); + dump_nal = atoi(argv[i + 1]); + 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; } - 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 ID:XXXX:refID got %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(1); + else { + trackID = 0; } - ext[0] = 0; - tracks[nb_track_act].lang = gf_strdup(szTK); - ext[0] = ':'; - tracks[nb_track_act].delay_ms = (s32) atoi(ext+1); - open_edit = 1; - nb_track_act++; - i++; +#ifdef GPAC_DISABLE_ISOM_WRITE + if (trackID) { + fprintf(stderr, "Error: Read-Only version - subtitle conversion not available\n"); + return 2; + } +#endif + if (!stricmp(arg, "-ttxt")) dump_ttxt = GF_TRUE; + else dump_srt = GF_TRUE; + import_subtitle = 1; } - 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) ); - - strcpy(szTK, argv[i+1]); - ext = strchr(szTK, '='); - if (!ext) { - fprintf(stderr, "Bad format for track name - expecting ID=name got %s\n", argv[i+1]); - MP4BOX_EXIT_WITH_CODE(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++; } - 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 = 1; - nb_track_act++; - i++; } -#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")) { + +#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 - if (!strcmp(argv[i+1], "auto")) import_fps = GF_IMPORT_AUTO_FPS; - 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 = ticks; - import_fps /= dts_inc; - } else import_fps = atof(argv[i+1]); + swf_flatten_angle = (Float)atof(argv[i + 1]); i++; } - else if (!stricmp(arg, "-agg")) { - CHECK_NEXT_ARG agg_samples = atoi(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, "-keep-all") || !stricmp(arg, "-keepall")) import_flags |= GF_IMPORT_KEEP_ALL_TRACKS; -#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]; + 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; + } + + 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, "-mp4")) { - encode = 1; - open_edit = 1; + else if (!stricmp(arg, "-tmp")) { + CHECK_NEXT_ARG tmpdir = argv[i + 1]; + i++; } - else if (!stricmp(arg, "-saf")) { - do_saf = 1; + else if (!stricmp(arg, "-for-test")) { + force_test_mode = GF_TRUE; } - else if (!stricmp(arg, "-log")) { - do_log = 1; + else if (!stricmp(arg, "-co64")) { + force_co64 = GF_TRUE; + open_edit = GF_TRUE; } -#ifndef GPAC_DISABLE_MPD - else if (!stricmp(arg, "-mpd")) { - do_mpd = 1; + else if (!stricmp(arg, "-write-buffer")) { CHECK_NEXT_ARG - inName = argv[i+1]; + gf_isom_set_output_buffering(NULL, atoi(argv[i + 1])); i++; } -#endif - -#ifndef GPAC_DISABLE_SCENE_ENCODER - else if (!stricmp(arg, "-def")) opts.flags |= GF_SM_ENCODE_USE_NAMES; - else if (!stricmp(arg, "-sync")) { - CHECK_NEXT_ARG - opts.flags |= GF_SM_ENCODE_RAP_INBAND; - opts.rap_freq = atoi(argv[i+1]); + else if (!stricmp(arg, "-cprt")) { + CHECK_NEXT_ARG cprt = argv[i + 1]; i++; - } else if (!stricmp(arg, "-shadow")) { - CHECK_NEXT_ARG - opts.flags &= ~GF_SM_ENCODE_RAP_INBAND; - opts.flags |= GF_SM_ENCODE_RAP_SHADOW; - opts.rap_freq = atoi(argv[i+1]); + if (!dash_duration) open_edit = GF_TRUE; + } + else if (!stricmp(arg, "-chap")) { + CHECK_NEXT_ARG chap_file = argv[i + 1]; i++; - } else if (!stricmp(arg, "-carousel")) { + open_edit = GF_TRUE; + } + else if (!strcmp(arg, "-strict-error")) { + gf_log_set_strict_error(1); + } + else if (!stricmp(arg, "-inter") || !stricmp(arg, "-old-inter")) { CHECK_NEXT_ARG - opts.flags &= ~(GF_SM_ENCODE_RAP_INBAND | GF_SM_ENCODE_RAP_SHADOW); - opts.rap_freq = atoi(argv[i+1]); + interleaving_time = atof(argv[i + 1]) / 1000; + open_edit = GF_TRUE; + needSave = GF_TRUE; + if (!stricmp(arg, "-old-inter")) old_interleave = 1; i++; } - /*LASeR options*/ - else if (!stricmp(arg, "-resolution")) { + else if (!stricmp(arg, "-frag")) { CHECK_NEXT_ARG - opts.resolution = atoi(argv[i+1]); + interleaving_time = atof(argv[i + 1]) / 1000; + needSave = GF_TRUE; i++; + Frag = 1; } -#ifndef GPAC_DISABLE_SCENE_STATS - else if (!stricmp(arg, "-auto-quant")) { + else if (!stricmp(arg, "-dash")) { CHECK_NEXT_ARG - opts.resolution = atoi(argv[i+1]); - opts.auto_quant = 1; + 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; + } i++; } -#endif - else if (!stricmp(arg, "-coord-bits")) { + else if (!stricmp(arg, "-dash-strict")) { CHECK_NEXT_ARG - opts.coord_bits = atoi(argv[i+1]); + 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; + } + dash_duration_strict = GF_TRUE; i++; } - else if (!stricmp(arg, "-scale-bits")) { + else if (!stricmp(arg, "-subdur")) { CHECK_NEXT_ARG - opts.scale_bits = atoi(argv[i+1]); + dash_subduration = atof(argv[i + 1]) / 1000; i++; } - else if (!stricmp(arg, "-global-quant")) { + else if (!stricmp(arg, "-dash-scale")) { CHECK_NEXT_ARG - opts.resolution = atoi(argv[i+1]); - opts.auto_quant = 2; + dash_scale = atoi(argv[i + 1]); + if (!dash_scale) { + fprintf(stderr, "\tERROR: \"-dash-scale\": invalid parameter %s\n", argv[i + 1]); + return 2; + } i++; } - /*chunk encoding*/ - else if (!stricmp(arg, "-ctx-out") || !stricmp(arg, "-outctx")) { - CHECK_NEXT_ARG output_ctx = argv[i+1]; + else if (!stricmp(arg, "-dash-ts-prog")) { + CHECK_NEXT_ARG + program_number = atoi(argv[i + 1]); i++; } - else if (!stricmp(arg, "-ctx-in") || !stricmp(arg, "-inctx")) { + else if (!stricmp(arg, "-subsegs-per-sidx") || !stricmp(arg, "-frags-per-sidx")) { CHECK_NEXT_ARG - chunk_mode = 1; - input_ctx = argv[i+1]; + subsegs_per_sidx = atoi(argv[i + 1]); i++; } -#endif /*GPAC_DISABLE_SCENE_ENCODER*/ - else if (!strcmp(arg, "-crypt")) { + else if (!stricmp(arg, "-segment-name")) { CHECK_NEXT_ARG - crypt = 1; - drm_file = argv[i+1]; - open_edit = 1; - i += 1; + seg_name = argv[i + 1]; + i++; } - else if (!strcmp(arg, "-decrypt")) { + else if (!stricmp(arg, "-dash-run-for")) { CHECK_NEXT_ARG - crypt = 2; - if (get_file_type_by_ext(argv[i+1])!=1) { - drm_file = argv[i+1]; - i += 1; - } - open_edit = 1; + dash_run_for = atoi(argv[i + 1]); + i++; } - else if (!stricmp(arg, "-set-kms")) { - char szTK[20], *ext; + else if (!stricmp(arg, "-segment-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] = '='; - } - open_edit = 1; - nb_track_act++; + seg_ext = argv[i + 1]; i++; } - else if (!stricmp(arg, "-split")) { + else if (!stricmp(arg, "-bs-switching")) { CHECK_NEXT_ARG - split_duration = atof(argv[i+1]); - if (split_duration<0) split_duration=0;; + 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; + } 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, "-dynamic")) { + dash_mode = GF_DASH_DYNAMIC; } - else if (!stricmp(arg, "-split-size") || !stricmp(arg, "-splits")) { - CHECK_NEXT_ARG - split_size = (u32) atoi(argv[i+1]); + else if (!stricmp(arg, "-last-dynamic")) { + dash_mode = GF_DASH_DYNAMIC_LAST; + } + else if (!stricmp(arg, "-frag-rt")) { + frag_real_time = GF_TRUE; + } + else if (!stricmp(arg, "-start-date")) { + dash_start_date = gf_net_parse_date(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"); - MP4BOX_EXIT_WITH_CODE(1); + 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; } - if (strstr(argv[i+1], "end")) { - sscanf(argv[i+1], "%lf:end", &split_start); - split_duration = -2; - } else { - sscanf(argv[i+1], "%lf:%lf", &split_start, &split_duration); - split_duration -= split_start; + } + 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; } - split_size = 0; - if (!stricmp(arg, "-splitz")) adjust_split_end = 1; + CHECK_NEXT_ARG + dash_duration = atof(argv[i + 1]) / 1000; + i++; + } + else if (!stricmp(arg, "-mpd-duration")) { + CHECK_NEXT_ARG mpd_live_duration = atof(argv[i + 1]); + i++; + } + else if (!stricmp(arg, "-mpd-refresh")) { + CHECK_NEXT_ARG mpd_update_time = atof(argv[i + 1]); + i++; + } + else if (!stricmp(arg, "-time-shift")) { + CHECK_NEXT_ARG + time_shift_depth = (u32)atoi(argv[i + 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 = 1; + else if (!stricmp(arg, "-min-buffer")) { + CHECK_NEXT_ARG + min_buffer = atoi(argv[i + 1]); + min_buffer /= 1000; 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 = 1; + else if (!stricmp(arg, "-ast-offset")) { + CHECK_NEXT_ARG + ast_offset_ms = atoi(argv[i + 1]); 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 = 1; + else if (!stricmp(arg, "-moof-sn")) { + CHECK_NEXT_ARG + initial_moof_sn = (u32)atoi(argv[i + 1]); 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 = 1; + else if (!stricmp(arg, "-tfdt")) { + CHECK_NEXT_ARG + sscanf(argv[i + 1], LLU, &initial_tfdt); 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 = 1; - i++; + else if (!stricmp(arg, "-no-frags-default")) { + no_fragments_defaults = 1; } - 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 = 1; + else if (!stricmp(arg, "-single-traf")) { + single_traf_per_moof = 1; } - 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++; + else if (!stricmp(arg, "-mpd-title")) { + CHECK_NEXT_ARG dash_title = argv[i + 1]; 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++; + else if (!stricmp(arg, "-mpd-source")) { + CHECK_NEXT_ARG dash_source = argv[i + 1]; 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"); - MP4BOX_EXIT_WITH_CODE(1); - } - open_edit=1; + else if (!stricmp(arg, "-mpd-info-url")) { + CHECK_NEXT_ARG dash_more_info = argv[i + 1]; i++; } - else if (!stricmp(arg, "-group-clean")) { - tsel_acts[nb_tsel_acts].act_type = TSEL_ACTION_REMOVE_ALL_TSEL_IN_FILE; - nb_tsel_acts++; - open_edit=1; - } - else if (!stricmp(arg, "-group-single")) { - single_group = 1; - } - else if (!stricmp(arg, "-package")) { + else if (!stricmp(arg, "-base-url")) { CHECK_NEXT_ARG - pack_file = argv[i+1]; + dash_more_info = argv[i + 1]; + mpd_base_urls = gf_realloc(mpd_base_urls, (nb_mpd_base_urls + 1)*sizeof(char**)); + mpd_base_urls[nb_mpd_base_urls] = argv[i + 1]; + nb_mpd_base_urls++; i++; } - else if (!stricmp(arg, "-mgt")) { + else if (!stricmp(arg, "-dash-ctx")) { CHECK_NEXT_ARG - pack_file = argv[i+1]; - pack_wgt = 1; + dash_ctx_file = argv[i + 1]; i++; } - - else if (!stricmp(arg, "-brand")) { - char *b = argv[i+1]; + else if (!stricmp(arg, "-daisy-chain")) { + daisy_chain_sidx = 1; + } + else if (!stricmp(arg, "-single-segment")) { + single_segment = 1; + } + else if (!stricmp(arg, "-single-file")) { + single_file = 1; + } + else if (!stricmp(arg, "-pssh-moof")) { + pssh_in_moof = 1; + } + else if (!stricmp(arg, "-sample-groups-traf")) { + samplegroups_in_traf = 1; + } + else if (!stricmp(arg, "-dash-profile") || !stricmp(arg, "-profile")) { CHECK_NEXT_ARG - major_brand = GF_4CC(b[0], b[1], b[2], b[3]); - open_edit = 1; - if (b[4]==':') minor_version = atoi(b+5); + if (!stricmp(argv[i + 1], "live") || !stricmp(argv[i + 1], "simple")) dash_profile = GF_DASH_PROFILE_LIVE; + else if (!stricmp(argv[i + 1], "onDemand")) dash_profile = GF_DASH_PROFILE_ONDEMAND; + else if (!stricmp(argv[i + 1], "hbbtv1.5:live")) { + dash_profile = GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE; + } + else if (!stricmp(argv[i + 1], "dashavc264:live")) { + dash_profile = GF_DASH_PROFILE_AVC264_LIVE; + } + else if (!stricmp(argv[i + 1], "dashavc264:onDemand")) { + dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND; + } + else if (!stricmp(argv[i + 1], "main")) dash_profile = GF_DASH_PROFILE_MAIN; + else dash_profile = GF_DASH_PROFILE_FULL; i++; } - else if (!stricmp(arg, "-ab")) { - char *b = argv[i+1]; + else if (!stricmp(arg, "-profile-ext")) { CHECK_NEXT_ARG - brand_add = 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 = 1; + dash_profile_extension = argv[i + 1]; i++; } - else if (!stricmp(arg, "-rb")) { - char *b = argv[i+1]; + 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; + } + } + 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 - brand_rem = 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 = 1; + m = argv[i + 1]; + segment_marker = GF_4CC(m[0], m[1], m[2], m[3]); i++; } + else if (!stricmp(arg, "-insert-utc")) { + insert_utc = GF_TRUE; + } + else { + u32 ret = mp4box_parse_args_continue(argc, argv, &i); + if (ret) return ret; + } + } + return 0; +} + +int mp4boxMain(int argc, char **argv) +{ + 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; + e = GF_OK; + split_duration = 0.0; + split_start = -1.0; + interleaving_time = DEFAULT_INTERLEAVING_IN_SEC; + dash_duration = dash_subduration = 0.0; + dash_duration_strict = GF_FALSE; + import_fps = 0; + import_flags = 0; + split_size = 0; + movie_time = 0; + dump_nal = 0; + FullInter = HintInter = encode = do_log = old_interleave = do_saf = do_hash = verbose = GF_FALSE; +#ifndef GPAC_DISABLE_SCENE_DUMP + dump_mode = GF_SM_DUMP_NONE; #endif - else if (!stricmp(arg, "-languages")) { - PrintLanguages(); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-h")) { - 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")) PrintFormats(); - 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")) PrintStreamerUsage(); - else if (!strcmp(argv[i+1], "live")) PrintLiveUsage (); + Frag = force_ocr = remove_sys_tracks = agg_samples = remove_hint = keep_sys_tracks = remove_root_od = single_group = clean_groups = GF_FALSE; + conv_type = HintIt = needSave = print_sdp = print_info = regular_iod = dump_std = open_edit = dump_rtp = dump_cr = dump_srt = dump_ttxt = force_new = dump_timestamps = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_live = GF_FALSE; + no_fragments_defaults = GF_FALSE; + single_traf_per_moof = GF_FALSE, + dump_isom = 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; + initial_moof_sn = 0; + initial_tfdt = 0; + +#ifndef GPAC_DISABLE_SCENE_ENCODER + memset(&opts, 0, sizeof(opts)); #endif - else if (!strcmp(argv[i+1], "all")) { - PrintGeneralUsage(); - PrintExtractUsage(); - PrintDASHUsage(); - PrintDumpUsage(); - PrintImportUsage(); - PrintFormats(); - PrintHintUsage(); - PrintEncodeUsage(); - PrintEncryptUsage(); - PrintMetaUsage(); - PrintSWFUsage(); -#if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG) - PrintStreamerUsage(); - PrintLiveUsage (); + + trackID = stat_level = hint_flags = 0; + program_number = 0; + info_track_id = 0; + do_flat = GF_FALSE; + inName = outName = mediaSource = input_ctx = output_ctx = drm_file = avi2raw = cprt = chap_file = pack_file = raw_cat = NULL; + +#ifndef GPAC_DISABLE_SWF_IMPORT + swf_flags = GF_SM_SWF_SPLIT_TIMELINE; #endif - } - else PrintUsage(); - MP4BOX_EXIT_WITH_CODE(0); - } - else if (!stricmp(arg, "-v")) verbose++; - else if (!stricmp(arg, "-tag-list")) { - fprintf(stderr, "Supported iTunes tag modifiers:\n"); - for (i=0; i=0) ? 1 : 0, (u32) subsegs_per_sidx, daisy_chain_sidx); + 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_in_moof, samplegroups_in_traf, single_traf_per_moof); + 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); + + 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)); + return mp4box_cleanup(1); + } + + dash_cumulated_time=0; + while (1) { + if (dash_run_for && (dash_cumulated_time>dash_run_for)) + do_abort = 3; + + dash_prev_time=gf_sys_clock(); if (do_abort>=2) { - dash_mode = GF_DASH_DYNAMIC_LAST; + e = gf_dasher_set_dynamic_mode(dasher, GF_DASH_DYNAMIC_LAST, 0, time_shift_depth, mpd_live_duration); } - e = gf_dasher_segment_files(szMPD, dash_inputs, nb_dash_inputs, dash_profile, dash_title, dash_source, cprt, dash_more_info, - (const char **) mpd_base_urls, nb_mpd_base_urls, - use_url_template, segment_timeline, single_segment, single_file, bitstream_switching_mode, - seg_at_rap, dash_duration, seg_name, seg_ext, segment_marker, - interleaving_time, subsegs_per_sidx, daisy_chain_sidx, frag_at_rap, tmpdir, - dash_ctx, dash_mode, mpd_update_time, time_shift_depth, dash_subduration, min_buffer, - ast_offset_ms, dash_scale, memory_frags, initial_moof_sn, initial_tfdt, no_fragments_defaults, - pssh_in_moof, samplegroups_in_traf, single_traf_per_moof, mpd_live_duration, insert_utc, frag_real_time, dash_profile_extension); + if (!e) e = gf_dasher_process(dasher, dash_subduration); - if (do_abort) + if (do_abort) break; //this happens when reading file while writing them (local playback of the live session ...) @@ -3624,9 +4026,10 @@ int mp4boxMain(int argc, char **argv) if (e) break; if (dash_live) { + u64 ms_in_session=0; u32 slept = gf_sys_clock(); - u32 sleep_for = gf_dasher_next_update_time(dash_ctx, mpd_update_time); - fprintf(stderr, "Next generation scheduled in %d ms\n", sleep_for); + u32 sleep_for = gf_dasher_next_update_time(dasher, &ms_in_session); + fprintf(stderr, "Next generation scheduled in %u ms (DASH time "LLU" ms)\n", sleep_for, ms_in_session); while (1) { if (gf_prompt_has_input()) { char c = (char) gf_prompt_get_char(); @@ -3649,10 +4052,12 @@ int mp4boxMain(int argc, char **argv) } if (!sleep_for) break; - gf_sleep(10); - sleep_for = gf_dasher_next_update_time(dash_ctx, mpd_update_time); - if (sleep_for<10) { - fprintf(stderr, "Slept for %d ms before generation\n", gf_sys_clock() - slept); + gf_sleep(1); + sleep_for = gf_dasher_next_update_time(dasher, NULL); + if (sleep_for<1) { + dash_now_time=gf_sys_clock(); + fprintf(stderr, "Slept for %d ms before generation\n", dash_now_time - slept); + dash_cumulated_time+=(dash_now_time-dash_prev_time); break; } } @@ -3661,6 +4066,8 @@ int mp4boxMain(int argc, char **argv) } } + gf_dasher_del(dasher); + if (dash_ctx) { if (do_abort==3) { if (!dash_ctx_file) { @@ -3679,7 +4086,8 @@ int mp4boxMain(int argc, char **argv) if (del_file) gf_delete_file(inName); - MP4BOX_EXIT_WITH_CODE( (e!=GF_OK) ? 1 : 0 ); + if (e) return mp4box_cleanup(1); + goto exit; } else if (!file @@ -3710,7 +4118,7 @@ int mp4boxMain(int argc, char **argv) if (!file) { fprintf(stderr, "Error opening file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL))); - MP4BOX_EXIT_WITH_CODE(1); + return mp4box_cleanup(1); } } break; @@ -3754,7 +4162,7 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "Error importing %s: %s\n", inName, gf_error_to_string(e)); gf_isom_delete(file); gf_delete_file("ttxt_convert"); - MP4BOX_EXIT_WITH_CODE(1); + return mp4box_cleanup(1); } } #endif /*GPAC_DISABLE_MEDIA_IMPORT*/ @@ -3767,8 +4175,10 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_MPEG2TS dump_mpeg2_ts(inName, pes_dump, program_number); #endif +#ifndef GPAC_DISABLE_CORE_TOOLS } else if (do_bin_nhml) { nhml_bs_to_bin(inName, outName, dump_std); +#endif } else if (do_hash) { hash_file(inName, dump_std); } else { @@ -3776,7 +4186,7 @@ int mp4boxMain(int argc, char **argv) convert_file_info(inName, info_track_id); #endif } - MP4BOX_EXIT_WITH_CODE(0); + goto exit; } #endif /*GPAC_DISABLE_ISOM_WRITE*/ else if (open_edit) { @@ -3784,10 +4194,10 @@ int mp4boxMain(int argc, char **argv) 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)); - MP4BOX_EXIT_WITH_CODE(1); + return mp4box_cleanup(1); } else { fprintf(stderr, "Cannot open %s - extension not supported\n", inName); - MP4BOX_EXIT_WITH_CODE(1); + return mp4box_cleanup(1); } } } @@ -3796,20 +4206,29 @@ int mp4boxMain(int argc, char **argv) gf_isom_keep_utc_times(file, 1); } + if (file && force_test_mode) { + gf_isom_no_version_date_info(file, 1); + } + + strcpy(outfile, outName ? outName : inName); - if (strrchr(outfile, '.')) { - char *szExt = strrchr(outfile, '.'); + { - /*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; + 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; - while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; - outfile[strlen(outfile)-1] = 0; + //remove extension from outfile + *szExt = 0; + } } #ifndef GPAC_DISABLE_MEDIA_EXPORT @@ -3834,7 +4253,7 @@ int mp4boxMain(int argc, char **argv) e = gf_media_export(&mdump); if (e) goto err_exit; - MP4BOX_EXIT_WITH_CODE(0); + goto exit; } if (!open_edit && !gf_isom_probe_file(inName) && track_dump_type) { GF_MediaExporter mdump; @@ -3846,7 +4265,7 @@ int mp4boxMain(int argc, char **argv) mdump.in_name = inName; mdump.flags = tka->dump_type; mdump.trackID = tka->trackID; - mdump.sample_num = raw_sample_num; + mdump.sample_num = tka->sample_num; if (outName) { mdump.out_name = outName; mdump.flags |= GF_EXPORT_MERGE; @@ -3859,24 +4278,24 @@ int mp4boxMain(int argc, char **argv) e = gf_media_export(&mdump); if (e) goto err_exit; } - MP4BOX_EXIT_WITH_CODE(0); + goto exit; } #endif /*GPAC_DISABLE_MEDIA_EXPORT*/ #ifndef GPAC_DISABLE_SCENE_DUMP if (dump_mode != GF_SM_DUMP_NONE) { - e = dump_file_text(inName, dump_std ? NULL : outfile, dump_mode, do_log); + e = dump_isom_scene(inName, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_mode, do_log); if (e) goto err_exit; } #endif #ifndef GPAC_DISABLE_SCENE_STATS - if (stat_level) dump_scene_stats(inName, dump_std ? NULL : outfile, stat_level); + if (stat_level) dump_isom_scene_stats(inName, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, stat_level); #endif #ifndef GPAC_DISABLE_ISOM_HINTING - if (!HintIt && print_sdp) DumpSDP(file, dump_std ? NULL : outfile); + if (!HintIt && print_sdp) dump_isom_sdp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); #endif if (print_info) { if (!file) { @@ -3887,29 +4306,38 @@ int mp4boxMain(int argc, char **argv) } } #ifndef GPAC_DISABLE_ISOM_DUMP - if (dump_isom) dump_isom_xml(file, dump_std ? NULL : outfile); - if (dump_cr) dump_file_ismacryp(file, dump_std ? NULL : outfile); - if ((dump_ttxt || dump_srt) && trackID) dump_timed_text_track(file, trackID, dump_std ? NULL : outfile, 0, dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT); + if (dump_isom) { + e = dump_isom_xml(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, (dump_isom==2) ? GF_TRUE : GF_FALSE); + if (e) goto err_exit; + } + if (dump_cr) dump_isom_ismacryp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); + if ((dump_ttxt || dump_srt) && trackID) + dump_isom_timed_text(file, trackID, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, + GF_FALSE, dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT); + #ifndef GPAC_DISABLE_ISOM_HINTING - if (dump_rtp) dump_file_rtp(file, dump_std ? NULL : outfile); + if (dump_rtp) dump_isom_rtp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); #endif + #endif - if (dump_timestamps) dump_file_timestamps(file, dump_std ? NULL : outfile); - if (dump_nal) dump_file_nal(file, dump_nal, dump_std ? NULL : outfile); + if (dump_timestamps) dump_isom_timestamps(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); + if (dump_nal) dump_isom_nal(file, dump_nal, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE); if (do_hash) { e = hash_file(inName, dump_std); if (e) goto err_exit; } +#ifndef GPAC_DISABLE_CORE_TOOLS if (do_bin_nhml) { e = nhml_bs_to_bin(inName, outName, dump_std); if (e) goto err_exit; } +#endif - if (dump_cart) dump_cover_art(file, outfile); - if (dump_chap) dump_chapters(file, outfile, (dump_chap==2) ? 1 : 0); - if (dump_udta_type) dump_udta(file, outfile, dump_udta_type, dump_udta_track); + 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==2) ? 1 : 0); + 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); @@ -3940,12 +4368,12 @@ int mp4boxMain(int argc, char **argv) } } -#if !(definedGPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) +#if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT) if (split_duration || split_size) { split_isomedia_file(file, split_duration, split_size, inName, interleaving_time, split_start, adjust_split_end, outName, tmpdir); /*never save file when splitting is desired*/ - open_edit = 0; - needSave = 0; + open_edit = GF_FALSE; + needSave = GF_FALSE; } #endif @@ -3960,7 +4388,7 @@ int mp4boxMain(int argc, char **argv) mdump.file = file; mdump.flags = tka->dump_type; mdump.trackID = tka->trackID; - mdump.sample_num = raw_sample_num; + mdump.sample_num = tka->sample_num; if (tka->out_name) { mdump.out_name = tka->out_name; } else if (outName) { @@ -3969,6 +4397,7 @@ int mp4boxMain(int argc, char **argv) } else { sprintf(szFile, "%s_track%d", outfile, mdump.trackID); mdump.out_name = szFile; + mdump.flags |= GF_EXPORT_FORCE_EXT; } if (tka->trackID==(u32) -1) { u32 j; @@ -3976,6 +4405,7 @@ int mp4boxMain(int argc, char **argv) mdump.trackID = gf_isom_get_track_id(file, j+1); sprintf(szFile, "%s_track%d", outfile, mdump.trackID); mdump.out_name = szFile; + mdump.flags |= GF_EXPORT_FORCE_EXT; e = gf_media_export(&mdump); if (e) goto err_exit; } @@ -4008,40 +4438,71 @@ int mp4boxMain(int argc, char **argv) /*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, 1); - needSave = 1; + 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, strlen(meta->szName) ? meta->szName : NULL, meta->item_id, + meta->item_type, strlen(meta->mime_type) ? meta->mime_type : NULL, strlen(meta->enc_type) ? meta->enc_type : NULL, - meta->use_dref ? meta->szPath : NULL, NULL); - needSave = 1; + 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: + { + e = import_file(file, meta->szPath, 0, 0, 0); + if (e == GF_OK) { + if (!gf_isom_get_meta_type(file, meta->root_meta, tk)) { + e = gf_isom_set_meta_type(file, meta->root_meta, tk, GF_4CC('p','i','c','t')); + } + 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) { + gf_isom_iff_create_image_item_from_track(file, meta->root_meta, tk, 1, + strlen(meta->szName) ? meta->szName : NULL, + meta->item_id, + meta->image_props, NULL); + 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); + } + } + } + } + gf_isom_remove_track(file, 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 = 1; + 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 = 1; + 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, (meta->act_type==META_ACTION_SET_BINARY_XML) ? 1 : 0); - needSave = 1; + 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 = 1; + needSave = GF_TRUE; } else { fprintf(stderr, "No meta box in input file\n"); } break; - case META_ACTION_DUMP_XML: + 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 { @@ -4049,7 +4510,7 @@ int mp4boxMain(int argc, char **argv) } break; #endif - case META_ACTION_DUMP_ITEM: + 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 { @@ -4059,14 +4520,25 @@ int mp4boxMain(int argc, char **argv) default: break; } + if (meta->image_props) { + gf_free(meta->image_props); + meta->image_props = NULL; + } if (e) goto err_exit; } if (!open_edit && !needSave) { if (file) gf_isom_delete(file); - MP4BOX_EXIT_WITH_CODE(0); + goto exit; } + #ifndef GPAC_DISABLE_ISOM_WRITE + if (clean_groups) { + e = gf_isom_reset_switch_parameters(file); + if (e) goto err_exit; + needSave = GF_TRUE; + } + for (i=0; itrackID); } - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_SET_LANGUAGE: for (i=0; ilang); if (e) goto err_exit; - needSave = 1; + needSave = GF_TRUE; } - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_SET_KIND: for (i=0; ikind_scheme, tka->kind_value); if (e) goto err_exit; - needSave = 1; + needSave = GF_TRUE; } - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_REM_KIND: for (i=0; ikind_scheme, tka->kind_value); if (e) goto err_exit; - needSave = 1; + needSave = GF_TRUE; } - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_SET_DELAY: if (tka->delay_ms) { @@ -4304,24 +4784,24 @@ int mp4boxMain(int argc, char **argv) gf_isom_remove_edit_segments(file, track); tk_dur = gf_isom_get_track_duration(file, track); if (gf_isom_get_edit_segment_count(file, track)) - needSave = 1; + needSave = GF_TRUE; if (tka->delay_ms>0) { gf_isom_append_edit_segment(file, track, (timescale*tka->delay_ms)/1000, 0, GF_ISOM_EDIT_EMPTY); gf_isom_append_edit_segment(file, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL); - needSave = 1; + 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_segment(file, track, tk_dur-to_skip, media_time, GF_ISOM_EDIT_NORMAL); - needSave = 1; + needSave = GF_TRUE; } else { fprintf(stderr, "Warning: request negative delay longer than track duration - ignoring\n"); } } } else if (gf_isom_get_edit_segment_count(file, track)) { gf_isom_remove_edit_segments(file, track); - needSave = 1; + needSave = GF_TRUE; } break; case TRAC_ACTION_SET_KMS_URI: @@ -4331,10 +4811,14 @@ int mp4boxMain(int argc, char **argv) if (!gf_isom_is_ismacryp_media(file, i+1, 1)) continue; e = gf_isom_change_ismacryp_protection(file, i+1, 1, NULL, (char *) tka->kms); if (e) goto err_exit; - needSave = 1; + 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); @@ -4342,7 +4826,24 @@ int mp4boxMain(int argc, char **argv) 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 = 1; + 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); @@ -4350,36 +4851,37 @@ int mp4boxMain(int argc, char **argv) break; case TRAC_ACTION_SET_PAR: e = gf_media_change_par(file, track, tka->par_num, tka->par_den); - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_SET_HANDLER_NAME: e = gf_isom_set_handler_name(file, track, tka->hdl_name); - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_ENABLE: if (!gf_isom_is_track_enabled(file, track)) { e = gf_isom_set_track_enabled(file, track, 1); - needSave = 1; + needSave = GF_TRUE; } break; case TRAC_ACTION_DISABLE: if (gf_isom_is_track_enabled(file, track)) { e = gf_isom_set_track_enabled(file, track, 0); - needSave = 1; + 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 = 1; + 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); - needSave = 1; + needSave = GF_TRUE; break; case TRAC_ACTION_SET_UDTA: - set_file_udta(file, track, tka->udta_type, tka->src_name, tka->sample_num ? GF_TRUE : GF_FALSE); - needSave = 1; + 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; @@ -4497,7 +4999,7 @@ int mp4boxMain(int argc, char **argv) gf_isom_apple_set_tag(file, itag, val, tlen); break; } - needSave = 1; + needSave = GF_TRUE; if (sep) { sep[0] = ':'; @@ -4513,22 +5015,23 @@ int mp4boxMain(int argc, char **argv) for (i=0; i len) { + fprintf(stderr, "Length allocated for conversion of wide char to UTF-8 not sufficient\n"); + return -1; + } + } + res = mp4boxMain(argc, argv); + for (i = 0; i < argc; i++) { + free(argv[i]); + } + free(argv); + return res; +} +#else +int main(int argc, char** argv) { return mp4boxMain( argc, argv ); } +#endif //win32 + #endif /*GPAC_DISABLE_ISOM*/ diff --git a/applications/mp4client/Makefile b/applications/mp4client/Makefile index 6aff667..9cb577e 100644 --- a/applications/mp4client/Makefile +++ b/applications/mp4client/Makefile @@ -4,7 +4,7 @@ vpath %.c $(SRC_PATH)/applications/mp4client CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" -I../../ -LINKLIBS=$(GPAC_SH_FLAGS) +LINKFLAGS=$(GPAC_SH_FLAGS) ifeq ($(DEBUGBUILD), yes) CFLAGS+=-g @@ -20,28 +20,43 @@ ifeq ($(GPACREADONLY), yes) CFLAGS+=-DGPAC_READ_ONLY endif -#common obj -OBJS= main.o extract.o - ifeq ($(CONFIG_WIN32),yes) +LINKFLAGS+=$(UNICODEFLAGS) EXE=.exe PROG=MP4Client$(EXE) + +ifeq ($(HAS_WMAIN),no) +CFLAGS+=-DNO_WMAIN +endif + else EXT= PROG=MP4Client endif +ifeq ($(STATICBUILD),yes) +##include static modules and other deps for libgpac +include ../../static.mak +LINKFLAGS=-lgpac_static $(GPAC_SH_FLAGS) $(EXTRALIBS) +else +LINKFLAGS+=-lgpac +endif + + +#common obj +OBJS= main.o extract.o ifeq ($(CONFIG_DARWIN),yes) OBJS+= carbon_events.o LDFLAGS += -framework Carbon endif + SRCS := $(OBJS:.o=.c) all: $(PROG) MP4Client$(EXE): $(OBJS) - $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(LINKLIBS) + $(CC) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc $(LINKFLAGS) $(LDFLAGS) clean: rm -f $(OBJS) ../../bin/gcc/$(PROG) diff --git a/applications/mp4client/carbon_events.c b/applications/mp4client/carbon_events.c index d4226bb..a3ac7a4 100644 --- a/applications/mp4client/carbon_events.c +++ b/applications/mp4client/carbon_events.c @@ -74,7 +74,7 @@ static pascal OSErr ae_open_doc (const AppleEvent *ae_event, AppleEvent *ae_repl } } } - err = AEDisposeDesc(&docList); + AEDisposeDesc(&docList); if (main_evt_loop_run) { QuitApplicationEventLoop(); @@ -88,7 +88,7 @@ void carbon_init () my_argv[0] = "GPAC"; my_argv[1] = NULL; - open_app_UPP = NewAEEventHandlerUPP(ae_open_app); + open_app_UPP = NewAEEventHandlerUPP(ae_open_app); AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, open_app_UPP, 0L, false); open_doc_UPP = NewAEEventHandlerUPP(ae_open_doc); AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, open_doc_UPP, 0L, false); @@ -100,7 +100,7 @@ void carbon_init () void carbon_uninit() { - DisposeAEEventHandlerUPP(open_app_UPP); + DisposeAEEventHandlerUPP(open_app_UPP); DisposeAEEventHandlerUPP(open_doc_UPP); if (my_argv[1]) free(my_argv[1]); diff --git a/applications/mp4client/extract.c b/applications/mp4client/extract.c index 20970df..d9e7d6e 100644 --- a/applications/mp4client/extract.c +++ b/applications/mp4client/extract.c @@ -422,9 +422,9 @@ void dump_depth (GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 fra fprintf(stderr, "Error writing frame\n"); } else #endif - if (sha_out) { - write_hash(sha_out, conv_buf, fb.height*fb.width*3); - } + if (sha_out) { + write_hash(sha_out, conv_buf, fb.height*fb.width*3); + } /*in -depth -avi mode, do not release it yet*/ if (dump_mode_flags & DUMP_DEPTH_ONLY) return; @@ -582,11 +582,11 @@ void dump_frame(GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 fram if (avi_out) { if (AVI_write_frame(avi_out, conv_buf, out_size, 1) <0) fprintf(stderr, "Error writing frame\n"); - } else + } else #endif - if (sha_out) { - write_hash(sha_out, conv_buf, out_size); - } + if (sha_out) { + write_hash(sha_out, conv_buf, out_size); + } break; case DUMP_BMP: write_bmp(&fb, rad_name, frameNum); @@ -608,7 +608,7 @@ void dump_frame(GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 fram #ifndef GPAC_DISABLE_AVILIB -typedef struct +typedef struct { GF_AudioListener al; GF_Mutex *mx; @@ -616,14 +616,14 @@ typedef struct u32 time_scale; u64 max_dur, nb_bytes, audio_time; u32 next_video_time, audio_time_init, flush_retry, nb_write, audio_clock_at_video_init; - u32 samplerate, bits_per_sample, nb_channel; + u32 samplerate, bits_per_sample, nb_channel; } AVI_AudioListener; void avi_audio_frame(void *udta, char *buffer, u32 buffer_size, u32 time, u32 delay) { AVI_AudioListener *avil = (AVI_AudioListener *)udta; - if (avil->audio_clock_at_video_init > time) + if (avil->audio_clock_at_video_init > time) return; if (avil->audio_time >= avil->audio_time_init + avil->max_dur) @@ -631,12 +631,12 @@ void avi_audio_frame(void *udta, char *buffer, u32 buffer_size, u32 time, u32 de gf_mx_p(avil->mx); - if (!avil->time_scale) { - AVI_set_audio(avil->avi, avil->nb_channel, avil->samplerate, avil->bits_per_sample, WAVE_FORMAT_PCM, 0); - avil->time_scale = avil->nb_channel*avil->bits_per_sample*avil->samplerate/8; + if (!avil->time_scale) { + AVI_set_audio(avil->avi, avil->nb_channel, avil->samplerate, avil->bits_per_sample, WAVE_FORMAT_PCM, 0); + avil->time_scale = avil->nb_channel*avil->bits_per_sample*avil->samplerate/8; gf_term_set_option(term, GF_OPT_FORCE_AUDIO_CONFIG, 1); - } - + } + avil->nb_bytes+=buffer_size; avil->flush_retry=0; @@ -648,7 +648,7 @@ void avi_audio_frame(void *udta, char *buffer, u32 buffer_size, u32 time, u32 de avil->audio_time = 1000*avil->nb_bytes/avil->time_scale; - //we are behind video dump, force audio flush + //we are behind video dump, force audio flush if (avil->audio_time < avil->next_video_time) { gf_term_step_clocks(term, 0); } @@ -659,15 +659,16 @@ void avi_audio_reconfig(void *udta, u32 samplerate, u32 bits_per_sample, u32 nb_ { AVI_AudioListener *avil = (AVI_AudioListener *)udta; - avil->nb_channel = nb_channel; - avil->samplerate = samplerate; - avil->bits_per_sample = bits_per_sample; + avil->nb_channel = nb_channel; + avil->samplerate = samplerate; + avil->bits_per_sample = bits_per_sample; } #endif Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times) { GF_Err e; + Bool ret = 0; u32 i = 0; GF_VideoSurface fb; char szPath[GF_MAX_PATH]; @@ -693,7 +694,7 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi u32 cur_time_idx; u32 mode = dump_mode_flags & 0x0000FFFF; - if (!out_url) out_url = url; + if (!out_url) out_url = url; prev = strstr(url, "://"); if (prev) { prev = strrchr(url, '/'); @@ -702,29 +703,33 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi if (!prev) prev = url; strcpy(szPath, prev); - prev = strrchr(szPath, '.'); - if (prev) prev[0] = 0; + prev = gf_file_ext_start(szPath); + if (prev) *prev = 0; if (out_url) { strcpy(szOutPath, out_url); } else { strcpy(szOutPath, szPath); } - prev = strrchr(szOutPath, '.'); - if (prev) prev[0] = 0; + prev = gf_file_ext_start(szOutPath); + if (prev) *prev = 0; + gf_term_set_simulation_frame_rate(term, (Double) fps); fprintf(stderr, "Opening URL %s\n", url); - /*connect in pause mode*/ - gf_term_connect_from_time(term, url, 0, 1); + /*connect and pause */ + gf_term_connect_from_time(term, url, 0, 2); while (!term->compositor->scene || term->compositor->msg_type || (gf_term_get_option(term, GF_OPT_PLAY_STATE) == GF_STATE_STEP_PAUSE) ) { if (last_error) return 1; - gf_term_process_flush(term); - gf_sleep(10); + e = gf_term_process_flush(term); + if (e) { + fprintf(stderr, "Error initializing plalback: %s\n", gf_error_to_string(e)); + return 1; + } } if (width && height) { @@ -738,7 +743,7 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi #endif if (e != GF_OK) { fprintf(stderr, "Error grabbing screen buffer: %s\n", gf_error_to_string(e)); - return 0; + return 1; } width = fb.width; height = fb.height; @@ -781,7 +786,7 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi } #endif } - + if (mode==DUMP_SHA1) { strcat(szOutPath, ".sha1"); sha_out = gf_fopen(szOutPath, "wb"); @@ -837,7 +842,7 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi #ifndef GPAC_DISABLE_AVILIB comp[0] = comp[1] = comp[2] = comp[3] = comp[4] = 0; AVI_set_video(avi_out, width, height, fps, comp); - + if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { memset(&avi_al, 0, sizeof(avi_al)); avi_al.al.udta = &avi_al; @@ -850,14 +855,14 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi gf_sc_add_audio_listener(term->compositor, &avi_al.al); } - if (dump_mode_flags & DUMP_DEPTH_ONLY) + if (dump_mode_flags & DUMP_DEPTH_ONLY) AVI_set_video(depth_avi_out, width, height, fps, comp); #endif } if ((mode==DUMP_AVI) || (mode==DUMP_SHA1)) { - - if (dump_mode_flags & (DUMP_RGB_DEPTH | DUMP_RGB_DEPTH_SHAPE) ) + + if (dump_mode_flags & (DUMP_RGB_DEPTH | DUMP_RGB_DEPTH_SHAPE) ) conv_buf = gf_malloc(sizeof(char) * width * height * 4); else conv_buf = gf_malloc(sizeof(char) * width * height * 3); @@ -876,15 +881,29 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi avi_al.audio_clock_at_video_init = gf_term_get_clock(term); #endif + ret = 0; while (time < dump_dur) { + u32 frame_start_time = gf_sys_clock(); while ((gf_term_get_option(term, GF_OPT_PLAY_STATE) == GF_STATE_STEP_PAUSE)) { - gf_term_process_flush(term); + e = gf_term_process_flush(term); + if (e) { + ret = 1; + break; + } + //if we can't flush a frame in 30 seconds consider this is an error + if (gf_sys_clock() - frame_start_time > 30000) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[MP4Client] Could not flush frame in 30 seconds for AVI dump, aborting dump\n")); + ret = 1; + break; + } } + if (ret) + break; if ((mode==DUMP_AVI) || (mode==DUMP_SHA1)) { - if (!no_prog) - fprintf(stderr, "Dumping %02d/100 %% - time %.02f sec\r", (u32) ((100.0*prev_time)/dump_dur), prev_time/1000.0 ); + if (!no_prog) + fprintf(stderr, "Dumping %02d/100 %% - time %.02f sec\r", (u32) ((100.0*prev_time)/dump_dur), prev_time/1000.0 ); if (avi_mx) gf_mx_p(avi_mx); @@ -925,19 +944,22 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi if (gf_prompt_has_input() && (gf_prompt_get_char()=='q')) { fprintf(stderr, "Aborting dump\n"); - dump_dur=0; break; } } #ifndef GPAC_DISABLE_AVILIB //flush audio dump - if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { + if (!ret && (mode==DUMP_AVI) && ! (term->user->init_flags & GF_TERM_NO_AUDIO)) { avi_al.flush_retry=0; - while ((avi_al.flush_retry <100) && (avi_al.audio_time < dump_dur)) { + while ((avi_al.flush_retry <1000) && (avi_al.audio_time < avi_al.audio_time_init + avi_al.max_dur)) { gf_term_step_clocks(term, 0); - gf_sleep(1); avi_al.flush_retry++; + gf_sleep(1); + } + if (avi_al.audio_time < avi_al.audio_time_init + avi_al.max_dur) { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Failed to flush audio frames: audio time "LLU" - expected "LLU" - retry %d\n", avi_al.audio_time, avi_al.audio_time_init + avi_al.max_dur, avi_al.flush_retry)); + ret = 1; } } @@ -957,6 +979,6 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode_flags, Double fps, u32 wi fprintf(stderr, "Dumping done: %d frames at %g FPS\n", nb_frames, fps); } - return 0; + return ret; } diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c index 074ba52..397bf6c 100644 --- a/applications/mp4client/main.c +++ b/applications/mp4client/main.c @@ -28,10 +28,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include /*ISO 639 languages*/ @@ -178,7 +181,8 @@ void PrintUsage() fprintf(stderr, "Usage MP4Client [options] [filename]\n" "\t-c fileName: user-defined configuration file. Also works with -cfg\n" #ifdef GPAC_MEMORY_TRACKING - "\t-mem-track: enables memory tracker\n" + "\t-mem-track: enables memory tracker\n" + "\t-mem-track-stack: enables memory tracker with stack dumping\n" #endif "\t-rti fileName: logs run-time info (FPS, CPU, Mem usage) to file\n" "\t-rtix fileName: same as -rti but driven by GPAC logs\n" @@ -235,7 +239,7 @@ void PrintUsage() #else "\t-no-thread: disables thread usage (except for audio)\n" #endif - "\t-no-compositor-thread: disables compositor thread (iOS and Android mode)\n" + "\t-no-compositor-thread: disables compositor thread (iOS and Android mode)\n" "\t-no-audio: disables audio \n" "\t-no-wnd: uses windowless mode (Win32 only)\n" "\t-no-back: uses transparent background for output window when no background is specified (Win32 only)\n" @@ -260,17 +264,18 @@ void PrintUsage() "\t-exit: automatically exits when presentation is over\n" "\t-run-for TIME: runs for TIME seconds and exits\n" "\t-service ID: auto-tune to given service ID in a multiplex\n" - "\t-noprog: disable progress report\n" - "\t-no-save: disable saving config file on exit\n" + "\t-noprog: disable progress report\n" + "\t-no-save: disable saving config file on exit\n" "\t-no-addon: disable automatic loading of media addons declared in source URL\n" "\t-gui: starts in GUI mode. The GUI is indicated in GPAC config, section General, by the key [StartupFile]\n" + "\t-ntp-shift T: shifts NTP clock of T (signed int) milliseconds\n" "\n" "Dumper Options (times is a formated as start-end, with start being sec, h:m:s:f/fps or h:m:s:ms):\n" "\t-bmp [times]: dumps given frames to bmp\n" "\t-png [times]: dumps given frames to png\n" "\t-raw [times]: dumps given frames to raw\n" "\t-avi [times]: dumps given file to raw avi\n" - "\t-sha [times]: dumps given file to raw SHA-1 (1 hash per frame)\n" + "\t-sha [times]: dumps given file to raw SHA-1 (1 hash per frame)\n" "\r-out filename: name of the output file\n" "\t-rgbds: dumps the RGBDS pixel format texture\n" "\t with -avi [times]: dumps an rgbds-format .avi\n" @@ -285,6 +290,8 @@ void PrintUsage() "\t-fill: uses fill aspect ratio for dumping (default: none)\n" "\t-show: shows window while dumping (default: no)\n" "\n" + "\t-uncache: Revert all cached items to their original name and location. Does not start player.\n" + "\n" "\t-help: shows this screen\n" "\n" "MP4Client - GPAC command line player and dumper - version "GPAC_FULL_VERSION"\n" @@ -724,7 +731,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); break; case GF_KEY_O: - if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) { if (gf_term_get_option(term, GF_OPT_MAIN_ADDON)) { fprintf(stderr, "Resuming to main content\n"); gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_PLAY_LIVE); @@ -734,13 +741,13 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) } break; case GF_KEY_P: - if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { - u32 is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE) ; - fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused"); - if ((is_pause == GF_STATE_PAUSED) && (evt->key.flags & GF_KEY_MOD_SHIFT)) { + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) { + u32 pause_state = gf_term_get_option(term, GF_OPT_PLAY_STATE) ; + fprintf(stderr, "[Status: %s]\n", pause_state ? "Playing" : "Paused"); + if ((pause_state == GF_STATE_PAUSED) && (evt->key.flags & GF_KEY_MOD_SHIFT)) { gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_PLAY_LIVE); } else { - gf_term_set_option(term, GF_OPT_PLAY_STATE, (gf_term_get_option(term, GF_OPT_PLAY_STATE)==GF_STATE_PAUSED) ? GF_STATE_PLAYING : GF_STATE_PAUSED); + gf_term_set_option(term, GF_OPT_PLAY_STATE, (pause_state==GF_STATE_PAUSED) ? GF_STATE_PLAYING : GF_STATE_PAUSED); } } break; @@ -761,12 +768,16 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) ViewODs(term, 0); break; case GF_KEY_H: - if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) { gf_term_switch_quality(term, 1); + // gf_term_set_option(term, GF_OPT_MULTIVIEW_MODE, 0); + } break; case GF_KEY_L: - if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) + if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) { gf_term_switch_quality(term, 0); + // gf_term_set_option(term, GF_OPT_MULTIVIEW_MODE, 1); + } break; case GF_KEY_F5: if (is_connected) @@ -777,17 +788,17 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) gf_term_toggle_addons(term, addon_visible); break; case GF_KEY_UP: - if (evt->key.flags & VK_MOD && is_connected) { + if ((evt->key.flags & VK_MOD) && is_connected) { do_set_speed(playback_speed * 2); } break; case GF_KEY_DOWN: - if (evt->key.flags & VK_MOD && is_connected) { + if ((evt->key.flags & VK_MOD) && is_connected) { do_set_speed(playback_speed / 2); } break; case GF_KEY_LEFT: - if (evt->key.flags & VK_MOD && is_connected) { + if ((evt->key.flags & VK_MOD) && is_connected) { do_set_speed(-1 * playback_speed ); } break; @@ -841,6 +852,10 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) ResetCaption(); break; + case GF_EVENT_RELOAD: + if (is_connected) + reload = 1; + break; case GF_EVENT_DROPFILE: { u32 i, pos; @@ -852,7 +867,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) readonly_playlist = 0; if (!playlist) { readonly_playlist = 0; - playlist = gf_temp_file_new(); + playlist = gf_temp_file_new(NULL); } pos = ftell(playlist); i=0; @@ -997,7 +1012,7 @@ static Bool get_time_list(char *arg, u32 *times, u32 *nb_times) str = strchr(arg, '-'); if (str) str[0] = 0; /*HH:MM:SS:MS time code*/ - if (strchr(arg, ':') && (sscanf(arg, "%02ud:%02ud:%02ud:%02ud", &h, &m, &s, &ms)==4)) { + if (strchr(arg, ':') && (sscanf(arg, "%u:%u:%u:%u", &h, &m, &s, &ms)==4)) { sec = ms; sec /= 1000; sec += 3600*h + 60*m + s; @@ -1016,9 +1031,9 @@ static Bool get_time_list(char *arg, u32 *times, u32 *nb_times) } static u64 last_log_time=0; -static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) +static void on_gpac_log(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *fmt, va_list list) { - FILE *logs = cbk; + FILE *logs = cbk ? cbk : stderr; if (rti_logs && (lm & GF_LOG_RTI)) { char szMsg[2048]; @@ -1072,20 +1087,24 @@ void set_cfg_option(char *opt_string) fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string); return; } - sep[0] = 0; - strcpy(szSec, opt_string); - sep[0] = ':'; + { + const size_t sepIdx = sep - opt_string; + strncpy(szSec, opt_string, sepIdx); + szSec[sepIdx] = 0; + } sep ++; sep2 = strchr(sep, '='); if (!sep2) { fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string); return; } - sep2[0] = 0; - strcpy(szKey, sep); - strcpy(szVal, sep2+1); - sep2[0] = '='; - + { + const size_t sepIdx = sep2 - sep; + strncpy(szKey, sep, sepIdx); + szKey[sepIdx] = 0; + strcpy(szVal, sep2+1); + } + if (!stricmp(szKey, "*")) { if (stricmp(szVal, "null")) { fprintf(stderr, "Badly formatted option %s - expected Section:*=null\n", opt_string); @@ -1094,23 +1113,78 @@ void set_cfg_option(char *opt_string) gf_cfg_del_section(cfg_file, szSec); return; } - + if (!stricmp(szVal, "null")) { szVal[0]=0; } gf_cfg_set_key(cfg_file, szSec, szKey, szVal[0] ? szVal : NULL); } +Bool revert_cache_file(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) +{ + const char *url; + char *sep; + GF_Config *cached; + if (strncmp(item_name, "gpac_cache_", 11)) return GF_FALSE; + cached = gf_cfg_new(NULL, item_path); + url = gf_cfg_get_key(cached, "cache", "url"); + if (url) url = strstr(url, "://"); + if (url) { + u32 i, len, dir_len=0, k=0; + char *dst_name; + sep = strstr(item_path, "gpac_cache_"); + if (sep) { + sep[0] = 0; + dir_len = (u32) strlen(item_path); + sep[0] = 'g'; + } + url+=3; + len = (u32) strlen(url); + dst_name = gf_malloc(len+dir_len+1); + memset(dst_name, 0, len+dir_len+1); + + strncpy(dst_name, item_path, dir_len); + k=dir_len; + for (i=0; i #endif static void progress_quiet(const void *cbck, const char *title, u64 done, u64 total) { } -int main (int argc, char **argv) +int mp4client_main(int argc, char **argv) { char c; const char *str; + int ret_val = 0; u32 i, times[100], nb_times, dump_mode; u32 simulation_time_in_ms = 0; u32 initial_service_id = 0; @@ -1124,10 +1198,10 @@ int main (int argc, char **argv) Double play_from = 0; #ifdef GPAC_MEMORY_TRACKING - Bool enable_mem_tracker = GF_FALSE; + GF_MemTrackerType mem_track = GF_MemTrackerNone; #endif Double fps = GF_IMPORT_DEFAULT_FPS; - Bool fill_ar, visible; + Bool fill_ar, visible, do_uncache; char *url_arg, *out_arg, *the_cfg, *rti_file, *views, *default_com; FILE *logfile = NULL; Float scale = 1; @@ -1141,7 +1215,7 @@ int main (int argc, char **argv) memset(&user, 0, sizeof(GF_User)); dump_mode = DUMP_NONE; - fill_ar = visible = GF_FALSE; + fill_ar = visible = do_uncache = GF_FALSE; url_arg = out_arg = the_cfg = rti_file = views = default_com = NULL; nb_times = 0; times[0] = 0; @@ -1153,11 +1227,11 @@ int main (int argc, char **argv) the_cfg = argv[i+1]; i++; } - else if (!strcmp(arg, "-mem-track")) { + else if (!strcmp(arg, "-mem-track") || !strcmp(arg, "-mem-track-stack")) { #ifdef GPAC_MEMORY_TRACKING - enable_mem_tracker = GF_TRUE; + mem_track = !strcmp(arg, "-mem-track-stack") ? GF_MemTrackerBackTrace : GF_MemTrackerSimple; #else - fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"); + fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"%s\"\n", arg); #endif } else if (!strcmp(arg, "-gui")) { gui_mode = 1; @@ -1165,14 +1239,14 @@ int main (int argc, char **argv) gui_mode = 2; } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) { PrintUsage(); - return 1; + return 0; } } #ifdef GPAC_MEMORY_TRACKING - gf_sys_init(enable_mem_tracker); + gf_sys_init(mem_track); #else - gf_sys_init(GF_FALSE); + gf_sys_init(GF_MemTrackerNone); #endif gf_sys_set_args(argc, (const char **) argv); @@ -1252,59 +1326,80 @@ int main (int argc, char **argv) gf_cfg_set_key(cfg_file, "Network", "DefaultMCastInterface", argv[i+1]); i++; } - else if (!stricmp(arg, "-help")) { - PrintUsage(); - return 1; - } - else if (!stricmp(arg, "-noprog")) { - no_prog=1; - gf_set_progress_callback(NULL, progress_quiet); - } - else if (!stricmp(arg, "--no-save")) { + else if (!stricmp(arg, "-help")) { + PrintUsage(); + return 1; + } + else if (!stricmp(arg, "-noprog")) { + no_prog=1; + gf_set_progress_callback(NULL, progress_quiet); + } + else if (!stricmp(arg, "-no-save") || !stricmp(arg, "--no-save") /*old versions used --n-save ...*/) { no_cfg_save=1; - } - + } + else if (!stricmp(arg, "-ntp-shift")) { + s32 shift = atoi(argv[i+1]); + i++; + gf_net_set_ntp_shift(shift); + } + else if (!stricmp(arg, "-run-for")) { + simulation_time_in_ms = atoi(argv[i+1]) * 1000; + if (!simulation_time_in_ms) + simulation_time_in_ms = 1; /*1ms*/ + i++; + } - /*arguments only used in non-gui mode*/ - else if (!gui_mode) { - if (arg[0] != '-') { - url_arg = arg; - } - else if (!strcmp(arg, "-out")) { - out_arg = argv[i+1]; - i++; - } - else if (!stricmp(arg, "-fps")) { - fps = atof(argv[i+1]); - i++; - } else if (!strcmp(arg, "-avi") || !strcmp(arg, "-sha")) { - dump_mode &= 0xFFFF0000; + else if (!strcmp(arg, "-out")) { + out_arg = argv[i+1]; + i++; + } + else if (!stricmp(arg, "-fps")) { + fps = atof(argv[i+1]); + i++; + } else if (!strcmp(arg, "-avi") || !strcmp(arg, "-sha")) { + dump_mode &= 0xFFFF0000; - if (!strcmp(arg, "-sha")) dump_mode |= DUMP_SHA1; - else dump_mode |= DUMP_AVI; + if (!strcmp(arg, "-sha")) dump_mode |= DUMP_SHA1; + else dump_mode |= DUMP_AVI; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!strcmp(arg, "-rgbds")) { /*get dump in rgbds pixel format*/ + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) { + if (!strcmp(arg, "-avi") && (nb_times!=2) ) { + fprintf(stderr, "Only one time arg found for -avi - check usage\n"); + return 1; + } + i++; + } + } else if (!strcmp(arg, "-rgbds")) { /*get dump in rgbds pixel format*/ dump_mode |= DUMP_RGB_DEPTH_SHAPE; - } else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/ + } else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/ dump_mode |= DUMP_RGB_DEPTH; - } else if (!strcmp(arg, "-depth")) { + } else if (!strcmp(arg, "-depth")) { dump_mode |= DUMP_DEPTH_ONLY; - } else if (!strcmp(arg, "-bmp")) { - dump_mode &= 0xFFFF0000; - dump_mode |= DUMP_BMP; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!strcmp(arg, "-png")) { - dump_mode &= 0xFFFF0000; - dump_mode |= DUMP_PNG; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!strcmp(arg, "-raw")) { - dump_mode &= 0xFFFF0000; - dump_mode |= DUMP_RAW; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!stricmp(arg, "-scale")) { - sscanf(argv[i+1], "%f", &scale); - i++; + } else if (!strcmp(arg, "-bmp")) { + dump_mode &= 0xFFFF0000; + dump_mode |= DUMP_BMP; + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!strcmp(arg, "-png")) { + dump_mode &= 0xFFFF0000; + dump_mode |= DUMP_PNG; + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!strcmp(arg, "-raw")) { + dump_mode &= 0xFFFF0000; + dump_mode |= DUMP_RAW; + if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; + } else if (!stricmp(arg, "-scale")) { + sscanf(argv[i+1], "%f", &scale); + i++; + } + + /*arguments only used in non-gui mode*/ + if (!gui_mode) { + if (arg[0] != '-') { + if (url_arg) { + fprintf(stderr, "Several input URLs provided (\"%s\", \"%s\"). Check your command-line.\n", url_arg, arg); + return 1; + } + url_arg = arg; } else if (!strcmp(arg, "-loop")) loop_at_end = 1; else if (!strcmp(arg, "-bench")) bench_mode = 1; @@ -1315,10 +1410,12 @@ int main (int argc, char **argv) else if (!strcmp(arg, "-pause")) pause_at_first = 1; else if (!strcmp(arg, "-play-from")) { play_from = atof((const char *) argv[i+1]); + i++; } else if (!strcmp(arg, "-speed")) { playback_speed = FLT2FIX( atof((const char *) argv[i+1]) ); if (playback_speed <= 0) playback_speed = FIX_ONE; + i++; } else if (!strcmp(arg, "-no-wnd")) user.init_flags |= GF_TERM_WINDOWLESS; else if (!strcmp(arg, "-no-back")) user.init_flags |= GF_TERM_WINDOW_TRANSPARENT; @@ -1333,18 +1430,14 @@ int main (int argc, char **argv) fill_ar = GF_TRUE; } else if (!strcmp(arg, "-show")) { visible = 1; + } else if (!strcmp(arg, "-uncache")) { + do_uncache = GF_TRUE; } else if (!strcmp(arg, "-exit")) auto_exit = GF_TRUE; else if (!stricmp(arg, "-views")) { views = argv[i+1]; i++; } - else if (!stricmp(arg, "-run-for")) { - simulation_time_in_ms = atoi(argv[i+1]) * 1000; - if (!simulation_time_in_ms) - simulation_time_in_ms = 1; /*1ms*/ - i++; - } else if (!stricmp(arg, "-com")) { default_com = argv[i+1]; i++; @@ -1352,23 +1445,35 @@ int main (int argc, char **argv) else if (!stricmp(arg, "-service")) { initial_service_id = atoi(argv[i+1]); i++; - } else if (!strcmp(arg, "-mem-track")) { - - } else { - fprintf(stderr, "Unrecognized option %s - skipping\n", arg); } } } - if (is_cfg_only) { - gf_cfg_del(cfg_file); - fprintf(stderr, "GPAC Config updated\n"); - return 0; - } + if (is_cfg_only) { + gf_cfg_del(cfg_file); + fprintf(stderr, "GPAC Config updated\n"); + return 0; + } + if (do_uncache) { + const char *cache_dir = gf_cfg_get_key(cfg_file, "General", "CacheDirectory"); + do_flatten_cache(cache_dir); + fprintf(stderr, "GPAC Cache dir %s flattened\n", cache_dir); + gf_cfg_del(cfg_file); + return 0; + } + if (dump_mode && !url_arg ) { - fprintf(stderr, "Missing argument for dump\n"); - PrintUsage(); - if (logfile) gf_fclose(logfile); - return 1; + FILE *test; + url_arg = (char *)gf_cfg_get_key(cfg_file, "General", "StartupFile"); + test = url_arg ? gf_fopen(url_arg, "rt") : NULL; + if (!test) url_arg = NULL; + else gf_fclose(test); + + if (!url_arg) { + fprintf(stderr, "Missing argument for dump\n"); + PrintUsage(); + if (logfile) gf_fclose(logfile); + return 1; + } } if (!gui_mode && !url_arg && (gf_cfg_get_key(cfg_file, "General", "StartupFile") != NULL)) { @@ -1393,20 +1498,27 @@ int main (int argc, char **argv) if (gui_mode==1) { hide_shell(1); } + if (gui_mode) { + no_prog=1; + gf_set_progress_callback(NULL, progress_quiet); + } if (!url_arg && simulation_time_in_ms) simulation_time_in_ms += gf_sys_clock(); #if defined(__DARWIN__) || defined(__APPLE__) - carbon_init(); + carbon_init(); #endif - + if (dump_mode) rti_file = NULL; if (!logs_set) { - //gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_ERROR); + gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); } + //only override default log callback when needed + if (rti_file || logfile || log_utc_time || log_time_start) + gf_log_set_callback(NULL, on_gpac_log); if (rti_file) init_rti_logs(rti_file, url_arg, use_rtix); @@ -1419,8 +1531,10 @@ int main (int argc, char **argv) /*setup dumping options*/ if (dump_mode) { - user.init_flags |= GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_REGULATION /*| GF_TERM_INIT_HIDE*/; - if (visible || dump_mode==8) user.init_flags |= GF_TERM_INIT_HIDE; + user.init_flags |= GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_REGULATION; + if (!visible) + user.init_flags |= GF_TERM_INIT_HIDE; + gf_cfg_set_key(cfg_file, "Audio", "DriverName", "Raw Audio Output"); no_cfg_save=GF_TRUE; } else { @@ -1448,7 +1562,7 @@ int main (int argc, char **argv) if (no_audio) user.init_flags |= GF_TERM_NO_AUDIO; if (no_regulation) user.init_flags |= GF_TERM_NO_REGULATION; - if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = 1; + if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = GF_TRUE; //in dump mode we don't want to rely on system clock but on the number of samples being consumed if (dump_mode) user.init_flags |= GF_TERM_USE_AUDIO_HW_CLOCK; @@ -1466,6 +1580,14 @@ int main (int argc, char **argv) } } + { + char dim[50]; + sprintf(dim, "%d", forced_width); + gf_cfg_set_key(user.config, "Compositor", "DefaultWidth", forced_width ? dim : NULL); + sprintf(dim, "%d", forced_height); + gf_cfg_set_key(user.config, "Compositor", "DefaultHeight", forced_height ? dim : NULL); + } + fprintf(stderr, "Loading GPAC Terminal\n"); i = gf_sys_clock(); term = gf_term_new(&user); @@ -1525,7 +1647,7 @@ int main (int argc, char **argv) times[0] = 0; nb_times++; } - dump_file(url_arg, out_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times); + ret_val = dump_file(url_arg, out_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times); Run = 0; } else if (views) { @@ -1554,12 +1676,7 @@ int main (int argc, char **argv) playlist = e ? NULL : gf_fopen(the_url, "rt"); readonly_playlist = 1; if (playlist) { - if (1 > fscanf(playlist, "%s", the_url)) - fprintf(stderr, "Cannot read any URL from playlist\n"); - else { - fprintf(stderr, "Opening URL %s\n", the_url); - gf_term_connect_with_path(term, the_url, pl_path); - } + request_next_playlist_item = GF_TRUE; } else { if (e) fprintf(stderr, "Failed to open playlist %s: %s\n", the_url, gf_error_to_string(e) ); @@ -1638,7 +1755,7 @@ int main (int argc, char **argv) /*sim time*/ if (simulation_time_in_ms - && ( (gf_term_get_time_in_ms(term)>simulation_time_in_ms) || (!url_arg && gf_sys_clock()>simulation_time_in_ms)) + && ( (gf_term_get_elapsed_time_in_ms(term)>simulation_time_in_ms) || (!url_arg && gf_sys_clock()>simulation_time_in_ms)) ) { Run = GF_FALSE; } @@ -1649,14 +1766,14 @@ int main (int argc, char **argv) force_input: switch (c) { case 'q': - { - GF_Event evt; - memset(&evt, 0, sizeof(GF_Event)); - evt.type = GF_EVENT_QUIT; - gf_term_send_event(term, &evt); - } + { + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_QUIT; + gf_term_send_event(term, &evt); + } // Run = 0; - break; + break; case 'X': exit(0); break; @@ -1705,6 +1822,8 @@ force_input: if (res == EOF) { fprintf(stderr, "No more items - exiting\n"); Run = 0; + } else if (the_url[0] == '#') { + request_next_playlist_item = GF_TRUE; } else { fprintf(stderr, "Opening URL %s\n", the_url); gf_term_connect_with_path(term, the_url, pl_path); @@ -2214,15 +2333,49 @@ force_input: } #ifdef GPAC_MEMORY_TRACKING - if (enable_mem_tracker && (gf_memory_size() || gf_file_handles_count() )) { - gf_memory_print(); + if (mem_track && (gf_memory_size() || gf_file_handles_count() )) { + gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); + gf_memory_print(); return 2; } #endif - return 0; + return ret_val; } +#if defined(WIN32) && !defined(NO_WMAIN) +int wmain(int argc, wchar_t** wargv) +{ + int i; + int res; + size_t len; + size_t 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; + if (res_len > len) { + fprintf(stderr, "Length allocated for conversion of wide char to UTF-8 not sufficient\n"); + return -1; + } + } + res = mp4client_main(argc, argv); + for (i = 0; i < argc; i++) { + free(argv[i]); + } + free(argv); + return res; +} +#else +int main(int argc, char** argv) +{ + return mp4client_main(argc, argv); +} +#endif //win32 static GF_ObjectManager *video_odm = NULL; static GF_ObjectManager *audio_odm = NULL; static GF_ObjectManager *scene_odm = NULL; @@ -2258,7 +2411,7 @@ void PrintAVInfo(Bool final) GF_ObjectManager *odm = gf_term_get_object(term, root_odm, i); if (!odm) break; if (gf_term_get_object_info(term, odm, &v_odi) == GF_OK) { - if (!video_odm && (v_odi.od_type == GF_STREAM_VISUAL) && (v_odi.raw_media || (v_odi.cb_max_count>1) || v_odi.direct_video_memory) ) { + if (!video_odm && (v_odi.od_type == GF_STREAM_VISUAL) && (v_odi.raw_media || (v_odi.cb_max_count>1) || v_odi.direct_video_memory || (bench_mode == 3) )) { video_odm = odm; } else if (!audio_odm && (v_odi.od_type == GF_STREAM_AUDIO)) { @@ -2281,17 +2434,18 @@ void PrintAVInfo(Bool final) video_odm = NULL; return; } - avg_dec_time = 0; - if (v_odi.nb_dec_frames && v_odi.total_dec_time) { - avg_dec_time = (Float) 1000000 * v_odi.nb_dec_frames; - avg_dec_time /= v_odi.total_dec_time; - } + } else { + memset(&v_odi, 0, sizeof(v_odi)); } if (print_codecs && audio_odm) { gf_term_get_object_info(term, audio_odm, &a_odi); + } else { + memset(&a_odi, 0, sizeof(a_odi)); } if ((print_codecs || !video_odm) && scene_odm) { gf_term_get_object_info(term, scene_odm, &s_odi); + } else { + memset(&s_odi, 0, sizeof(s_odi)); } if (final) { @@ -2336,7 +2490,7 @@ void PrintAVInfo(Bool final) if (scene_odm) { u32 w, h; gf_term_get_visual_output_size(term, &w, &h); - fprintf(stderr, "%s scene size %dx%d rastered to %dx%d duration %.2fs\n", s_odi.codec_name, s_odi.width, s_odi.height, w, h, s_odi.duration); + fprintf(stderr, "%s scene size %dx%d rastered to %dx%d duration %.2fs\n", s_odi.codec_name ? s_odi.codec_name : "", s_odi.width, s_odi.height, w, h, s_odi.duration); if (final) { if (s_odi.nb_dec_frames>2 && s_odi.total_dec_time) { u32 dec_run_time = s_odi.last_frame_time - s_odi.first_frame_time; @@ -2345,7 +2499,8 @@ void PrintAVInfo(Bool final) fprintf(stderr, "\n"); } else { u32 nb_frames_drawn; - Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); + Double FPS; + gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); tot_time = gf_sys_clock() - bench_mode_start; FPS = gf_term_get_framerate(term, 0); fprintf(stderr, "%d frames FPS %.2f (abs %.2f)\n", nb_frames_drawn, (1000.0*nb_frames_drawn / tot_time), FPS); @@ -2366,7 +2521,6 @@ void PrintAVInfo(Bool final) } else if (scene_odm) { - avg_dec_time = 0; if (s_odi.nb_dec_frames>2 && s_odi.total_dec_time) { avg_dec_time = (Float) 1000000 * s_odi.nb_dec_frames; avg_dec_time /= s_odi.total_dec_time; @@ -2374,7 +2528,8 @@ void PrintAVInfo(Bool final) fprintf(stderr, "%d f %.2f (%d us max) - rate %d ", s_odi.nb_dec_frames, avg_dec_time, s_odi.max_dec_time, (u32) s_odi.instant_bitrate/1000); } else { u32 nb_frames_drawn; - Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); + Double FPS; + gf_term_get_simulation_frame_rate(term, &nb_frames_drawn); tot_time = gf_sys_clock() - bench_mode_start; FPS = gf_term_get_framerate(term, 1); fprintf(stderr, "%d f FPS %.2f (abs %.2f) ", nb_frames_drawn, (1000.0*nb_frames_drawn / tot_time), FPS); diff --git a/applications/osmo4_android_studio/.gitignore b/applications/osmo4_android_studio/.gitignore new file mode 100644 index 0000000..769114f --- /dev/null +++ b/applications/osmo4_android_studio/.gitignore @@ -0,0 +1,41 @@ +### Mac BS ### +.DS_Store + +### Android ### +# Built application files +*.apk +*.ap_ +captures/ + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ +build/ +!build/jar/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +#Log Files +*.log + + +## Intellij settings +.idea/ +*.iml + +## jimu mirror +app/mirror/ +.gradle diff --git a/applications/osmo4_android_studio/Readme.md b/applications/osmo4_android_studio/Readme.md new file mode 100644 index 0000000..5b68436 --- /dev/null +++ b/applications/osmo4_android_studio/Readme.md @@ -0,0 +1,11 @@ +# To compile this "to be improved" project + +Compile libgpac and its dependencies using the scripts provided in build/android + +Copy the content of applications/osmo4_android/libs into app/src/main/jniLibs + +# A problem occurred starting process 'null/ndk-build' + +Add this into your local.properties file + +ndk.dir=/path/to/Android/sdk/ndk-bundle \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/build.gradle b/applications/osmo4_android_studio/app/build.gradle new file mode 100644 index 0000000..dcbf0f9 --- /dev/null +++ b/applications/osmo4_android_studio/app/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.application' +import org.apache.tools.ant.taskdefs.condition.Os + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "com.gpac.Osmo4" + minSdkVersion 16 + targetSdkVersion 22 + } + + sourceSets.main { + jni.srcDirs = [] // This prevents the auto generation of Android.mk + jniLibs.srcDir 'src/main/libs' // This is not necessary unless you have precompiled libraries in your project. + } + + + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile files('libs/real3d.jar') + compile 'com.android.support:recyclerview-v7:23.1.1' + compile 'com.android.support:cardview-v7:23.1.1' + compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:design:23.1.1' + +} diff --git a/applications/osmo4_android_studio/app/libs/real3d.jar b/applications/osmo4_android_studio/app/libs/real3d.jar new file mode 100644 index 0000000000000000000000000000000000000000..bd268d3899e88fd181767313b58d8aabba76ab36 GIT binary patch literal 3786 zcmbVPOK%%h6h1R{-cI5q&cjX8v`q_+Y2rXAue1fn9yi8MY&WHqkeNDDcPhtI*^|(S z1#D0^{1Su^1yLjk=&_4_!OfGG5k9i+j^B6WTtO zB)H=e4d#vAT1kuP%rfCH6mJU_f-Ed0(J|_wUbKBcGF&U;8SBN}gPsstn4fxrKhp3$ zAu@_PPap_*#a#%{7>xt@X@Y!>$)|-Bk$a3DeT^}h+H^y`|45RTC!RKc}XyvE&H5qzJpouA&Ep-2Y58 z-kcInu0@N5t68O(&ZHF%P4+F!J7OQp=fx}T=q+q;FK0))Y$TJsoJtqt>4K6=h9gQ; z1PjuGT_~5i;*dZFowG}1;~y$XhfI$|Gj^HCrV>dgxs6OXCs=wNEU{cTr4;kZ2bYy} zMB#Px;gxA<$mF6*u9(a@dvZw@^m4khtkV!IX41*4Jaoc2lxq#Gwl}dASFWToQKhj3 zCA<|+qZl-;&>GIiqsqorzPC5m8cZs&0@K>k#6lpcR<~=0z8%`rwNFC%-P#Scq-`1% zq?7fIda>l8GZbu=kr%5P)7?`A(u7>UiCrGH2voOvv!Za`kmz`zyE>71mN+r$LhkSc zHQcIGme%>e(jjUkn#L+nX7{vOS*w<`s9wK~3Tf_xE)Zi&4IooDyQCN2qyAmyD{ZRm~8VW@>lLbv9U^=)8kNhQH+sryL3f7MxP==sUYR zS);C-`X1ITI&s24XId+(R%b`fAF^`(N=JeBK3CxVjq+|4d=IknuqgKy9swS;VK4BQ z4UYp)*su?H(uSvir)_u!*l)wffM#u&`R8nS9{9KoF94sg;gi6pY?$XS+Ay#Gv<-X3 z^BH;x$?;{RfeUE41n_|-U=^}g00%{90kz{Yoduq zD%oWnZdi|XF#6c0LvHDiX^mbNI?fT#<>j0enA7pMKr*#;RD=$zh&FXd^d`O4n0Zdf zBj>j_VUd4oBbQp_61`3D2(ooL?<61k#zFo?SMm#V@hI}I4j_M5xIv=#DC{JE&U*K| zl5ZTn^Is1jkBFTQP?VG-$sc!+$LJC)Bhlv39`}6n}_yUI%@av6ex^Jzw3vw%S@$Ja#?TAhX%Ny_^c22l%$aB3{6*3b{a7=PIW% e=aH`!dCtFoq|9zN{CEN)uHf%NV$qyGRu + + + + + + + + + + + + + + + + + + + + + + + android:theme="@android:style/Theme.AppCompat"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/osmo4_android_studio/app/src/main/assets/configuration.xml b/applications/osmo4_android_studio/app/src/main/assets/configuration.xml new file mode 100755 index 0000000..d796bf9 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/assets/configuration.xml @@ -0,0 +1,171 @@ + + +
+ + Specifies the path to modules directory. The MPEG-4 Systems engine cannot be loaded without modules. This option is used by GPAC clients on all platforms. + + + Specifies location of temp files. The user must have write access to this location. Although not used by applications, this is used by several modules. + + + Specifies file to load upon startup of most clients (Osmo4/MP4Client). If not specified, no file is loaded. + + + Specifies where to output GPAC's log. By default, the logs are written to stdout. Note that GPAC may be compiled without log support. This is not used by MP4Client. + + + Specifies log level for each tool, with the following syntax:

+ tool[:tool]@level:tool[:tool]@level

+ By default, only errors are logged.

+ Available levels are: +
    +
  • quiet : no logging is performed on the tool
  • +
  • error : only errors are logged
  • +
  • warning : warnings are also logged.
  • +
  • info : information messages are also logged
  • +
  • debug : debug messages are also logged
  • +
+ Available tools are: +
    +
  • core : libgpac core
  • +
  • coding : bitstream formats (audio, video, scene)
  • +
  • container : container formats (ISO File, MPEG-2 TS, AVI, ...)
  • +
  • network : network data exept RTP trafic
  • +
  • rtp : rtp, rtcp and rtsp trafic
  • +
  • author : authoring tools (hint, import, export)
  • +
  • sync : terminal sync layer
  • +
  • codec : terminal codec messages
  • +
  • parser : scene parsers (svg, xmt, bt) and other
  • +
  • media : terminal media object management
  • +
  • scene : scene graph and scene manager
  • +
  • script : scripting engine messages
  • +
  • interact : user interaction messages
  • +
  • compose : composition engine (events, etc)
  • +
  • cache : HTTP cache
  • +
  • mmio : Audio/Video HW I/O management
  • +
  • rti : Run-time info (CPU, mem, ...)
  • +
  • smil : SMIL timing and animation
  • +
  • memory : GPAC memory tracker
  • +
  • audio : Audio renderer and mixers
  • +
  • module : used by some modules
  • +
  • mutex : mutex information
  • +
  • console : console messages, such as script alert() and error notifications
  • +
+
+ + Specifies whether the presentation has to be restarted when done playing. + + + Specifies whether application messages (script, buffering, download progress) are displayed in the console or not. + + + Specifies if the player should be a single instance application or not (Osmo4-Win32 only). + + + Specifies if Osmo4 shall look for subtitle files when opening a presentation. + + + Specifies if scene dumping shall be done in XML (XMT, X3D) or in VRML-like syntax (BT, WRL). + + + Specifies the latest config panel selected by user. + + + Specifies if the player has to check for mime type when following hyperlinks, or only follow links of known extensions. + + + Indicates active playlist entry when player was last closed. Playlist backup is: +
    +
  • "gpac_pl.m3u" on win32 platforms, stored in same directory as application
  • +
  • ".gpac_pl.m3u" on other platforms, stored in user home directory
  • +
+
+ + Specifies if the display area shall fill all available space on screen. WindowsMobile/Symbian only + + + Specifies if the screen backlighting shall be disabled while playing. WindowsMobile/Symbian only + + + Specifies the directory of the last local file opened. Smartphone Windows only + + + Specifies prefered browser for WWW anchors and scene graph viewing - Only used by Osmo4/wxWidgets. + +
+
+ The "RecentFiles" section of the config file holds last accessed files (hardcoded to no more than 20) in the last access order. The keys are the file names and no value is used. This section is only used by GUI clients (osmo4/wxOsmo4) +
+
+ + Specifies the user prefered language in readable english. This is used to select streams in case of alternate content in an audio object. + + + Specifies the user prefered language as expressed in ISO 639-2. This is used to select streams in case of alternate content in an audio object. + + + Specifies the user prefered language as expressed in ISO 639-1. This is used to select streams in case of alternate content in an audio object. + + + If set, late frames will still be drawn. If not set, the late frames are droped (or executed for systems decoders) untill the decoder output is back in sync. This is by default on to keep better testing heavy content or slow renderers, but should be set to off when needing a better sync or monitoring skipped frames. + + + One big problem with MP4 files is that the notion of "duration" has been unclear for a long time, and most content available (audio-video files) specifiy a wrong BIFS duration. In such a case the movie cannot be controled/seeked into. Another problem with ISMA streaming is that BIFS/OD don't use the same clock as audio/video, thus seeking the main timeline does not seek AV media. Setting the ForceSingleClock will handle both cases by using a single timeline for all media streams and setting the duration to the one of the longest stream + + + Specifies how media decoders are to be threaded. "Free" lets decoders decide of their threading, "Single" means that all decoders are managed in a single thread performing scheduling and priority handling and "Multi" means that each decoder runs in its own thread. + + + Specifies the priority of the decoders (priority is applied to decoder thread(s) regardless of threading mode). + + + Specifies the target maximum time (in ms) of one cycle of the media manager (the media manager will attempts to call all the active decoders within this time. Depending on the threading mode this option can be ignored. + + + Specifies whether modules should be unloaded if not used or not. Default: "yes". + + + Specifies the threshold after which late clocks are resynchronized to timestamps for OCR streams. By default, no threashold (0) is used and clocks are never resynchronized. This allows to resync clocks to the media owning the clock when the decoding is really too slow, and should only be used for debugging purposes. + + + Specifies whether the visual rendering is done in the main codec manager or in a dedicated thread. + + + Specifies which module to use by default for audio decoding. The string is the name of the module to be used (same considerations as other modules, cf introduction). + + + Specifies which module to use by default for video decoding. The string is the name of the module to be used (same considerations as other modules, cf introduction). + + + Specifies which module to use by default for image decoding. The string is the name of the module to be used (same considerations as other modules, cf introduction). + + + Allows to specify default media module (audio/video) per stream type and object type. This is useful if you have more than one decoder for a given type (ex, XviD and FFMPEG for MPEG-4 visual SP). The syntax is:

+ codec_AA_BB=modulename

+ where AA is the hexadecimal MPEG-4 streamType value for the codec (04=visual, 05=audio) and BB is the hexadecimal MPEG-4 objectTypeIndication of the media (0x20 = MPEG-4 video, 0x40=MPEG-4 Audio, ...). The string is the name of the module to be used (same considerations as other modules, cf introduction). +
+
+
+ + Specifies the length of the decoding buffer in milliseconds. The client will wait for the buffer to be filled before starting decoding. A module may decide to use a different value based on protocol and network jitters. + +
+
+ + Sets low-latency mode enabled. In low-latency mode, media data is parsed as soon as possible while segment is being downloaded. Default is no. If chunk is selected, media data is re-parsed at each HTTP 1.1 chunk end. If always is selected, media data is re-parsed as soon as HTTP data is received. + +
+
\ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/BitmapView.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/BitmapView.java new file mode 100644 index 0000000..522ffde --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/BitmapView.java @@ -0,0 +1,93 @@ +///** +// * Osmo on Android +// * Aug/2010 +// * NGO Van Luyen +// * +// * +// */ +//package com.gpac.Osmo4; +// +//import android.content.Context; +//import android.graphics.Bitmap; +//import android.graphics.Canvas; +//import android.util.Log; +//import android.view.View; +// +///** +// * +// * @version $Revision$ +// * +// */ +//@Deprecated +//public class BitmapView extends View { +// +// private Bitmap m_Bitmap = null; +// +// private int m_width = 100, m_height = 100; +// +// private final static String LOG_BITMAP = BitmapView.class.getSimpleName(); +// +// /** +// * Constructor +// * +// * @param context The current view's context +// */ +// public BitmapView(Context context) { +// super(context); +// } +// +// @Override +// protected void onDraw(Canvas canvas) { +// // canvas.drawColor(0xFFCCCCCC); +// m_width = canvas.getWidth(); +// m_height = canvas.getHeight(); +// if (m_Bitmap == null) { +// if (m_width < 1) +// m_width = 100; +// if (m_height < 1) +// m_height = 100; +// m_Bitmap = Bitmap.createBitmap(m_width, m_height, Bitmap.Config.ARGB_8888); +// gpacinit(); +// } +// +// GpacObject.gpacrender(m_Bitmap); +// canvas.drawBitmap(m_Bitmap, 0, 0, null); +// // force a redraw, with a different time-based pattern. +// invalidate(); +// +// } +// +// /** +// * Called to init all GPAC resources +// */ +// private void gpacinit() { +// Log.i(LOG_BITMAP, "Going to gpacinit"); //$NON-NLS-1$ +// if (m_Bitmap != null) { +// Log.e(LOG_BITMAP, "m_Bitmap != null"); //$NON-NLS-1$ +// if (m_width < 1) +// m_width = 100; +// if (m_height < 1) +// m_height = 100; +// GpacObject.gpacinit(m_Bitmap, +// null, +// m_width, +// m_height, +// Osmo4Renderer.GPAC_CFG_DIR, +// Osmo4Renderer.GPAC_MODULES_DIR, +// Osmo4Renderer.GPAC_CACHE_DIR, +// Osmo4Renderer.GPAC_FONT_DIR, +// null); +// // GpacObject.gpacconnect("/data/osmo/bifs-2D-interactivity-stringsensor.mp4"); +// GpacObject.gpacresize(m_width, m_height); +// } +// } +// +// /** +// * Called to free all GPAC resources +// */ +// public void gpacfree() { +// Log.e(LOG_BITMAP, "gpacfree()"); //$NON-NLS-1$ +// GpacObject.gpacdisconnect(); +// GpacObject.gpacfree(); +// } +// } diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstance.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstance.java new file mode 100644 index 0000000..a78176d --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstance.java @@ -0,0 +1,425 @@ +/** + * $URL$ + * + * $LastChangedBy$ - $LastChangedDate$ + */ +package com.gpac.Osmo4; + +import java.io.File; +import java.io.PrintStream; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +/** + * @version $Revision$ + * + */ +public class GPACInstance implements GPACInstanceInterface { + + private final static String LOG_LIB = "LibrariesLoader"; //$NON-NLS-1$ + + private final Thread uniqueThread; + + /** + * + * a recursive method to get the directory hierarchy under root. + * + * @param sb StringBuilder object which will return the final hierarchy + * @param root root of the hierarchy + * @param inc initial number of spaces. + */ + private static void listing(StringBuilder sb, File root, int inc) { + StringBuilder increment = new StringBuilder(); + for (int i = 0; i < inc; i++) + increment.append(' '); + String incr = increment.toString(); + for (File f : root.listFiles()) { + sb.append(incr).append(f.getName()); + if (f.isDirectory()) { + sb.append(" [Directory]\n"); //$NON-NLS-1$ + listing(sb, f, inc + 2); + } else { + sb.append(" [").append(f.length() + " bytes]\n"); //$NON-NLS-1$//$NON-NLS-2$ + } + } + } + + /** + * Loads all libraries + * + * @param config + * + * @return a map of exceptions containing the library as key and the exception as value. If map is empty, no error + * + */ + + + synchronized static Map loadAllLibraries(GpacConfig config) { + if (errors != null) + return errors; + StringBuilder sb = new StringBuilder(); + final String[] toLoad = { "GLESv2", "log",//$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ + "jpegdroid", "javaenv", //$NON-NLS-1$ //$NON-NLS-2$ + "mad", "editline", "ft2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "js_osmo", "openjpeg", "png", "z", //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ + "stlport_shared", "stdc++", "faad", "gpac", //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + "gm_droid_cam", "gm_droid_mpegv","gm_mediacodec_dec", //$NON-NLS-1$ //$NON-NLS-2$ + "avutil", "swscale", "swresample", "avcodec", "avformat", "avfilter", + "gpacWrapper" }; // //$NON-NLS-1$ //$NON-NLS-2$ + HashMap exceptions = new HashMap(); + for (String s : toLoad) { + try { + String msg = "Loading library " + s + "...";//$NON-NLS-1$//$NON-NLS-2$ + sb.append(msg); + Log.i(LOG_LIB, msg); + System.loadLibrary(s); + } catch (UnsatisfiedLinkError e) { + sb.append("Failed to load " + s + ", error=" + e.getLocalizedMessage() + " :: " //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + + e.getClass().getSimpleName() + "\n"); //$NON-NLS-1$ + exceptions.put(s, e); + Log.e(LOG_LIB, "Failed to load library : " + s + " due to link error " + e.getLocalizedMessage(), e); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (SecurityException e) { + exceptions.put(s, e); + Log.e(LOG_LIB, "Failed to load library : " + s + " due to security error " + e.getLocalizedMessage(), e); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (Throwable e) { + exceptions.put(s, e); + Log.e(LOG_LIB, "Failed to load library : " + s + " due to Runtime error " + e.getLocalizedMessage(), e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + if (!exceptions.isEmpty()) { + try { + PrintStream out = new PrintStream(config.getGpacLogDirectory() + "debug_libs.txt", "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + out.println("$Revision$"); //$NON-NLS-1$ + out.println(new Date()); + out.println("\n*** Configuration\n"); //$NON-NLS-1$ + out.println(config.getConfigAsText()); + sb.append("*** Libs listing: "); //$NON-NLS-1$ + sb.append(config.getGpacLibsDirectory()); + sb.append('\n'); + listing(sb, new File(config.getGpacLibsDirectory()), 2); + sb.append("*** Modules listing: "); //$NON-NLS-1$ + sb.append(config.getGpacModulesDirectory()); + sb.append('\n'); + listing(sb, new File(config.getGpacModulesDirectory()), 2); + sb.append("*** Fonts listing: \n"); //$NON-NLS-1$ + sb.append(config.getGpacFontDirectory()); + sb.append('\n'); + listing(sb, new File(config.getGpacFontDirectory()), 2); + sb.append("*** Exceptions:\n"); //$NON-NLS-1$ + for (Map.Entry ex : exceptions.entrySet()) { + sb.append(ex.getKey()).append(": ") //$NON-NLS-1$ + .append(ex.getValue().getLocalizedMessage()) + .append('(') + .append(ex.getValue().getClass()) + .append(")\n"); //$NON-NLS-1$ + } + out.println(sb.toString()); + out.flush(); + out.close(); + } catch (Exception e) { + Log.e(LOG_LIB, "Failed to output debug info to debug file", e); //$NON-NLS-1$ + } + } + errors = Collections.unmodifiableMap(exceptions); + return errors; + } + + private static Map errors = null; + + private boolean hasToBeFreed = true; + + /** + * Constructor + * + * @param callback + * @param width + * @param height + * @param config The configuration to use for GPAC + * @param urlToOpen + * @throws GpacInstanceException + */ + public GPACInstance(GpacCallback callback, int width, int height, GpacConfig config, String urlToOpen) + throws GpacInstanceException { + StringBuilder sb = new StringBuilder(); + Map errors = loadAllLibraries(config); + if (!errors.isEmpty()) { + sb.append("Exceptions while loading libraries:"); //$NON-NLS-1$ + for (Map.Entry x : errors.entrySet()) { + sb.append('\n') + .append(x.getKey()) + .append('[') + .append(x.getValue().getClass().getSimpleName()) + .append("]: ") //$NON-NLS-1$ + .append(x.getValue().getLocalizedMessage()); + } + Log.e(LOG_LIB, sb.toString()); + } + try { + handle = createInstance(callback, + width, + height, + config.getGpacConfigDirectory(), + config.getGpacModulesDirectory(), + config.getGpacCacheDirectory(), + config.getGpacFontDirectory(), + config.getGpacGuiDirectory(), + urlToOpen); + } catch (Throwable e) { + throw new GpacInstanceException("Error while creating instance\n" + sb.toString()); //$NON-NLS-1$ + } + if (handle == 0) { + throw new GpacInstanceException("Error while creating instance, no handle created!\n" + sb.toString()); //$NON-NLS-1$ + } + synchronized (this) { + hasToBeFreed = true; + } + uniqueThread = Thread.currentThread(); + } + + /** + * This one handles the pointer to the real C object + */ + private final long handle; + + /** + * @return the handle + */ + public synchronized long getHandle() { + return handle; + } + + private void checkCurrentThread() throws RuntimeException { + if (Thread.currentThread() != uniqueThread) + throw new RuntimeException("Method called outside allowed Thread scope !"); //$NON-NLS-1$ + } + + @Override + public void disconnect() { + checkCurrentThread(); + gpacrender(); + gpacdisconnect(); + } + + @Override + public void connect(String url) { + Log.i(LOG_LIB, "connect(" + url + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + checkCurrentThread(); + gpacrender(); + gpacconnect(url); + } + + /** + * Call this method when a key has been pressed + * + * @param keyCode + * @param event + * @param pressed true if key is pressed, false if key is released + * @param unicode + */ + public void eventKey(int keyCode, KeyEvent event, boolean pressed, int unicode) { + checkCurrentThread(); + gpaceventkeypress(keyCode, event.getScanCode(), pressed ? 1 : 0, event.getFlags(), unicode); + } + + /** + * Renders the current frame + */ + public void render() { + checkCurrentThread(); + gpacrender(); + } + + /** + * Resizes the object to new dimensions + * + * @param width + * @param height + */ + public void resize(int width, int height) { + Log.i(LOG_LIB, "Resizing to " + width + "x" + height); //$NON-NLS-1$ //$NON-NLS-2$ + gpacresize(width, height); + } + + private boolean touched = false; + + /** + * Call this when a motion event occurs + * + * @param event + */ + public void motionEvent(MotionEvent event) { + checkCurrentThread(); + final float x = event.getX(); + final float y = event.getY(); + switch (event.getAction()) { + // not in 1.6 case MotionEvent.ACTION_POINTER_1_DOWN: + case MotionEvent.ACTION_DOWN: + gpaceventmousemove(x, y); + gpaceventmousedown(x, y); + touched = true; + break; + // not in 1.6 case MotionEvent.ACTION_POINTER_1_UP: + case MotionEvent.ACTION_UP: + if ( !touched ) + break; + gpaceventmouseup(x, y); + touched = false; + break; + case MotionEvent.ACTION_MOVE: + gpaceventmousemove(x, y); + if ( !touched ) { + touched = true; + //Log.i("Osmo4", "Mouse down: " + x +"," + y); + gpaceventmousedown(x, y); + } + break; + case MotionEvent.ACTION_CANCEL: + if ( !touched ) + break; + //Log.i("Osmo4", "Mouse up: " + x +"," + y); + gpaceventmouseup(x, y); + touched = false; + break; + } + } + + @Override + public void finalize() throws Throwable { + // Not sure how to do this..., destroy is supposed to be called already + // destroy(); + super.finalize(); + } + + /** + * All Native functions, those functions are binded using the handle + */ + + /** + * Opens an URL + * + * @param url The URL to open + */ + private native void gpacconnect(String url); + + /** + * Used to create the GPAC instance + * + * @param callback + * @param width + * @param height + * @param cfg_dir + * @param modules_dir + * @param cache_dir + * @param font_dir + * @param gui_dir + * @return + */ + private native long createInstance(GpacCallback callback, int width, int height, String cfg_dir, + String modules_dir, String cache_dir, String font_dir, String gui_dir, String url_to_open); + + /** + * Disconnects the currently loaded URL + */ + private native void gpacdisconnect(); + + /** + * Renders + * + * @param handle + */ + private native void gpacrender(); + + /** + * Resizes the current view + * + * @param width The new width to set + * @param height The new height to set + */ + private native void gpacresize(int width, int height); + + /** + * Free all GPAC resources + */ + private native void gpacfree(); + + /** + * To call when a key has been pressed + * + * @param keycode + * @param rawkeycode + * @param up + * @param flag + */ + private native void gpaceventkeypress(int keycode, int rawkeycode, int up, int flag, int unicode); + + /** + * To call when a mouse is down + * + * @param x Position in pixels + * @param y Position in pixels + */ + private native void gpaceventmousedown(float x, float y); + + /** + * To call when a mouse is up (released) + * + * @param x Position in pixels + * @param y Position in pixels + */ + private native void gpaceventmouseup(float x, float y); + + /** + * To call when a mouse is moving + * + * @param x Position in pixels + * @param y Position in pixels + */ + private native void gpaceventmousemove(float x, float y); + + /** + * To call when a change in orientation is returned from the sensors + * All angles are in RADIANS and positive in the COUNTER-CLOCKWISE direction + * + * @param x yaw (rotation around the -Z axis) range: [-PI, PI] + * @param y pitch (rotation around the -X axis) range: [-PI/2, PI/2] + * @param z roll (rotation around the Y axis) range: [-PI, PI] + */ + private native void gpaceventorientationchange(float x, float y, float z); + + public void onOrientationChange(float yaw, float pitch, float roll){ + gpaceventorientationchange(yaw, pitch, roll); + } + + @Override + public void destroy() { + boolean freeIt; + synchronized (this) { + freeIt = hasToBeFreed; + hasToBeFreed = false; + } + if (freeIt) { + disconnect(); + gpacfree(); + } + } + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#setGpacPreference(String, String, String) + */ + @Override + public native void setGpacPreference(String category, String name, String value); + + + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#setGpacLogs(String) + */ + @Override + public native void setGpacLogs(String tools_at_levels); +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstanceInterface.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstanceInterface.java new file mode 100644 index 0000000..ab5adf3 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GPACInstanceInterface.java @@ -0,0 +1,70 @@ +/** + * $URL$ + * + * $LastChangedBy$ - $LastChangedDate$ + */ +package com.gpac.Osmo4; + +/** + * @copyright RTL Group 2008 + * @author RTL Group DTIT software development team (last changed by $LastChangedBy$) + * @version $Revision$ + * + */ +public interface GPACInstanceInterface { + + /** + * @version $Revision$ + * + */ + public static class GpacInstanceException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 3207851655866335152L; + + /** + * Constructor + * + * @param msg + */ + public GpacInstanceException(String msg) { + super(msg); + } + + } + + /** + * Call this method to disconnect + */ + public void disconnect(); + + /** + * Call this method to connect to a given URL + * + * @param url The URL to connect to + */ + public void connect(String url); + + /** + * Destroys the current instance, you won't be able to use it anymore... + */ + public void destroy(); + + /** + * Set a GPAC preference to given value + * + * @param category + * @param name The name of preference as defined in GPAC.cfg + * @param value The value to set, if null, value will be deleted + */ + public void setGpacPreference(String category, String name, String value); + + /** + * Set a GPAC debug level for a given tool + * + * @param tools_at_levels a ":" separated debugspec with debugspec := tool@debug_level + */ + public void setGpacLogs(String tools_at_levels); +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacCallback.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacCallback.java new file mode 100644 index 0000000..e1e24a8 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacCallback.java @@ -0,0 +1,313 @@ +/** + * $URL$ + * + * $LastChangedBy$ - $LastChangedDate$ + */ +package com.gpac.Osmo4; + +/** + * Interface to implement by Java Objects to listen for callbacks from GPAC native code + * + * @version $Revision$ + * + */ +public interface GpacCallback { + + /** + * GPAC Error codes + * + * @version $Revision$ + * + */ + public enum GF_Err { + + /** Message from any scripting engine used in the presentation (ECMAScript, MPEG-J, ...) (Info). */ + GF_SCRIPT_INFO(3), + /** + * Indicates an data frame has several AU packed (not MPEG-4 compliant). This is used by decoders to force + * multiple decoding of the same data frame (Info). + */ + GF_PACKED_FRAMES(2), + /** Indicates the end of a stream or of a file (Info). */ + GF_EOS(1), + /* + * ! \n\n + */ + /** Operation success (no error). */ + GF_OK(0), + /** \n */ + /** One of the input parameter is not correct or cannot be used in the current operating mode of the framework. */ + GF_BAD_PARAM(-1), + /** Memory allocation failure. */ + GF_OUT_OF_MEM(-2), + /** Input/Output failure (disk access, system call failures) */ + GF_IO_ERR(-3), + /** The desired feature or operation is not supported by the framework */ + GF_NOT_SUPPORTED(-4), + /** Input data has been corrupted */ + GF_CORRUPTED_DATA(-5), + /** A modification was attempted on a scene node which could not be found */ + GF_SG_UNKNOWN_NODE(-6), + /** The PROTO node interface does not match the nodes using it */ + GF_SG_INVALID_PROTO(-7), + /** An error occured in the scripting engine */ + 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 */ + GF_NON_COMPLIANT_BITSTREAM(-10), + /** No decoders could be found to handle the desired media type */ + GF_CODEC_NOT_FOUND(-11), + /** The URL is not properly formatted or cannot be found */ + GF_URL_ERROR(-12), + /** An service error has occured at the local side */ + GF_SERVICE_ERROR(-13), + /** A service error has occured at the remote (server) side */ + GF_REMOTE_SERVICE_ERROR(-14), + /** The desired stream could not be found in the service */ + GF_STREAM_NOT_FOUND(-15), + /** 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 */ + GF_ISOM_INCOMPLETE_FILE(-21), + /** The media in this IsoMedia track is not valid (usually due to a broken stream description) */ + GF_ISOM_INVALID_MEDIA(-22), + /** The requested operation cannot happen in the current opening mode of the IsoMedia file */ + GF_ISOM_INVALID_MODE(-23), + /** This IsoMedia track refers to media outside the file in an unknown way */ + GF_ISOM_UNKNOWN_DATA_REF(-24), + + /** An invalid MPEG-4 Object Descriptor was found */ + GF_ODF_INVALID_DESCRIPTOR(-30), + /** An MPEG-4 Object Descriptor was found or added to a forbidden descriptor */ + GF_ODF_FORBIDDEN_DESCRIPTOR(-31), + /** An invalid MPEG-4 BIFS command was detected */ + GF_ODF_INVALID_COMMAND(-32), + /** The scene has been encoded using an unknown BIFS version */ + GF_BIFS_UNKNOWN_VERSION(-33), + + /** The remote IP address could not be solved */ + GF_IP_ADDRESS_NOT_FOUND(-40), + /** The connection to the remote peer has failed */ + GF_IP_CONNECTION_FAILURE(-41), + /** The network operation has failed */ + GF_IP_NETWORK_FAILURE(-42), + /** The network connection has been closed */ + GF_IP_CONNECTION_CLOSED(-43), + /** The network operation has failed because no data is available */ + GF_IP_NETWORK_EMPTY(-44), + /** The network operation has been discarded because it would be a blocking one */ + GF_IP_SOCK_WOULD_BLOCK(-45), + /** + * UDP connection did not receive any data at all. Signaled by client services to reconfigure network if + * possible + */ + GF_IP_UDP_TIMEOUT(-46), + + /** Authentication with the remote host has failed */ + GF_AUTHENTICATION_FAILURE(-50), + /** Script not ready for playback */ + GF_SCRIPT_NOT_READY(-51), + + /** + * Unknown GPAC Error code + */ + JAVA_UNKNOWN_ERROR(-100); + + int value; + + GF_Err(int x) { + this.value = x; + } + + /** + * Get a GPAC Error code from its value + * + * @param status The int status corresponding to the error + * @return A {@link GF_Err} object + */ + public static GF_Err getError(int status) { + for (GF_Err x : values()) { + if (x.value == status) + return x; + } + return JAVA_UNKNOWN_ERROR; + } + } + + /** + * Mapping between GPAC Log Modules and Java symbols + * + * @version $Revision$ + * + */ + public enum GF_Log_Module implements Comparable { + /** Log message from the core library (init, threads, network calls, etc) */ + GF_LOG_CORE(0), + /** Log message from a raw media parser (BIFS, LASeR, A/V formats) */ + GF_LOG_CODING(1), + /** Log message from a bitstream parser (IsoMedia, MPEG-2 TS, OGG, ...) */ + GF_LOG_CONTAINER(2), + /** Log message from the network/service stack (messages & co) */ + GF_LOG_NETWORK(3), + /** Log message from the RTP/RTCP stack (TS info) and packet structure & hinting (debug) */ + GF_LOG_RTP(4), + /** Log message from authoring subsystem (file manip, import/export) */ + GF_LOG_AUTHOR(5), + /** Log message from the sync layer of the terminal */ + GF_LOG_SYNC(6), + /** Log message from a codec */ + GF_LOG_CODEC(7), + /** Log message from any XML parser (context loading, etc) */ + GF_LOG_PARSER(8), + /** Log message from the terminal/compositor, indicating media object state */ + GF_LOG_MEDIA(9), + /** Log message from the scene graph/scene manager (handling of nodes and attribute modif, DOM core) */ + GF_LOG_SCENE(10), + /** Log message from the scripting engine */ + GF_LOG_SCRIPT(11), + /** Log message from event handling */ + GF_LOG_INTERACT(12), + /** Log message from compositor */ + GF_LOG_COMPOSE(13), + /** Log for video object cache */ + GF_LOG_CACHE(14), + /** Log message from multimedia I/O devices (audio/video input/output, ...) */ + GF_LOG_MMIO(15), + /** Log for runtime info (times, memory, CPU usage) */ + GF_LOG_RTI(16), + /** Log for SMIL timing and animation */ + GF_LOG_SMIL(17), + /** Log for memory tracker */ + GF_LOG_MEMORY(18), + /** Log for audio compositor */ + GF_LOG_AUDIO(19), + /** generic Log for modules */ + GF_LOG_MODULE(20), + /** + * Log for GPAC mutexes and threads (Very verbose at DEBUG) + * + */ + GF_LOG_MUTEX(21), + /*! Log for threads and condition */ + GF_LOG_CONDITION(22), + /*! Log for all HTTP streaming */ + GF_LOG_DASH(23), + /*! Log for all messages coming from GF_Terminal or script alert()*/ + GF_LOG_CONSOLE(24), + /*! Log for all messages coming the application, not used by libgpac or the modules*/ + GF_LOG_APP(25), + /*! Log for all messages coming from the scheduler */ + GF_LOG_SCHEDULER(26), + /** + * Unknown Log subsystem + */ + GF_LOG_UNKNOWN(30); + + int value; + + /** + * Private Constructor + */ + private GF_Log_Module(int x) { + this.value = x; + } + + /** + * Finds a module from its module_code + * + * @param module_code + * @return The Module found (never null) + */ + public static GF_Log_Module getModule(int module_code) { + for (GF_Log_Module x : values()) { + if (x.value == module_code) + return x; + } + return GF_LOG_UNKNOWN; + } + } + + /** + * Display a message + * + * @param message + * @param title + * @param errorCode + */ + public void displayMessage(String message, String title, int errorCode); + + + /** + * Called when setup log file + * + * @param path + */ + public void setLogFile(String path); + + /** + * Called when logging + * + * @param level + * @param module + * @param message + */ + public void onLog(int level, int module, String message); + + /** + * Called when progress is set + * + * @param msg + * @param done + * @param total + */ + public void onProgress(String msg, int done, int total); + + /** + * Called when GPAC is ready + */ + public void onGPACReady(); + + /** + * Called when GPAC initialization fails + * + * @param e + */ + public void onGPACError(Throwable e); + + // /** + // * Returns UserName:Password for given site + // * + // * @param siteURL The URL of site requiring authorization + // * @param userName The User Name (may be null if never set) + // * @param password The password (may be null if never set) + // * @return A String formated as username:password + // */ + // public String onGPACAuthorization(String siteURL, String userName, String password); + + /** + * Set the new caption for the application + * + * @param newCaption The new caption to set for application + */ + public void setCaption(String newCaption); + + /** + * Show the virtual keyboard + * + * @param showKeyboard + */ + public void showKeyboard(boolean showKeyboard); + + /** + * Toggle Sensors on/off + * + * @param active sensor (true/false) + */ + public void sensorSwitch(boolean active); + + +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacConfig.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacConfig.java new file mode 100644 index 0000000..4914987 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/GpacConfig.java @@ -0,0 +1,236 @@ +/** + * $URL$ + * + * $LastChangedBy$ - $LastChangedDate$ + */ +package com.gpac.Osmo4; + +import java.io.File; +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Environment; +import android.util.Log; + +/** + * This class handles all GPAC configuration directories + * + * @author Pierre Souchay (VizionR SAS) (last changed by $LastChangedBy$) + * @version $Revision$ + * + */ + +/** + * NOTE FOR DEVELOPERS + * Whenever you add or change a path here, you MUST verify also the corresponding path in src/utils/os_config_init.c + */ +public class GpacConfig { + + private final static String LOG_GPAC_CONFIG = GpacConfig.class.getSimpleName(); + + /** + * Default Constructor + * + * @param context + */ + public GpacConfig(Context context) { + String dataDir; + try { + if (context == null || context.getPackageManager() == null) { + dataDir = Environment.getDataDirectory() + "/data/com.gpac.Osmo4/"; //$NON-NLS-1$ + Log.e(LOG_GPAC_CONFIG, "Cannot get context or PackageManager, using default directory=" + dataDir); //$NON-NLS-1$ + } else + dataDir = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0).dataDir; + } catch (NameNotFoundException e) { + Log.e(LOG_GPAC_CONFIG, "This is bad, we cannot find ourself : " + context.getPackageName(), e); //$NON-NLS-1$ + throw new RuntimeException("Cannot find package " + context.getPackageName(), e); //$NON-NLS-1$ + } + gpacAppDirectory = dataDir + '/'; + Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacAppDirectory + " for osmo"); //$NON-NLS-1$ //$NON-NLS-2$ + gpacCacheDirectory = context.getCacheDir().getAbsolutePath(); + Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacCacheDirectory + " for cache"); //$NON-NLS-1$ //$NON-NLS-2$ + // + //Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacModulesDirectory + " for modules"); //$NON-NLS-1$ //$NON-NLS-2$ + gpacLibsDirectory = dataDir + "/lib/"; //$NON-NLS-1$ + Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacLibsDirectory + " for libraries"); //$NON-NLS-1$ //$NON-NLS-2$ + + gpacGuiDirectory = dataDir + "/gui/"; + Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacGuiDirectory + " for GUI"); //$NON-NLS-1$ //$NON-NLS-2$ + + gpacShaderDirectory = dataDir + "/shaders/"; + Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacShaderDirectory + " for shader files"); //$NON-NLS-1$ //$NON-NLS-2$ + + File osmo = new File(Environment.getExternalStorageDirectory(), "osmo"); //$NON-NLS-1$ + gpacLogDirectory = osmo.getAbsolutePath() + "/log/"; + Log.v(LOG_GPAC_CONFIG, "Using directory " + gpacLogDirectory + " for log files"); //$NON-NLS-1$ //$NON-NLS-2$ + + //check if GPAC.cfg exists in /sdcard/osmo + File gpac_cfg = new File(osmo.getAbsolutePath(), "GPAC.cfg"); + if (gpac_cfg.exists()) + gpacConfigDirectory = osmo.getAbsolutePath() + "/"; + else + gpacConfigDirectory = null; + } + + /** + * Ensures all directories are created + * + * @return The {@link GpacConfig} instance itself + */ + public GpacConfig ensureAllDirectoriesExist() { + for (String s : new String[] { gpacAppDirectory, gpacCacheDirectory, gpacShaderDirectory, gpacLogDirectory }) { + createDirIfNotExist(s); + } + return this; + } + + /** + * Default directory for GPAC configuration directory, ends with / + * + * @return the gpacAppDirectory + */ + public String getGpacAppDirectory() { + return gpacAppDirectory; + } + + + /** + * Default directory for GPAC configuration directory, ends with / + * + * @return the gpacConfigDirectory + */ + public String getGpacConfigDirectory() { + return gpacConfigDirectory; + } + + /** + * Directory of Android containing all fonts + * + * @return the gpacFontDirectory + */ + public String getGpacFontDirectory() { + return gpacFontDirectory; + } + + /** + * Default directory for GPAC modules directory, ends with / + * + * @return the gpacModulesDirectory + */ + public String getGpacModulesDirectory() { + // return gpacModulesDirectory; + return gpacLibsDirectory; + } + + /** + * @return the gpacLibsDirectory + */ + public String getGpacLibsDirectory() { + return gpacLibsDirectory; + } + + /** + * Default directory for cached files + * + * @return the gpacCacheDirectory + */ + public String getGpacCacheDirectory() { + return gpacCacheDirectory; + } + + /** + * Default directory for GUI files + * + * @return the gpacGuiDirectory + */ + public String getGpacGuiDirectory() { + return gpacGuiDirectory; + } + + /** + * Default directory for shader files + * + * @return the gpacShaderDirectory + */ + public String getGpacShaderDirectory() { + return gpacShaderDirectory; + } + + /** + * Default directory for log files + * + * @return the gpacLogDirectory + */ + public String getGpacLogDirectory() { + return gpacLogDirectory; + } + + private final String gpacAppDirectory; + + private final String gpacConfigDirectory; + + private final String gpacFontDirectory = "/system/fonts/"; //$NON-NLS-1$ + + // private final String gpacModulesDirectory; + + private final String gpacLibsDirectory; + + private final String gpacCacheDirectory; + + private final String gpacGuiDirectory; + + private final String gpacShaderDirectory; + + private final String gpacLogDirectory; + + /** + * Creates a given directory if it does not exist + * + * @param path + */ + private static boolean createDirIfNotExist(String path) { + File f = new File(path); + if (!f.exists()) { + if (!f.mkdirs()) { + Log.e(LOG_GPAC_CONFIG, "Failed to create directory " + path); //$NON-NLS-1$ + return false; + } else { + Log.i(LOG_GPAC_CONFIG, "Created directory " + path); //$NON-NLS-1$ + } + } + return true; + } + + /** + * Get the GPAC.cfg file + * + * @return the file + */ + public File getGpacConfigFile() { + return new File(getGpacConfigDirectory(), "GPAC.cfg"); //$NON-NLS-1$ + } + + /** + * Get the GPAC.cfg file + * + * @return the file + */ + public File getGpacLastRevFile() { + return new File(getGpacConfigDirectory(), "lastRev.txt"); //$NON-NLS-1$ + } + + /** + * Get the configuration as text + * + * @return a String with newlines representing all the configuration + */ + public String getConfigAsText() { + StringBuilder sb = new StringBuilder(); + sb.append("GpacAppDirectory=").append(getGpacAppDirectory()).append('\n'); //$NON-NLS-1$ + sb.append("GpacModulesDirectory=").append(getGpacModulesDirectory()).append('\n'); //$NON-NLS-1$ + sb.append("GpacFontDirectory=").append(getGpacFontDirectory()).append('\n'); //$NON-NLS-1$ + sb.append("GpacCacheDirectory=").append(getGpacCacheDirectory()).append('\n'); //$NON-NLS-1$ + sb.append("GpacGuiDirectory=").append(getGpacGuiDirectory()).append('\n'); //$NON-NLS-1$ + sb.append("GpacShaderDirectory=").append(getGpacShaderDirectory()).append('\n'); //$NON-NLS-1$ + return sb.toString(); + } +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/MPEGVSensor.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/MPEGVSensor.java new file mode 100644 index 0000000..112e566 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/MPEGVSensor.java @@ -0,0 +1,503 @@ +package com.gpac.Osmo4; + +import android.app.Activity; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; + +/** + * Handle Physical sensors + * + * @authors Ivica Arsov (ivica.arsov@it-sudparis.eu) - Pierre Souchay (last changed by $LastChangedBy$) + * @version $Revision$ + * + */ +public class MPEGVSensor implements SensorEventListener, LocationListener { + + public static Activity myAct = null; + + private native void sendData(int ptr, String data); + + private static SensorManager mySensorManager = null; + private static LocationManager myLocationManager = null; + + private static Sensor sensor = null; + + private static Sensor sensor1 = null; + + private int SensorType = -2; + + private int InternalPtr = 0; + + private Boolean run = false; + + /** + * Init the sensor Manager + * + * @param mgr The manager to set + * @return the sensor manager set + */ + public static SensorManager initSensorManager(SensorManager mgr) { + return mySensorManager = mgr; + } + + /** + * Init the location Manager + * + * @param mgr The manager to set + * @return the location manager set + */ + public static LocationManager initLocationManager(LocationManager mgr) { + return myLocationManager = mgr; + } + + /** + * Starts the given sensor and register the listener + * + * @param ptr The pointer + * @param type The type of sensor as defined in {@link Sensor} + */ + public void startSensor(int ptr, int type) { + InternalPtr = ptr; + SensorType = type; + + switch (SensorType) { + case Sensor.TYPE_ORIENTATION: { + sensor = mySensorManager + .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_GAME)) + return; + sensor1 = mySensorManager + .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor1, + SensorManager.SENSOR_DELAY_GAME)) + { + mySensorManager.unregisterListener(MPEGVSensor.this); + return; + } + run = true; + break; + } + case Sensor.TYPE_ACCELEROMETER: { + sensor = mySensorManager + .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + if( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_GAME)) + return; + run = true; + break; + } + case Sensor.TYPE_GYROSCOPE: { + sensor = mySensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_GAME)) + return; + run = true; + break; + } + case Sensor.TYPE_MAGNETIC_FIELD: { + sensor = mySensorManager + .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_GAME)) + return; + run = true; + break; + } + case Sensor.TYPE_LIGHT: { + sensor = mySensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_UI)) + return; + run = true; + break; + } + case Sensor.TYPE_PRESSURE: { + sensor = mySensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_UI)) + return; + run = true; + break; + } + //case Sensor.TYPE_ROTATION_VECTOR: { + case 11: { + sensor = mySensorManager + .getDefaultSensor(11); + if ( !mySensorManager.registerListener(MPEGVSensor.this, sensor, + SensorManager.SENSOR_DELAY_GAME)) + return; + run = true; + break; + } + case 100: { // Type for the GPS sensor + myAct.runOnUiThread(new Runnable() { + + @Override + public void run() { + myLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, MPEGVSensor.this); + run = true; + } + }); + } + } + } + + /** + * Stops the sensor and unregister listener + */ + public void stopSensor() { + if (SensorType == 100) + myAct.runOnUiThread(new Runnable() { + + @Override + public void run() { + + myLocationManager.removeUpdates(MPEGVSensor.this); + + } + }); + else + mySensorManager.unregisterListener(MPEGVSensor.this); + run = false; + } + + @Override + public void onAccuracyChanged(Sensor arg0, int arg1) { + // TODO Auto-generated method stub + + } + + public double azzimuth = 0; + public double pitch = 0; + public double roll = 0; + + public double x, y, z, angle; + + private float[] mGData = new float[3]; + private float[] mMData = new float[3]; + private float[] mR = new float[16]; + private float[] mI = new float[16]; + private float[] mOrientation = new float[3]; + + int buffsize = 8; + + public double[] al = new double[buffsize]; + public double[] pl = new double[buffsize]; + public double[] rl = new double[buffsize]; + int ind = 0; + + double rotangle = 0; + + @Override + public void onSensorChanged(SensorEvent event) { + + if ( !run ) + return; + + switch (SensorType) + { + case Sensor.TYPE_ORIENTATION: + { + int type = event.sensor.getType(); + if (type == Sensor.TYPE_ACCELEROMETER) { + for (int i=0 ; i<3 ; i++) + mGData[i] = event.values[i]; + + lowPass(mGData, accel); + //filterAccData(); + //Log.i("Acc: ", "" + event.values[0] + " " + event.values[1] + " " + event.values[2]); + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + for (int i=0 ; i<3 ; i++) + mMData[i] = event.values[i]; + + lowPass(mMData, mag); + //filterMagData(); + //Log.i("Mag: ", "" + event.values[0] + " " + event.values[1] + " " + event.values[2]); + } else { + if ( event.sensor.getType() == Sensor.TYPE_ORIENTATION ) + { + azzimuth = event.values[0]; + pitch = event.values[1]; + roll = event.values[2]; + } + return; + } + + SensorManager.getRotationMatrix(mR, mI, mGData, mMData); + SensorManager.getOrientation(mR, mOrientation); + + lowPass(mOrientation, ordata); + //filterOrientationData(); + + al[ind] = mOrientation[0]; + pl[ind] = mOrientation[1]; + rl[ind] = mOrientation[2]; + + if ( ++ind == buffsize ) + ind = 0; + + double a = 0, p = 0, r = 0; + for ( int i =0; i < buffsize; i++ ) + { + a += al[i]; + p += pl[i]; + r += rl[i]; + } + + a /= buffsize; + p /= buffsize; + r /= buffsize; + + final float rad2deg = (float)(180.0f/Math.PI); + azzimuth = a*rad2deg;//mOrientation[0]*rad2deg; + pitch = p*rad2deg;//mOrientation[1]*rad2deg; + roll = r*rad2deg;//mOrientation[2]*rad2deg; + +// mOrientation[0] = (float)azzimuth; +// mOrientation[1] = (float)pitch; +// mOrientation[2] = (float)roll; +// +// filterOrientationData(); +// +// azzimuth = mOrientation[0]; +// pitch = mOrientation[1]; +// roll = mOrientation[2]; + + String res = ""; + res += azzimuth+";" + pitch + ";" + roll + ";"; + sendData(InternalPtr, res); + break; + } + case Sensor.TYPE_ACCELEROMETER: + { + for (int i=0 ; i<3 ; i++) + mGData[i] = event.values[i]; + + lowPass(mGData, accel); + + al[ind] = mGData[0]; + pl[ind] = mGData[1]; + rl[ind] = mGData[2]; + + if ( ++ind == buffsize ) + ind = 0; + + double a = 0, p = 0, r = 0; + for ( int i =0; i < buffsize; i++ ) + { + a += al[i]; + p += pl[i]; + r += rl[i]; + } + + a /= buffsize; + p /= buffsize; + r /= buffsize; + + String res = ""; + res += a+";" + p + ";" + r + ";"; + sendData(InternalPtr, res); + break; + } + case Sensor.TYPE_GYROSCOPE: + { + for (int i=0 ; i<3 ; i++) + mGData[i] = event.values[i]; + + lowPass(mGData, accel); + + al[ind] = mGData[0]; + pl[ind] = mGData[1]; + rl[ind] = mGData[2]; + + if ( ++ind == buffsize ) + ind = 0; + + double a = 0, p = 0, r = 0; + for ( int i =0; i < buffsize; i++ ) + { + a += al[i]; + p += pl[i]; + r += rl[i]; + } + + a /= buffsize; + p /= buffsize; + r /= buffsize; + + String res = ""; + res += a+";" + p + ";" + r + ";"; + sendData(InternalPtr, res); + break; + } + case Sensor.TYPE_MAGNETIC_FIELD: + { + for (int i=0 ; i<3 ; i++) + mGData[i] = event.values[i]; + + lowPass(mGData, accel); + + al[ind] = mGData[0]; + pl[ind] = mGData[1]; + rl[ind] = mGData[2]; + + if ( ++ind == buffsize ) + ind = 0; + + double a = 0, p = 0, r = 0; + for ( int i =0; i < buffsize; i++ ) + { + a += al[i]; + p += pl[i]; + r += rl[i]; + } + + a /= buffsize; + p /= buffsize; + r /= buffsize; + + String res = ""; + res += a+";" + p + ";" + r + ";"; + sendData(InternalPtr, res); + break; + } + //case Sensor.TYPE_ROTATION_VECTOR: + case 11: + { + double a = event.values[0], p = event.values[1], r = event.values[2]; + + final float rad2deg = (float)(180.0f/Math.PI); + a = a*rad2deg; + p = p*rad2deg; + r = r*rad2deg; + + String res = ""; + res += a + ";" + p + ";" + r + ";"; + sendData(InternalPtr, res); + + break; + } + case Sensor.TYPE_LIGHT: + { + String res = ""; + res += event.values[0] + ";"; + sendData(InternalPtr, res); + break; + } + case Sensor.TYPE_PRESSURE: + { + String res = ""; + res += event.values[0]+";"; + sendData(InternalPtr, res); + break; + } + } + } + + static final float ALPHA = 0.01f; + + protected float[] lowPass(float[] input, float[] output) { + if (output == null) + return input; + + for (int i = 0; i < input.length; i++) { + output[i] = output[i] + ALPHA * (input[i] - output[i]); + } + return output; + } + + Boolean accinited = false; + float[] accel = new float[3]; + + private void filterData(float[] data, float[] filter) { + float kFilteringFactor = 0.1f; + + filter[0] = data[0] * kFilteringFactor + filter[0] + * (1.0f - kFilteringFactor); + filter[1] = data[1] * kFilteringFactor + filter[1] + * (1.0f - kFilteringFactor); + filter[2] = data[2] * kFilteringFactor + filter[2] + * (1.0f - kFilteringFactor); + data[0] = data[0] - filter[0]; + data[1] = data[1] - filter[1]; + data[2] = data[2] - filter[2]; + + filter[0] = data[0]; + filter[1] = data[1]; + filter[2] = data[2]; + } + + private void filterAccData() { + if (!accinited) { + accel[0] = mGData[0]; + accel[1] = mGData[1]; + accel[2] = mGData[2]; + accinited = true; + } + filterData(mGData, accel); + } + + Boolean maginited = false; + float[] mag = new float[3]; + + private void filterMagData() { + if (!maginited) { + mag[0] = mMData[0]; + mag[1] = mMData[1]; + mag[2] = mMData[2]; + maginited = true; + } + filterData(mMData, mag); + } + + Boolean orinited = false; + float[] ordata = new float[3]; + + private void filterOrientationData() { + if (!orinited) { + ordata[0] = mOrientation[0]; + ordata[1] = mOrientation[1]; + ordata[2] = mOrientation[2]; + orinited = true; + } + filterData(mOrientation, ordata); + } + + @Override + public void onLocationChanged(Location loc) { + String res = ""; + res += loc.getLongitude() + ";" + + loc.getLatitude() + ";" + + loc.getAltitude() + ";" + + loc.getAccuracy() + ";" + + loc.getBearing() + ";"; + sendData(InternalPtr, res); + } + + @Override + public void onProviderDisabled(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onProviderEnabled(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onStatusChanged(String arg0, int arg1, Bundle arg2) { + // TODO Auto-generated method stub + + } + +} + diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4.java new file mode 100644 index 0000000..d72b197 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4.java @@ -0,0 +1,1383 @@ +/** + * Osmo on Android + * Aug/2010 + * NGO Van Luyen + * $Id$ + * + */ +package com.gpac.Osmo4; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Set; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.hardware.SensorManager; +import android.location.LocationManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.os.StrictMode; +import android.os.Vibrator; +import android.text.InputType; +import android.util.Log; +import android.view.View; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.LinearLayout; +import android.widget.Toast; +import android.content.res.AssetManager; +import android.os.Environment; + + +import android.os.Handler; +import android.os.Message; +import android.view.GestureDetector; +import android.view.MotionEvent; + +import com.gpac.Osmo4.Osmo4GLSurfaceView; +import com.gpac.Osmo4.Preview; +import com.gpac.Osmo4.R; +import com.gpac.Osmo4.extra.ConfigFileEditorActivity; +import com.gpac.Osmo4.extra.FileChooserActivity; +import com.gpac.Osmo4.extra.PrefsActivity; +import com.gpac.Osmo4.logs.GpacLogger; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +import com.lge.real3d.Real3D; +import com.lge.real3d.Real3DInfo; +/** + * The main Osmo4 activity, used to launch everything + * + * @version $Revision$ + * + */ +public class Osmo4 extends Activity implements GpacCallback { + + // private String[] m_modules_list; + private static final int INITIAL_HIDE_DELAY = 300; + + public boolean m3DLibraryLoaded = false; + private Real3D mReal3D; + private View mDecorView; + + private boolean shouldDeleteGpacConfig = false; + + /** + * @return the shouldDeleteGpacConfig + */ + public synchronized boolean isShouldDeleteGpacConfig() { + return shouldDeleteGpacConfig; + } + + /** + * @param shouldDeleteGpacConfig the shouldDeleteGpacConfig to set + */ + public synchronized void setShouldDeleteGpacConfig(boolean shouldDeleteGpacConfig) { + this.shouldDeleteGpacConfig = shouldDeleteGpacConfig; + } + + private final static String CFG_STARTUP_CATEGORY = "General"; //$NON-NLS-1$ + + private final static String CFG_STARTUP_NAME = "StartupFile"; //$NON-NLS-1$ + + private static boolean keyboardIsVisible = false; + + private final static int DEFAULT_BUFFER_SIZE = 8192; + + private static boolean uivisible; + + public static Context context; + + private GpacConfig gpacConfig; + + /** + * Activity request ID for picking a file from local file system + */ + public final static int PICK_FILE_REQUEST = 1; + + private final static String LOG_OSMO_TAG = "Osmo4"; //$NON-NLS-1$ + + /** + * List of all extensions recognized by Osmo + */ + public final static String OSMO_REGISTERED_FILE_EXTENSIONS = "*.mp4,*.bt,*.xmt,*.xml,*.ts,*.svg,*.mp3,*.m3u8,*.mpg,*.aac,*.m4a,*.jpg,*.png,*.wrl,*.mpd"; //$NON-NLS-1$ + + private PowerManager.WakeLock wl = null; + + private Osmo4GLSurfaceView mGLView; + + private GpacLogger logger; + + private ProgressDialog startupProgress; + + private LinearLayout gl_view; + + /** + * Handling of Sensors + */ + private SensorServices sensors; + + // --------------------------------------- + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + context = getApplicationContext(); + + try { + Class c = Class.forName("com.lge.real3d.Real3D"); + final String LGE_3D_DISPLAY = "lge.hardware.real3d.barrier.landscape"; + if(this.getPackageManager().hasSystemFeature(LGE_3D_DISPLAY)) + m3DLibraryLoaded = true; + } + catch (ClassNotFoundException e) { + m3DLibraryLoaded = false; + } + MPEGVSensor.myAct = this; + MPEGVSensor.initSensorManager((SensorManager) getSystemService(Context.SENSOR_SERVICE)); + MPEGVSensor.initLocationManager((LocationManager)getSystemService(Context.LOCATION_SERVICE)); + + final String toOpen; + if (Intent.ACTION_VIEW.equals(getIntent().getAction())) { + Uri uri = getIntent().getData(); + if (uri != null) { + synchronized (this) { + toOpen = uri.toString(); + } + } else + toOpen = null; + } else + toOpen = null; + if (gpacConfig == null) { + gpacConfig = new GpacConfig(this); + if (gpacConfig == null) { + Log.e(LOG_OSMO_TAG, "Failed to load GPAC config"); //$NON-NLS-1$ + displayPopup(getResources().getString(R.string.failedToLoadGPACConfig), + getResources().getString(R.string.failedToLoadGPACConfig)); + } else + gpacConfig.ensureAllDirectoriesExist(); + } + if (logger == null) + logger = new GpacLogger(gpacConfig); + logger.onCreate(); + if (startupProgress == null) { + startupProgress = new ProgressDialog(this); + startupProgress.setCancelable(false); + } + startupProgress.setMessage(getResources().getText(R.string.osmoLoading)); + startupProgress.setTitle(R.string.osmoLoading); + startupProgress.show(); + + if (mGLView != null) { + setContentView(R.layout.main); + if (toOpen != null) + openURLasync(toOpen); + // OK, it means activity has already been started + return; + } + Preview.context = this; + + setContentView(R.layout.main); + + final View contentView = (LinearLayout)findViewById(R.id.surface_gl); + mDecorView = getWindow().getDecorView(); + + mDecorView.setOnSystemUiVisibilityChangeListener + (new View.OnSystemUiVisibilityChangeListener() { + @Override + public void onSystemUiVisibilityChange(int visibility) { + if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + uivisible = true; + } else { + uivisible = false; + } + } + }); + + contentView.setClickable(true); + final GestureDetector clickDetector = new GestureDetector(this, + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (uivisible) { + if (Osmo4.this.keyboardIsVisible) + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(mGLView.getWindowToken(), 0); + hideSystemUI(); + } + return true; + } + }); + contentView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + return clickDetector.onTouchEvent(motionEvent); + } + }); + + showSystemUI(); + mGLView = new Osmo4GLSurfaceView(this); + + gl_view = (LinearLayout)findViewById(R.id.surface_gl); + + sensors = new SensorServices(this); + + if( m3DLibraryLoaded ) //should be checking wether the terminal is a LG one + { + //TryLoad3DClass(true); + mReal3D = new Real3D(mGLView.getHolder()); + mReal3D.setReal3DInfo(new Real3DInfo(true, Real3D.REAL3D_TYPE_SS, Real3D.REAL3D_ORDER_LR)); + } + service.submit(new Runnable() { + + @Override + public void run() { + // loadAllModules(); + runOnUiThread(new Runnable() { + + @Override + public void run() { + startupProgress.setIndeterminate(true); + startupProgress.setMessage(getResources().getText(R.string.gpacLoading)); + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, LOG_OSMO_TAG); + if (wl != null) + wl.acquire(); + synchronized (Osmo4.this) { + Osmo4.this.wl = wl; + } + + Osmo4Renderer renderer = new Osmo4Renderer(Osmo4.this, gpacConfig, toOpen); + mGLView.setRenderer(renderer); + + gl_view.addView(mGLView); + + sensors.setRenderer(renderer); + } + }); + + } + }); + // creates no media files if it does not exist + service.submit(new Runnable() { + + @Override + public void run() { + for (String s : new String[] { gpacConfig.getGpacAppDirectory(), gpacConfig.getGpacCacheDirectory() }) { + File noMedia = new File(s, ".nomedia"); //$NON-NLS-1$ + if (!noMedia.exists()) { + try { + noMedia.createNewFile(); + } catch (IOException e) { + Log.w(LOG_OSMO_TAG, "Failed to create " + noMedia.getAbsolutePath(), e); //$NON-NLS-1$ + } + } + } + } + }); + + //copy GUI elements + File guiDir = new File(gpacConfig.getGpacGuiDirectory()); + if (!guiDir.isDirectory()) { + // there was a file which have the same name with GUI dir, delete it + if (guiDir.exists()) { + if (!guiDir.delete()) + Log.e(LOG_OSMO_TAG, "Failed to delete " + guiDir); + } + if (!guiDir.mkdir()) + Log.e(LOG_OSMO_TAG, "Failed to create directory " + guiDir); + copyAssets(gpacConfig, GUI_ROOT_ASSET_DIR); + } + + //copy Shaders + File shaderDir = new File(gpacConfig.getGpacShaderDirectory()); + if (!shaderDir.isDirectory()) { + // we do not delete the directory if it already exists, because it might contain custom shaders + if (shaderDir.exists()) { + Log.v(LOG_OSMO_TAG, "Shader directory already exists at: " + shaderDir); + }else if (!shaderDir.mkdir()){ + Log.e(LOG_OSMO_TAG, "Failed to create directory " + shaderDir); + } + } + copyAssets(gpacConfig, SHADER_ROOT_ASSET_DIR); + + //if there is not a GPAC.cfg in external storage (i.e using config in app directory) + //copy GPAC.cfg from gpacAppDirectoryto gpacLogDirectory + File osmo = new File(Environment.getExternalStorageDirectory(), "osmo"); + File gpac_external_cfg = new File(osmo.getAbsolutePath(), "GPAC.cfg"); + if (!gpac_external_cfg.exists()) { + try { + InputStream in = new FileInputStream(gpacConfig.getGpacAppDirectory() + "GPAC.cfg"); + OutputStream out = new FileOutputStream(gpacConfig.getGpacLogDirectory() + "GPAC.cfg"); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } catch (IOException e) { + Log.d(LOG_OSMO_TAG, "Error in copying config file: " + e.toString()); + } + } + + } + + /* + * Copy GUI elements + * + * @param config + * + * Reference: http://stackoverflow.com/questions/4447477/android-how-to-copy-files-from-assets-folder-to-sdcard + */ + private final static String GUI_ROOT_ASSET_DIR = "gui"; + private final static String SHADER_ROOT_ASSET_DIR = "shaders"; + + private void copyAssets(GpacConfig config, String asset_dir) { + StringBuilder sb = new StringBuilder(); + HashMap exceptions = new HashMap(); + AssetManager assetManager = getAssets(); + String[] list = null; + Log.d(LOG_OSMO_TAG, "Copy assets of " + asset_dir); + try { + list = assetManager.list(asset_dir); + } catch (IOException e) { + Log.e(LOG_OSMO_TAG, "Failed to get asset file list.", e); + exceptions.put("Failed to get asset file list", e); + } + for(String path : list) { + try { + copyFileOrDir(config, asset_dir, path); + } catch(IOException e) { + Log.e(LOG_OSMO_TAG, "Failed to copy: " + path, e); + exceptions.put("Failed to copy " + path, e); + } + } + + if (!exceptions.isEmpty()) { + try { + PrintStream out = new PrintStream(config.getGpacLogDirectory() + "debug_assets.txt", "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + sb.append("*** Exceptions:\n"); //$NON-NLS-1$ + for (Map.Entry ex : exceptions.entrySet()) { + sb.append(ex.getKey()).append(": ") //$NON-NLS-1$ + .append(ex.getValue().getLocalizedMessage()) + .append('(') + .append(ex.getValue().getClass()) + .append(")\n"); //$NON-NLS-1$ + } + out.println(sb.toString()); + out.flush(); + out.close(); + } catch (Exception e) { + Log.e(LOG_OSMO_TAG, "Failed to output debug info to debug file", e); //$NON-NLS-1$ + } + } + } + + private void copyFileOrDir(GpacConfig config, String root, String path) throws IOException { + AssetManager assetManager = getAssets(); + String assets[] = null; + assets = assetManager.list(root + "/" + path); + if (assets.length == 0) { + copyFile(config, root, path); + } else { + String fullPath = null; + if(root == GUI_ROOT_ASSET_DIR){ + fullPath = config.getGpacGuiDirectory() + path; + }else if(root == SHADER_ROOT_ASSET_DIR){ + fullPath = config.getGpacShaderDirectory() + path; + }else{ //Fallback (useless for now) + fullPath = path; + } + File dir = new File(fullPath); + if (!dir.exists()) + dir.mkdir(); + for (int i = 0; i < assets.length; ++i) { + copyFileOrDir(config, root, path + "/" + assets[i]); + } + } + } + + private void copyFile(GpacConfig config, String root, String filename) throws IOException { + // if this file exists, do nothing + + if(root.equals(GUI_ROOT_ASSET_DIR)){ + if ((new File(config.getGpacGuiDirectory() + filename).exists())) + return; + } + + AssetManager assetManager = getAssets(); + InputStream in = null; + OutputStream out = null; + in = assetManager.open(root + "/" + filename); + + String newFileName = null; + if(root.equals(GUI_ROOT_ASSET_DIR)){ + newFileName = config.getGpacGuiDirectory() + filename; + }else if(root.equals(SHADER_ROOT_ASSET_DIR)){ + newFileName = config.getGpacShaderDirectory() + filename; + }else{ //Fallback + newFileName = filename; + } + out = new FileOutputStream(newFileName); + + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + in.close(); + in = null; + out.flush(); + out.close(); + out = null; + } + + // --------------------------------------- + + public static boolean isUIvisible(){ + return uivisible; + } + + public static boolean IskeyboardVisible(){ + return keyboardIsVisible; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main_menu, menu); + return true; + } + + private String getRecentURLsFile() { + return gpacConfig.getGpacAppDirectory() + "recentURLs.txt"; //$NON-NLS-1$ + } + + private boolean openURL() { + Future res = service.submit(new Callable() { + + @Override + public String[] call() throws Exception { + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(getRecentURLsFile()), + DEFAULT_ENCODING), DEFAULT_BUFFER_SIZE); + + String s = null; + Set results = new HashSet(); + while (null != (s = reader.readLine())) { + results.add(s); + } + addAllRecentURLs(results); + return results.toArray(new String[0]); + } finally { + if (reader != null) + reader.close(); + } + } + }); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + final AutoCompleteTextView textView = new AutoCompleteTextView(this); + textView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI); + builder.setMessage(R.string.pleaseEnterAnURLtoConnectTo) + .setCancelable(true) + .setPositiveButton(R.string.open_url, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + final String newURL = textView.getText().toString(); + openURLasync(newURL); + service.execute(new Runnable() { + + @Override + public void run() { + addAllRecentURLs(Collections.singleton(newURL)); + File tmp = new File(getRecentURLsFile() + ".tmp"); //$NON-NLS-1$ + BufferedWriter w = null; + try { + w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tmp), + DEFAULT_ENCODING), DEFAULT_BUFFER_SIZE); + Collection toWrite = getAllRecentURLs(); + for (String s : toWrite) { + w.write(s); + w.write("\n"); //$NON-NLS-1$ + } + w.close(); + w = null; + if (tmp.renameTo(new File(getRecentURLsFile()))) + Log.e(LOG_OSMO_TAG, "Failed to rename " + tmp + " to " + getRecentURLsFile()); //$NON-NLS-1$//$NON-NLS-2$ + + } catch (IOException e) { + Log.e(LOG_OSMO_TAG, "Failed to write recent URLs to " + tmp, e); //$NON-NLS-1$ + try { + if (w != null) + w.close(); + } catch (IOException ex) { + Log.e(LOG_OSMO_TAG, "Failed to close stream " + tmp, ex); //$NON-NLS-1$ + } + } + + } + }); + } + }) + .setNegativeButton(R.string.cancel_button, null); + + textView.setText("http://"); //$NON-NLS-1$ + builder.setView(textView); + + builder.show(); + ArrayAdapter adapter; + try { + adapter = new ArrayAdapter(this, + android.R.layout.simple_dropdown_item_1line, + res.get(1, TimeUnit.SECONDS)); + textView.setAdapter(adapter); + } catch (ExecutionException e) { + // Ignored + Log.e(LOG_OSMO_TAG, "Error while parsing recent URLs", e); //$NON-NLS-1$ + } catch (TimeoutException e) { + Log.e(LOG_OSMO_TAG, "It took too long to parse recent URLs", e); //$NON-NLS-1$ + } catch (InterruptedException e) { + Log.e(LOG_OSMO_TAG, "Interrupted while parsing recent URLs", e); //$NON-NLS-1$ + } + + return true; + } + + private final ExecutorService service = Executors.newSingleThreadExecutor(); + + private final Set allRecentURLs = new HashSet(); + + private synchronized void addAllRecentURLs(Collection urlsToAdd) { + allRecentURLs.addAll(urlsToAdd); + } + + private synchronized Collection getAllRecentURLs() { + return new ArrayList(allRecentURLs); + } + + private final static Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); //$NON-NLS-1$ + + /** + * Opens a new activity to select a file + * + * @return true if activity has been selected + */ + private boolean openFileDialog() { + String title = getResources().getString(R.string.pleaseSelectAFile); + Uri uriDefaultDir = Uri.fromFile(new File(gpacConfig.getGpacAppDirectory())); + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_PICK); + // Files and directories + intent.setDataAndType(uriDefaultDir, "vnd.android.cursor.dir/lysesoft.andexplorer.file"); //$NON-NLS-1$ + // Optional filtering on file extension. + intent.putExtra("browser_filter_extension_whitelist", OSMO_REGISTERED_FILE_EXTENSIONS); //$NON-NLS-1$ + // Title + intent.putExtra("explorer_title", title); //$NON-NLS-1$ + + try { + startActivityForResult(intent, PICK_FILE_REQUEST); + return true; + } catch (ActivityNotFoundException e) { + // OK, lets try with another one... (it includes out bundled one) + intent = new Intent("org.openintents.action.PICK_FILE"); //$NON-NLS-1$ + intent.setData(uriDefaultDir); + intent.putExtra(FileChooserActivity.TITLE_PARAMETER, title); + intent.putExtra("browser_filter_extension_whitelist", OSMO_REGISTERED_FILE_EXTENSIONS); //$NON-NLS-1$ + try { + startActivityForResult(intent, PICK_FILE_REQUEST); + return true; + } catch (ActivityNotFoundException ex) { + // Not found neither... We build our own dialog to display error + // Note that this should happen only if we did not embed out own intent + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage("Impossible to find an Intent to choose a file... Cannot open file !") //$NON-NLS-1$ + .setCancelable(true) + .setPositiveButton(R.string.cancel_button, null); + AlertDialog alert = builder.create(); + alert.show(); + return false; + } + } + } + + // --------------------------------------- + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + if (requestCode == PICK_FILE_REQUEST) { + if (resultCode == RESULT_OK) { + Uri uri = intent.getData(); + if (uri != null) { + String url = uri.toString(); + String file = "file://"; //$NON-NLS-1$ + if (url.startsWith(file)) { + url = uri.getPath(); + } + Log.i(LOG_OSMO_TAG, "Requesting opening local file " + url); //$NON-NLS-1$ + openURLasync(url); + } + } + } + } + + private String currentURL; + + private void openURLasync(final String url) { + service.execute(new Runnable() { + + @Override + public void run() { + mGLView.connect(url); + currentURL = url; + runOnUiThread(new Runnable() { + + @Override + public void run() { + setTitle(getResources().getString(R.string.titleWithURL, url)); + } + }); + } + }); + } + + // --------------------------------------- + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + } + + // --------------------------------------- + + private int last_orientation = 0; + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + switch (item.getItemId()) { + case R.id.open_url: + return openURL(); + case R.id.open_file: + // newGame(); + return openFileDialog(); + case R.id.cleanCache: + return cleanCache(); + case R.id.showVirtualKeyboard: + showKeyboard(!keyboardIsVisible); + return true; + case R.id.reloadFile: + openURLasync(currentURL); + return true; + case R.id.autoRotate: + if (item.isChecked()) { + item.setChecked(false); + last_orientation = this.getRequestedOrientation(); + int ornt = getResources().getConfiguration().orientation; + if (ornt == Configuration.ORIENTATION_PORTRAIT) + this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + else + this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else { + item.setChecked(true); + this.setRequestedOrientation(last_orientation); + } + return true; + case R.id.enableDebug: + if (item.isChecked()) { + item.setChecked(false); + mGLView.setGpacLogs("all@error"); //$NON-NLS-1$ + } else { + item.setChecked(true); + mGLView.setGpacLogs("sync:codec:dash:media@debug:container@warning"); //$NON-NLS-1$ + } + return true; + case R.id.setAsStartupFile: { + AlertDialog.Builder b = new AlertDialog.Builder(this); + b.setTitle(R.string.setAsStartupFileTitle); + if (currentURL != null) { + b.setMessage(getResources().getString(R.string.setAsStartupFileMessage, currentURL)); + b.setPositiveButton(R.string.setAsStartupFileYes, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + mGLView.setGpacPreference(CFG_STARTUP_CATEGORY, CFG_STARTUP_NAME, currentURL); + } + }); + } else { + b.setMessage(getResources().getString(R.string.setAsStartupFileMessageNoURL)); + } + b.setNegativeButton(R.string.setAsStartupFileNo, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + b.setNeutralButton(R.string.setAsStartupFileNull, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + mGLView.setGpacPreference(CFG_STARTUP_CATEGORY, CFG_STARTUP_NAME, null); + } + }); + b.show(); + return true; + } + case R.id.resetGpacConfig: { + AlertDialog.Builder b = new AlertDialog.Builder(this); + b.setCancelable(true) + .setTitle(R.string.resetGpacConfig) + .setMessage(R.string.resetGpacConfigMessage) + .setNegativeButton(R.string.cancel_button, null) + .setPositiveButton(R.string.ok_button, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + setShouldDeleteGpacConfig(true); + deleteConfigIfNeeded(); + } + }) + .show(); + return true; + } + + case R.id.configFileEditor: { + Intent i = new Intent(Osmo4.this, ConfigFileEditorActivity.class); + startActivity(i); + return true; + } + + case R.id.about: { + Dialog d = new Dialog(this); + d.setTitle(R.string.aboutTitle); + d.setCancelable(true); + d.setContentView(R.layout.about_dialog); + d.show(); + } + return true; + + case R.id.preferences:{ + Intent i = new Intent(Osmo4.this, PrefsActivity.class); + startActivity(i); + return true; + } + + case R.id.quit: + if ( mGLView != null ) + mGLView.disconnect(); + this.finish(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + /** + * Cleans GPAC cache + * + * @return true if successful + */ + protected boolean cleanCache() { + final CharSequence oldTitle = getTitle(); + runOnUiThread(new Runnable() { + + @Override + public void run() { + startupProgress.setTitle(R.string.cleaningCache); + startupProgress.setMessage(getResources().getString(R.string.cleaningCache, + gpacConfig.getGpacCacheDirectory())); + startupProgress.setProgress(0); + startupProgress.setIndeterminate(false); + startupProgress.show(); + } + }); + service.submit(new Runnable() { + + @Override + public void run() { + File dir = new File(gpacConfig.getGpacCacheDirectory()); + if (!dir.exists() || !dir.canRead() || !dir.canWrite() || !dir.isDirectory()) { + return; + } + File files[] = dir.listFiles(); + int i = 0; + for (File f : files) { + if (f.isFile()) + if (!f.delete()) { + Log.w(LOG_OSMO_TAG, "Failed to delete file " + f); //$NON-NLS-1$ + } else { + Log.v(LOG_OSMO_TAG, f + " has been deleted"); //$NON-NLS-1$ + } + final int percent = (++i) * 100 / files.length; + runOnUiThread(new Runnable() { + + @Override + public void run() { + startupProgress.setProgress(percent); + } + }); + } + runOnUiThread(new Runnable() { + + @Override + public void run() { + startupProgress.setProgress(100); + startupProgress.setTitle(oldTitle); + startupProgress.dismiss(); + } + }); + } + }); + return true; + } + + private void deleteConfigIfNeeded() { + if (isShouldDeleteGpacConfig()) { + Log.i(LOG_OSMO_TAG, "Deleting GPAC config file..."); //$NON-NLS-1$ + File f = gpacConfig.getGpacConfigFile(); + if (f.exists() && !f.delete()) { + Log.e(LOG_OSMO_TAG, "Failed to delete " + f.getAbsolutePath()); //$NON-NLS-1$ + } + f = gpacConfig.getGpacLastRevFile(); + if (f.exists() && !f.delete()) { + Log.e(LOG_OSMO_TAG, "Failed to delete " + f.getAbsolutePath()); //$NON-NLS-1$ + } + } + } + + // --------------------------------------- + @Override + protected void onDestroy() { + deleteConfigIfNeeded(); + service.shutdown(); + logger.onDestroy(); + synchronized (this) { + if (wl != null) + wl.release(); + } + Log.d(LOG_OSMO_TAG, "Disconnecting instance..."); //$NON-NLS-1$ + mGLView.disconnect(); + Log.d(LOG_OSMO_TAG, "Destroying GPAC instance..."); //$NON-NLS-1$ + mGLView.destroy(); + // Deleteing is done two times if GPAC fails to shutdown by crashing... + deleteConfigIfNeeded(); + super.onDestroy(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + // Handle the back button + if (keyCode == KeyEvent.KEYCODE_BACK) { + // Ask the user if they want to quit + new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.quit) + .setMessage(R.string.really_quit) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + + // Stop the activity + if ( mGLView != null ) + mGLView.disconnect(); + Osmo4.this.finish(); + } + + }) + .setNegativeButton(R.string.no, null) + .show(); + + return true; + } else { + return super.onKeyDown(keyCode, event); + } + + } + + // --------------------------------------- + // private void loadAllModules() { + // Log.i(LOG_OSMO_TAG, "Start loading all modules..."); //$NON-NLS-1$ + // long start = System.currentTimeMillis(); + // byte buffer[] = new byte[1024]; + // int[] ids = getAllRawResources(); + // String currentRevision = "$Revision$"; //$NON-NLS-1$ + // File revisionFile = gpacConfig.getGpacLastRevFile(); + // boolean fastStartup = false; + // // We check if we already copied all the modules once without error... + // if (revisionFile.exists() && revisionFile.canRead()) { + // BufferedReader r = null; + // try { + // r = new BufferedReader(new InputStreamReader(new FileInputStream(revisionFile), DEFAULT_ENCODING), + // DEFAULT_BUFFER_SIZE); + // String rev = r.readLine(); + // if (currentRevision.equals(rev)) { + // fastStartup = true; + // } + // } catch (IOException ignored) { + // } finally { + // // Exception or not, always close the stream... + // if (r != null) + // try { + // r.close(); + // } catch (IOException ignored) { + // } + // } + // } + // boolean noErrors = true; + // final StringBuilder errorsMsg = new StringBuilder(); + // for (int i = 0; i < ids.length; i++) { + // OutputStream fos = null; + // InputStream ins = null; + // String fn = gpacConfig.getGpacModulesDirectory() + m_modules_list[i] + ".so"; //$NON-NLS-1$ + // File finalFile = new File(fn); + // // If file has already been copied, not need to do it again + // if (fastStartup && finalFile.exists() && finalFile.canRead()) { + // Log.i(LOG_OSMO_TAG, "Skipping " + finalFile); //$NON-NLS-1$ + // continue; + // } + // try { + // final String msg = getResources().getString(R.string.copying_native_libs, + // finalFile.getName(), + // finalFile.getParent()); + // runOnUiThread(new Runnable() { + // + // @Override + // public void run() { + // startupProgress.setIndeterminate(false); + // startupProgress.setMessage(msg); + // } + // }); + // Log.i(LOG_OSMO_TAG, "Copying resource " + ids[i] + " to " //$NON-NLS-1$//$NON-NLS-2$ + // + finalFile.getAbsolutePath()); + // File tmpFile = new File(fn + ".tmp"); //$NON-NLS-1$ + // int read; + // ins = new BufferedInputStream(getResources().openRawResource(ids[i]), DEFAULT_BUFFER_SIZE); + // fos = new BufferedOutputStream(new FileOutputStream(tmpFile), DEFAULT_BUFFER_SIZE); + // while (0 < (read = ins.read(buffer))) { + // fos.write(buffer, 0, read); + // } + // ins.close(); + // ins = null; + // fos.close(); + // fos = null; + // if (!tmpFile.renameTo(finalFile)) { + // if (finalFile.exists() && finalFile.delete() && !tmpFile.renameTo(finalFile)) + // Log.e(LOG_OSMO_TAG, "Failed to rename " + tmpFile.getAbsolutePath() + " to " //$NON-NLS-1$//$NON-NLS-2$ + // + finalFile.getAbsolutePath()); + // } + // final int percent = i * 10000 / ids.length; + // runOnUiThread(new Runnable() { + // + // @Override + // public void run() { + // startupProgress.setProgress(percent); + // } + // }); + // } catch (IOException e) { + // noErrors = false; + // String msg = "IOException for resource : " + ids[i]; //$NON-NLS-1$ + // errorsMsg.append(msg).append('\n').append(finalFile.getAbsolutePath()).append('\n'); + // errorsMsg.append(e.getLocalizedMessage()); + // Log.e(LOG_OSMO_TAG, msg, e); + // } finally { + // if (ins != null) { + // try { + // ins.close(); + // } catch (IOException e) { + // Log.e(LOG_OSMO_TAG, "Error while closing read stream", e); //$NON-NLS-1$ + // } + // } + // if (fos != null) { + // try { + // fos.close(); + // } catch (IOException e) { + // Log.e(LOG_OSMO_TAG, "Error while closing write stream", e); //$NON-NLS-1$ + // } + // } + // } + // } + // // If no error during copy, fast startup will be enabled for next time + // if (noErrors && !fastStartup) { + // BufferedWriter w = null; + // try { + // w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(revisionFile), DEFAULT_ENCODING), + // DEFAULT_BUFFER_SIZE); + // w.write(currentRevision); + // w.write('\n'); + // // We add the date as second line to ease debug in case of problem + // w.write(String.valueOf(new Date())); + // } catch (IOException ignored) { + // } finally { + // if (w != null) + // try { + // w.close(); + // } catch (IOException ignored) { + // } + // } + // } else { + // if (!noErrors) { + // setShouldDeleteGpacConfig(true); + // displayMessage(errorsMsg.toString(), "Errors while copying modules !", GF_Err.GF_IO_ERR.value); //$NON-NLS-1$ + // } + // } + // Log.i(LOG_OSMO_TAG, "Done loading all modules, took " + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$ //$NON-NLS-2$ + // startupProgress.setProgress(100); + // startupProgress.setIndeterminate(true); + // runOnUiThread(new Runnable() { + // + // @Override + // public void run() { + // setTitle(LOG_OSMO_TAG); + // } + // }); + // } + + // private int[] getAllRawResources() throws RuntimeException { + // R.raw r = new R.raw(); + // + // java.lang.reflect.Field fields[] = R.raw.class.getDeclaredFields(); + // final int ids[] = new int[fields.length]; + // m_modules_list = new String[fields.length]; + // + // try { + // for (int i = 0; i < fields.length; i++) { + // java.lang.reflect.Field f = fields[i]; + // ids[i] = f.getInt(r); + // m_modules_list[i] = f.getName(); + // Log.i(LOG_OSMO_TAG, "R.raw." + f.getName() + " = 0x" + Integer.toHexString(ids[i])); //$NON-NLS-1$ //$NON-NLS-2$ + // } + // } catch (IllegalArgumentException e) { + // throw new RuntimeException(e); + // } catch (IllegalAccessException e) { + // throw new RuntimeException(e); + // } + // + // return ids; + // } + + // --------------------------------------- + + private String lastDisplayedMessage; + + private void displayPopup(final CharSequence message, final CharSequence title) { + final String fullMsg = getResources().getString(R.string.displayPopupFormat, title, message); + synchronized (this) { + // In case of an error message, always popup it + if (fullMsg.equals(lastDisplayedMessage) && !title.equals("Error")) + return; + lastDisplayedMessage = fullMsg; + } + runOnUiThread(new Runnable() { + + @Override + public void run() { + Toast toast = Toast.makeText(Osmo4.this, fullMsg, Toast.LENGTH_SHORT); + toast.show(); + } + }); + + } + + /** + * @see com.gpac.Osmo4.GpacCallback#displayMessage(String, String, int) + */ + @Override + public void displayMessage(final String message, final String title, final int status) { + if (status == GF_Err.GF_OK.value) { + // displayPopup(message, title); + Log.d(LOG_OSMO_TAG, message); + } else { + runOnUiThread(new Runnable() { + + @Override + public void run() { + StringBuilder sb = new StringBuilder(); + sb.append(GF_Err.getError(status)); + sb.append(' '); + sb.append(title); + AlertDialog.Builder builder = new AlertDialog.Builder(Osmo4.this); + builder.setTitle(sb.toString()); + sb.append('\n'); + sb.append(message); + builder.setMessage(sb.toString()); + builder.setCancelable(true); + builder.setPositiveButton(R.string.ok_button, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + try { + builder.create().show(); + } catch (WindowManager.BadTokenException e) { + // May happen when we close the window and there are still somes messages + Log.e(LOG_OSMO_TAG, "Failed to display Message " + sb.toString(), e); //$NON-NLS-1$ + } + } + }); + } + } + + /** + * @see com.gpac.Osmo4.GpacCallback#onLog(int, int, String) + */ + @Override + public void onLog(int level, int module, String message) { + logger.onLog(level, module, message); + if (level == Log.ERROR) + displayPopup(message, "Error"); + } + + /** + * @see com.gpac.Osmo4.GpacCallback#onProgress(java.lang.String, int, int) + */ + @Override + public void onProgress(final String msg, final int done, final int total) { + if (Log.isLoggable(LOG_OSMO_TAG, Log.DEBUG)) + Log.d(LOG_OSMO_TAG, "Setting progress to " + done + "/" + total + ", message=" + msg); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + runOnUiThread(new Runnable() { + + @Override + public void run() { + // GPAC sometimes return total = 0 + if (total < 1) { + setProgressBarIndeterminate(true); + } else { + int progress = done * 10000 / (total < 1 ? 1 : total); + if (progress > 9900) + progress = 10000; + setProgressBarIndeterminate(false); + setProgress(progress); + } + } + }); + } + + /** + * @see com.gpac.Osmo4.GpacCallback#onGPACReady() + */ + @Override + public void onGPACReady() { + startupProgress.dismiss(); + Log.i(LOG_OSMO_TAG, "GPAC is ready"); //$NON-NLS-1$ + } + + /** + * @see com.gpac.Osmo4.GpacCallback#onGPACError(java.lang.Throwable) + */ + @Override + public void onGPACError(final Throwable e) { + startupProgress.dismiss(); + Log.e(LOG_OSMO_TAG, "GPAC Error", e); //$NON-NLS-1$ + runOnUiThread(new Runnable() { + + @Override + public void run() { + // In such case, we force GPAC Configuration file deletion + setShouldDeleteGpacConfig(true); + StringBuilder sb = new StringBuilder(); + sb.append("Failed to init GPAC due to "); //$NON-NLS-1$ + sb.append(e.getClass().getSimpleName()); + AlertDialog.Builder builder = new AlertDialog.Builder(Osmo4.this); + builder.setTitle(sb.toString()); + sb.append('\n'); + sb.append("Description: "); //$NON-NLS-1$ + sb.append(e.getLocalizedMessage()); + sb.append('\n'); + sb.append("Revision: $Revision$"); //$NON-NLS-1$ + sb.append("\nConfiguration information :\n") //$NON-NLS-1$ + .append(gpacConfig.getConfigAsText()); + builder.setMessage(sb.toString()); + builder.setCancelable(true); + builder.setPositiveButton(R.string.ok_button, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.create().show(); + } + }); + } + + @Override + protected void onPause() { + super.onPause(); + if (mGLView != null) + mGLView.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + if (mGLView != null) + mGLView.onResume(); + } + + /** + * @see com.gpac.Osmo4.GpacCallback#setCaption(java.lang.String) + */ + @Override + public void setCaption(final String newCaption) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + setTitle(newCaption); + } + }); + } + + /** + * @see android.app.Activity#onStop() + */ + @Override + protected void onStop() { + Log.i(LOG_OSMO_TAG, "onStop called on activity"); //$NON-NLS-1$ + super.onStop(); + } + + /** + * @see com.gpac.Osmo4.GpacCallback#showKeyboard(boolean) + */ + @Override + public void showKeyboard(boolean showKeyboard) { + this.keyboardIsVisible = showKeyboard; + + runOnUiThread(new Runnable() { + + @Override + public void run() { + InputMethodManager mgr = ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)); + if ( Osmo4.this.keyboardIsVisible ){ + mgr.showSoftInput(mGLView, 0); + getActionBar().hide(); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + } + else{ + mgr.hideSoftInputFromWindow(mGLView.getWindowToken(), 0); + getActionBar().show(); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + } + //mgr.toggleSoftInputFromWindow(mGLView.getWindowToken(), 0, 0); + mGLView.requestFocus(); + } + }); + } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + // When the window loses focus (e.g. the action overflow is shown), + // cancel any pending hide action. When the window gains focus, + // hide the system UI. + if (hasFocus) { + delayedHide(INITIAL_HIDE_DELAY); + } else { + mHideHandler.removeMessages(0); + } + } + + public void setLogFile(String logfile) { + logger.setEnableLogOnDisk(true); + logger.setLogFile(logfile); + logger.onCreate(); + } + + private void hideSystemUI() { + mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_LOW_PROFILE + | View.SYSTEM_UI_FLAG_IMMERSIVE); + } + + private void showSystemUI() { + mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } + + private final Handler mHideHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + hideSystemUI(); + } + }; + + private void delayedHide(int delayMillis) { + mHideHandler.removeMessages(0); + mHideHandler.sendEmptyMessageDelayed(0, delayMillis); + } + /** + * @see com.gpac.Osmo4.GpacCallback#sensorSwitch(boolean) + */ + @Override + public void sensorSwitch(final boolean active) { + if(active){ + //this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + sensors.registerSensors(); + Log.i(LOG_OSMO_TAG, "Received Register Sensors call"); + }else{ + sensors.unregisterSensors(); + Log.i(LOG_OSMO_TAG, "Received Un-Register Sensors call"); + } + } + +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4GLSurfaceView.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4GLSurfaceView.java new file mode 100644 index 0000000..f45aa9e --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4GLSurfaceView.java @@ -0,0 +1,234 @@ +package com.gpac.Osmo4; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.widget.Toast; + +/** + * The view represented the blitted contents by libgpac + * + * @version $Revision$ + * + */ +public class Osmo4GLSurfaceView extends GLSurfaceView implements GPACInstanceInterface { + + private final static String LOG_GL_SURFACE = Osmo4GLSurfaceView.class.getSimpleName(); + + /** + * Constructor + * + * @param context + */ + public Osmo4GLSurfaceView(Context context) { + super(context); + setEGLContextClientVersion(2); + setPreserveEGLContextOnPause(true); + setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS); + setFocusable(true); + setFocusableInTouchMode(true); + } + + private Osmo4Renderer gpacRenderer; + + /** + * Set the renderer + * + * @param renderer + */ + public void setRenderer(Osmo4Renderer renderer) { + synchronized (this) { + this.gpacRenderer = renderer; + } + super.setRenderer(renderer); + setRenderMode(RENDERMODE_CONTINUOUSLY); + } + + private synchronized Osmo4Renderer getGpacRenderer() { + return gpacRenderer; + } + + private GPACInstance getInstance() { + Osmo4Renderer r = getGpacRenderer(); + if (r == null) + return null; + return r.getInstance(); + } + + // ------------------------------------ + @Override + public boolean onTouchEvent(final MotionEvent event) { + if(!Osmo4.isUIvisible() | Osmo4.IskeyboardVisible()){ + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.motionEvent(event); + } + }); + return true; + } + return false; + } + + /** + * Should we handle this key in GPAC ? + * + * @param keyCode + * @param event + * @return + */ + private static final long TIME_INTERVAL = 500; + private static long mBackPressed; + private static boolean handleInGPAC(int keyCode, KeyEvent event) { + if (event.isSystem() && keyCode!=KeyEvent.KEYCODE_BACK) + return false; + switch (keyCode) { + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MENU: + return false; + case KeyEvent.KEYCODE_BACK: + if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()){ + return false; + } + return true; + default: + return true; + } + } + + @Override + public boolean onKeyDown(final int keyCode, final KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) Toast.makeText(Osmo4.context, "Press back button twice to exit", Toast.LENGTH_SHORT).show(); + if (handleInGPAC(keyCode, event)) { + Log.d(LOG_GL_SURFACE, "onKeyDown = " + keyCode); //$NON-NLS-1$ + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.eventKey(keyCode, event, true, event.getUnicodeChar()); + } + }); + return true; + } + return false; + } + + // ------------------------------------ + @Override + public boolean onKeyUp(final int keyCode, final KeyEvent event) { + if (handleInGPAC(keyCode, event)) { + Log.d(LOG_GL_SURFACE, "onKeyUp =" + keyCode); //$NON-NLS-1$ + if (keyCode == KeyEvent.KEYCODE_BACK) mBackPressed = System.currentTimeMillis(); + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.eventKey(keyCode, event, false, event.getUnicodeChar()); + } + }); + return true; + } + return false; + } + + @Override + public void onResume() { + if (getInstance() != null) + super.onResume(); + } + + @Override + public void onPause() { + if (getInstance() != null) + super.onPause(); + } + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#connect(java.lang.String) + */ + @Override + public void connect(final String url) { + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.connect(url); + } + }); + } + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#disconnect() + */ + @Override + public void disconnect() { + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.disconnect(); + } + }); + } + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#destroy() + */ + @Override + public void destroy() { + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.destroy(); + } + }); + } + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#setGpacPreference(String, String, String) + */ + @Override + public void setGpacPreference(final String category, final String name, final String value) { + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.setGpacPreference(category, name, value); + } + }); + } + + /** + * @see com.gpac.Osmo4.GPACInstanceInterface#setGpacLogs(String tools_at_levels) + */ + @Override + public void setGpacLogs(final String tools_at_levels) { + queueEvent(new Runnable() { + + @Override + public void run() { + GPACInstance instance = getInstance(); + if (instance != null) + instance.setGpacLogs(tools_at_levels); + } + }); + } +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4Renderer.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4Renderer.java new file mode 100644 index 0000000..a5065b9 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Osmo4Renderer.java @@ -0,0 +1,98 @@ +package com.gpac.Osmo4; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; +import android.opengl.GLES20; +import android.opengl.GLSurfaceView; +import android.util.Log; + +/** + * The renderer + * + * @version $Revision$ + * + */ +public class Osmo4Renderer implements GLSurfaceView.Renderer { + + private final GpacConfig gpacConfig; + + private final static String LOG_RENDERER = Osmo4Renderer.class.getSimpleName(); + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + if (instance == null) { + try { + Log.i(LOG_RENDERER, "Creating instance from thread " + Thread.currentThread()); //$NON-NLS-1$ + instance = new GPACInstance(callback, 320, 430, gpacConfig, urlToLoad); + } catch (com.gpac.Osmo4.GPACInstanceInterface.GpacInstanceException e) { + Log.e(LOG_RENDERER, "Failed to create new GPAC instance !"); //$NON-NLS-1$ + instance = null; + callback.onGPACError(e); + return; + } + if (callback != null) + callback.onGPACReady(); + } + } + + private GPACInstance instance = null; + + private final String urlToLoad; + + /** + * @return the urlToLoad + */ + public synchronized String getUrlToLoad() { + return urlToLoad; + } + + /** + * Constructor + * + * @param callback + * @param gpacConfig + * @param urlToLoad The URL to load at startup, can be null + */ + public Osmo4Renderer(GpacCallback callback, GpacConfig gpacConfig, String urlToLoad) { + this.callback = callback; + this.urlToLoad = urlToLoad; + this.gpacConfig = gpacConfig; + } + + private final GpacCallback callback; + + @Override + public void onSurfaceChanged(GL10 gl, int w, int h) { + // gl.glViewport(0, 0, w, h); + if (instance != null) { + Log.i(LOG_RENDERER, "Surface changed from thread " + Thread.currentThread()); //$NON-NLS-1$ + instance.resize(w, h); + } + } + + private int frames; + + private long startFrame = System.currentTimeMillis(); + + @Override + public void onDrawFrame(GL10 gl) { + if (instance != null) { + frames++; + if (frames % 1000 == 0) { + long now = System.currentTimeMillis(); + Log.i(LOG_RENDERER, "Frames Per Second = " + ((now - startFrame) / 1000) + " fps"); //$NON-NLS-1$//$NON-NLS-2$ + this.startFrame = now; + } + instance.render(); + } + } + + /** + * Get the current GPAC Instance + * + * @return the instance + */ + synchronized GPACInstance getInstance() { + return instance; + } +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Preview.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Preview.java new file mode 100644 index 0000000..2724ab6 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/Preview.java @@ -0,0 +1,694 @@ +package com.gpac.Osmo4; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.util.List; +import android.app.Activity; +import android.app.ProgressDialog; +import android.graphics.Bitmap; +import android.graphics.PixelFormat; +import android.hardware.Camera; +import android.hardware.Camera.Parameters; +import android.hardware.Camera.Size; +import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.widget.LinearLayout; + +/** + * Manage camera preview and frame grabbing. + * + * Mostly copied from + * + * {@link "http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html"} + */ +public class Preview { + + private static final String TAG = "Preview"; //$NON-NLS-1$ + + private Camera mCamera = null; + + private Size mPreviewSize = null; + + private int nBuffers = 0; + + private int mBufferSize = 0; + + private int mPreviewFormat = 0; + + private PreviewHandler mPreviewHandler = null; + + private boolean takePicture = false; + + private boolean mPreviewing = false; + + private boolean isPortrait = false; + + private int width = 0; + + private int height = 0; + + private int bitsPerPixel = 0; + + public static Activity context = null; + + private boolean previewRequested = false; + private boolean previewStarted = false; + + private CameraPreview camPreview = null; + + // Native functions + private native void processFrameBuf(byte[] data); + + Preview() { + mCamera = Camera.open(); + if (mCamera == null) { + Log.e(TAG, "Camera failed to open"); //$NON-NLS-1$ + return; + } + setParameters(mCamera.getParameters()); + mCamera.release(); + mCamera = null; + } + + private class CameraPreview implements SurfaceHolder.Callback { + + private SurfaceHolder holder = null; + private SurfaceView mCamSV; + private boolean hasCallback = false; + //private LinearLayout cam_view; + + private ProgressDialog cameraOpening; + + + public CameraPreview(final Activity context) { + Log.v(TAG, "CameraPreview: Constructor..."); + + cameraOpening = new ProgressDialog(context); + cameraOpening.setCancelable(false); + cameraOpening.setIndeterminate(true); + cameraOpening.setMessage("Opening camera"); + cameraOpening.setTitle("Osmo4 camera"); + + //cam_view = (LinearLayout)context.findViewById(R.id.surface_camera); + + //cam_view.addView(mCamSV); + + context.runOnUiThread(new Runnable() { + + @Override + public void run() { + cameraOpening.show(); + } + }); + + mCamSV = (SurfaceView)context.findViewById(R.id.surface_camera); + + holder = mCamSV.getHolder(); + holder.addCallback(CameraPreview.this); + holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + + hasCallback = true; + + context.runOnUiThread(new Runnable() { + + @Override + public void run() { + Log.i(TAG, "CameraPreview: Set visible..."); + mCamSV.setVisibility(View.VISIBLE); + Log.i(TAG, "CameraPreview: Set visible done"); + } + }); + Log.v(TAG, "CameraPreview: Constructor done"); + } + + public void startPreview() + { + Log.v(TAG, "CameraPreview: Start preview..."); + mCamera.startPreview(); + context.runOnUiThread(new Runnable() { + @Override + public void run() { + //Log.i(TAG, "CameraPreview: Set gone..."); + Log.i(TAG, "CameraPreview: Dismiss"); + //mCamSV.setVisibility(View.GONE); + cameraOpening.dismiss(); + //Log.i(TAG, "CameraPreview: Set gone done"); + } + }); + mPreviewHandler = new PreviewHandler("CameraPreviewHandler"); + mPreviewing = true; + Log.v(TAG, "CameraPreview: Start preview done"); + } + + public void stopPreview() + { + if ( hasCallback ) + { + Log.v(TAG, "CameraPreview: Remove callback"); + holder.removeCallback(CameraPreview.this); + //cam_view.removeView(mCamSV); + //mCamSV = null; + context.runOnUiThread(new Runnable() { + @Override + public void run() { + Log.i(TAG, "CameraPreview: Set gone..."); + mCamSV.setVisibility(View.GONE); + Log.i(TAG, "CameraPreview: Set gone done"); + } + }); + hasCallback = false; + } + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + Log.v(TAG, "CameraPreview: Surface changed "+width+"x"+height+" ..."); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + try { + Log.v(TAG, "CameraPreview: Surface created..."); + mCamera.setPreviewDisplay(holder); + if ( previewRequested ) { + startPreview(); + previewRequested = false; + } + else + previewStarted = true; + Log.v(TAG, "CameraPreview: Surface created done"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + // TODO Auto-generated method stub + + } + + @Override + public void finalize() + { + stopPreview(); + camPreview = null; + } + } + + @Override + protected void finalize() { + stopCamera(); + } + + /** + * Set up the camera parameters and begin the preview. + * + * @param isPortrait True if camera orientation is portrait. False if it is landscape. + * @return True if successful. + */ + public boolean initializeCamera(boolean isPortrait) { + + this.isPortrait = isPortrait; + + // Open camera + if (mCamera == null) { + Log.i(TAG, "Open camera..."); //$NON-NLS-1$ + mCamera = Camera.open(); + if (mCamera == null) { + Log.w(TAG, "Camera failed to open"); //$NON-NLS-1$ + return false; + } + } + + pausePreview(); + + // Get parameters + mCamera.setParameters(setParameters(mCamera.getParameters())); + width = mPreviewSize.width; + height = mPreviewSize.height; + if (mPreviewSize == null || mPreviewFormat == 0) { + Log.e(TAG, "Preview size or format error"); //$NON-NLS-1$ + return false; + } + + // Define buffer size + PixelFormat pixelinfo = new PixelFormat(); + PixelFormat.getPixelFormatInfo(mPreviewFormat, pixelinfo); + bitsPerPixel = pixelinfo.bitsPerPixel; + mBufferSize = mPreviewSize.width * mPreviewSize.height * pixelinfo.bitsPerPixel / 8; + Log.d(TAG, "Pixelsize = " + pixelinfo.bitsPerPixel + " Buffersize = " + mBufferSize); //$NON-NLS-1$//$NON-NLS-2$ + nBuffers = 1; + + // Initialize frame grabbing + // mPreviewHandler = new PreviewHandler("CameraPreviewHandler"); + + context.runOnUiThread(new Runnable() { + + @Override + public void run() { + camPreview = new CameraPreview(context); + //camPreview.setVisibility(View.INVISIBLE); + } + }); + + Log.d(TAG, "Camera preview started"); //$NON-NLS-1$ + return true; + } + + /** + * Get the size of Preview + * + * @return null if camera not setup + */ + public Size getPreviewSize() { + return mPreviewSize; + } + + /** + * Get the preview format + * + * @return 0 if not initialized + */ + public int getPreviewFormat() { + return mPreviewFormat; + } + + /** + * Get the Image height + * + * @return -1 if not initialized, the height otherwise + */ + public int getImageHeight() { + Size sz = getPreviewSize(); + if (sz == null) + return -1; + return sz.height; + } + + /** + * Get the image Width if set + * + * @return -1 if not initialized, the width otherwise + */ + public int getImageWidth() { + Size sz = getPreviewSize(); + if (sz == null) + return -1; + return sz.width; + } + + /** + * Get the bits per pixel + * + * @return 0 if not initialized + */ + public int getBitsPerPixel() { + return bitsPerPixel; + } + + /** + * Stop preview and release the camera. Because the CameraDevice object is not a shared resource, it is very + * important to release it when the activity is paused. + */ + public void stopCamera() { + Log.v(TAG, "stopCamera()"); //$NON-NLS-1$ + + if ( mPreviewing ) + pausePreview(); + if (mCamera != null) { + camPreview.stopPreview(); + camPreview = null; + mCamera.release(); + mCamera = null; + previewRequested = false; + previewStarted = false; + Log.v(TAG, "Camera released"); //$NON-NLS-1$ + } + } + + /** + * Stop the processing thread + */ + public void pausePreview() { + Log.v(TAG, "pausePreview()"); + if ( mPreviewing ) { + if ( mPreviewHandler != null ) + mPreviewHandler.stopPreview(); + mPreviewHandler = null; + mCamera.stopPreview(); + mPreviewing = false; + Log.v(TAG, "Camera preview stopped"); //$NON-NLS-1$ + } + } + + /** + * Restart the processing thread + */ + public void resumePreview() { + Log.v(TAG, "resumePreview()"); + if ( previewStarted ) { + camPreview.startPreview(); + previewStarted = false; + } + else + previewRequested = true; + } + + /** + * Set preferred mPreviewSize and mPrevieformat and return adapted camera parameters. If mPreviewSize == null or + * mPreviewFormat == 0 then some error has occurred. + * + * @param parameters the parameters to set + * + * @return the parameters set as argument + * @throws IllegalArgumentException if argument is null + */ + protected Camera.Parameters setParameters(Camera.Parameters parameters) throws IllegalArgumentException { + if (parameters == null) + throw new IllegalArgumentException("parameters must not be null"); //$NON-NLS-1$ + // Get preview size + mPreviewSize = parameters.getPreviewSize(); + parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); + Log.d(TAG, "PreviewSize: " + mPreviewSize.width + 'x' + mPreviewSize.height); //$NON-NLS-1$ + + // Get preview format + mPreviewFormat = PixelFormat.YCbCr_420_SP; + // getOptimalPreviewFormat(parameters + // .getSupportedPreviewFormats()); + if (mPreviewFormat == 0) { + Log.e(TAG, "Cannot set mPreviewFormat"); //$NON-NLS-1$ + } else { + Log.d(TAG, "Previewformat: " + mPreviewFormat); //$NON-NLS-1$ + parameters.setPreviewFormat(mPreviewFormat); + } + + Log.d(TAG, "PreviewFrameRate: " + parameters.getPreviewFrameRate()); //$NON-NLS-1$ + parameters.setPreviewFrameRate(parameters.getPreviewFrameRate()); + parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO ); + + return parameters; + } + + + private Size getOptimalPreviewSize(List sizes, int w, int h) { + final double ASPECT_TOLERANCE = 0.1; + double targetRatio = (double) w / h; + if (sizes == null) return null; + + Size optimalSize = null; + double minDiff = Double.MAX_VALUE; + + int targetHeight = h; + + // Try to find an size match aspect ratio and size + for (Size size : sizes) { + double ratio = (double) size.width / size.height; + if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + + // Cannot find the one match the aspect ratio, ignore the requirement + if (optimalSize == null) { + minDiff = Double.MAX_VALUE; + for (Size size : sizes) { + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + } + return optimalSize; + } + + /** + * Return preferred camera preview format. At the moment, PixelFormat.YCbCr_420_SP is required. + * + * @param formats Supported formats: Camera.Parameters.getSupportedPreviewFormats() + * @return Image format 17 (YUV420SP) if supported, 0 if not. + */ + protected int getOptimalPreviewFormat(List formats) { + int optFormat = 0; + for (Integer format : formats) { + int intFormat = format.intValue(); + Log.d(TAG, "supported image format: " + intFormat); //$NON-NLS-1$ + if (intFormat == PixelFormat.YCbCr_420_SP) { + optFormat = intFormat; + } + } + return optFormat; + } + + /** + * Process a frame grabbed from the camera. + * + * @param data Image from camera in YUV420SP format. + */ + protected void processFrame(byte[] data) { + if (takePicture) { + // Test: decode and save image + int[] rgbBuf = decodeYUV420SP(data, width, height); + saveImageToFile(rgbBuf, width, height); + takePicture = false; + } + // End of test + + // Send data to C library + processFrameBuf(data); + } + + /** + * Save an RGB image to the file /sdcard/image.jpg + * + * @param rgbBuffer RGB image buffer to save + * @param width Width of the image + * @param height Height of the image + */ + public void saveImageToFile(int[] rgbBuffer, int width, int height) { + Bitmap bm = Bitmap.createBitmap(rgbBuffer, width, height, Bitmap.Config.RGB_565); + + // Save image + String path = Environment.getExternalStorageDirectory().toString(); + OutputStream fOut = null; + File file = new File(path, "image.jpg"); //$NON-NLS-1$ + try { + try { + fOut = new FileOutputStream(file); + bm.compress(Bitmap.CompressFormat.JPEG, 100, fOut); + fOut.flush(); + } catch (IOException e1) { + Log.e(TAG, "io error file output stream while writing", e1); //$NON-NLS-1$ + e1.printStackTrace(); + } finally { + if (fOut != null) + fOut.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Convert an image from YUV to RGB format. + * + * @param yuv420sp YUV format image, as a byte array + * @param width Width of the image + * @param height Height of the image + * @return RGB image as an int array + */ + public int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) { + final int frameSize = width * height; + + int rgb[] = new int[width * height]; + for (int j = 0, yp = 0; j < height; j++) { + int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; + for (int i = 0; i < width; i++, yp++) { + int y = (0xff & (yuv420sp[yp])) - 16; + if (y < 0) + y = 0; + if ((i & 1) == 0) { + v = (0xff & yuv420sp[uvp++]) - 128; + u = (0xff & yuv420sp[uvp++]) - 128; + } + + int y1192 = 1192 * y; + int r = (y1192 + 1634 * v); + int g = (y1192 - 833 * v - 400 * u); + int b = (y1192 + 2066 * u); + + if (r < 0) + r = 0; + else if (r > 262143) + r = 262143; + if (g < 0) + g = 0; + else if (g > 262143) + g = 262143; + if (b < 0) + b = 0; + else if (b > 262143) + b = 262143; + rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); + } + } + return rgb; + } + + /** + * Interface between PreviewHandler and mCamera + * + * @param cb + */ + private void setPreviewCallbackWithBuffer(Camera.PreviewCallback cb) { + // call mCamera.setPreviewCallbackWithBuffer(cb) + // if cb != null then also add a callback buffers + try { + if (bufferWorks) { + if (cb != null) { + for (int i = 0; i < nBuffers; i++) { + // TODO level 8: mCamera.addCallbackBuffer(new + // byte[mBufferSize]); + camAddCbBuffer.invoke(mCamera, new byte[mBufferSize]); + } + } + // TODO level 8: mCamera.setPreviewCallbackWithBuffer(cb); + camSetPreview.invoke(mCamera, cb); + } else if (cb != null) { + mCamera.setOneShotPreviewCallback(cb); + } + } catch (Exception e) { + Log.e(TAG, "setPreviewCallbackWithBuffer failed:" + e, e); //$NON-NLS-1$ + } + } + + private int fps_max_count = 100; + + private int fps_count = 1; + + private long fps_last = -42; + + private void addCallbackBuffer(byte[] buffer) { + if (--fps_count == 0) { + long now = System.currentTimeMillis(); + if (fps_last != -42) { + float fps = fps_max_count * 1000.f / (now - fps_last); + Log.i(TAG, "fps: " + fps); //$NON-NLS-1$ + fps_max_count = (int) (5.f * fps); + } + fps_count = fps_max_count; + fps_last = now; + } + try { + if (bufferWorks) { + camAddCbBuffer.invoke(mCamera, buffer); + } else { + mCamera.setOneShotPreviewCallback(mPreviewHandler); + } + } catch (Exception e) { + Log.e(TAG, "addCallbackBuffer failed: " + e); //$NON-NLS-1$ + } + } + + /* + * TODO: for level 8 all the stuff below becomes obsolete Use reflection for accessing hidden methods + */ + private static final Method getCamAddCallbackBuffer() { + try { + return Class.forName("android.hardware.Camera").getMethod("addCallbackBuffer", byte[].class); //$NON-NLS-1$//$NON-NLS-2$ + } catch (Exception e) { + Log.e(TAG, "No addCallbackBuffer: " + e); //$NON-NLS-1$ + } + return null; + } + + private static final Method getCamSetPreviewCallbackWithBuffer() { + try { + return Class.forName("android.hardware.Camera").getMethod("setPreviewCallbackWithBuffer", //$NON-NLS-1$ //$NON-NLS-2$ + Camera.PreviewCallback.class); + } catch (Exception e) { + Log.e(TAG, "No setPreviewCallbackWithBuffer: " + e); //$NON-NLS-1$ + } + return null; + } + + /** + * Handles camera frame buffer callbacks in a new thread. + */ + protected class PreviewHandler extends HandlerThread implements Camera.PreviewCallback { + + private Handler mHandler; + + private boolean stopped = false; + + PreviewHandler(String name) { + super(name); + mHandler = null; + start(); + } + + @Override + public void onPreviewFrame(final byte[] data, final Camera camera) { + synchronized (this) { + if (mHandler != null && camera == mCamera) { + mHandler.post(new Runnable() { + + @Override + public void run() { + if (!stopped) { + processFrame(data); + if (mHandler != null) { + addCallbackBuffer(data); + } + } + } + }); + } + } + + } + + @Override + synchronized protected void onLooperPrepared() { + synchronized (this) { + Log.v(TAG, "onLooperPrepared()"); //$NON-NLS-1$ + if (stopped == false) { + mHandler = new Handler(); + Log.d(TAG, "frame processing start"); //$NON-NLS-1$ + setPreviewCallbackWithBuffer(this); + // mCamera.setPreviewCallback(this); + } + } + } + + synchronized private void stopPreview() { + synchronized (this) { + stopped = true; + if (mHandler != null) { + Log.d(TAG, "frame processing stop"); //$NON-NLS-1$ + setPreviewCallbackWithBuffer(null); + // mCamera.setPreviewCallback(null); + mHandler = null; + } + } + } + } + + private static final Method camAddCbBuffer = getCamAddCallbackBuffer(); + + private static final Method camSetPreview = getCamSetPreviewCallbackWithBuffer(); + + private static final boolean bufferWorks = camAddCbBuffer != null && camSetPreview != null; +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/SensorServices.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/SensorServices.java new file mode 100644 index 0000000..a3f41b5 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/SensorServices.java @@ -0,0 +1,385 @@ +package com.gpac.Osmo4; + +import android.content.Context; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; + + +import java.util.TimerTask; +import java.util.Timer; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +/** + * Class for 360video sensors management + * + * @author Emmanouil Potetsianakis + * @version $Revision$ + */ +public class SensorServices implements SensorEventListener, GPACInstanceInterface { + + //automatically set to true, if TYPE_ROTATION_VECTOR sensor is detected + //NOTE: this is a composite sensor; does not work with fusion + private boolean useRotationVector; + +//Startof Options + private static final int SENSOR_DELAY = SensorManager.SENSOR_DELAY_FASTEST; // 0: SENSOR_DELAY_FASTEST, 1: SENSOR_DELAY_GAME, 2: SENSOR_DELAY_UI, 3: SENSOR_DELAY_NORMAL + + private static final boolean USE_ORIENTATION_FILTER = true; //if true smoothSensorMeasurement is applied to getOrientation result + private static final boolean USE_ORIENTATION_THRESHOLD = true; //if true keepOrientation() discards results within the error margin + + //the lower the value, the more smoothing is applied (lower response) - set to 1.0 for no filter + private static final float ORIENTATION_FILTER_LVL = 0.04f; + //threshold to discard orientation x, y, z + private static final float[] ORIENTATION_THRESHOLD = {0.2f, 0.02f, 0.02f}; +//Endof Options + + + private static SensorManager sensorManager; + + private static Sensor accelerometer; //base sensor + private static Sensor magnetometer; //base sensor + private static Sensor rotationSensor; //composite sensor + + protected Osmo4Renderer rend; + private Display displayDev; + + private boolean newOrientation = false; //auto-set to true when new Rotation arrives (from acc), auto-set to false when rotation is sent to player + + private Timer fuseTimer = new Timer(); + + private float[] acceleration = {0.0f, 0.0f, 0.0f}; //holds acceleration values (g) + private float[] magnetic = {0.0f, 0.0f, 0.0f}; //holds magnetic field values (μT) + private float[] rotationValues = {0.0f, 0.0f, 0.0f};//holds rotation vector + private float[] orientation = {0.0f, 0.0f, 0.0f}; //from acc+magn + private float[] lastOrient = {0.0f, 0.0f, 0.0f}, prevOrient; + + private float rotationMx[] = new float[9]; + private float rotationMxRaw[] = new float[9]; + + private static final String LOG_TAG = "GPAC SensorServices"; + private static final float _PI_ = (float) Math.PI; + + + /** + * Constructor (initialize sensors) + * + * @param context The parent Context + * @return SensorServices object + */ + public SensorServices(Context context) { + //init sensors + sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + rotationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); + + //init the rest + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + displayDev = wm.getDefaultDisplay(); + + //check sensor availability and select + if(rotationSensor!=null){ + useRotationVector = true; + return; + }else{ + Log.w(LOG_TAG, "No Rotation Vector composit sensor found - Switching to Acc+Magn sensors"); + } + + if (magnetometer == null || accelerometer == null){ + Log.e(LOG_TAG, "No Accelerometer and/or Magnetic Field sensors found"); //TODOk handle this - rollback to manual navigation + } + + } + + public void setRenderer(Osmo4Renderer renderer) { + rend = renderer; + } + + /** + * Register sensors to start receiving data + */ + public void registerSensors() { + + if(rotationSensor!=null){ + sensorManager.registerListener(this, rotationSensor, SENSOR_DELAY); + Log.i(LOG_TAG, "Using Rotation Vector sensor for 360navigation"); + return; + } + + if(magnetometer != null && accelerometer != null){ + sensorManager.registerListener(this, magnetometer, SENSOR_DELAY); + sensorManager.registerListener(this, accelerometer, SENSOR_DELAY); + Log.i(LOG_TAG, "Using Acceleration & Magnetic Field sensors for 360navigation"); + } + } + + //TODOk we do not handle this yet - there is an issue with onResume (not working) and onPause (working) + public void unregisterSensors() { + sensorManager.unregisterListener(this); + } + + /** + * We calculate rotation/orientation on new acc measurements + **/ + @Override + public void onSensorChanged(SensorEvent event) { + + boolean newevent = false; + + switch (event.sensor.getType()) { + case Sensor.TYPE_ROTATION_VECTOR: + rotationValues = event.values.clone(); + newOrientation = calculateRotationMx(); + if (newOrientation){ + float[] tmpOrient = new float[3]; + SensorManager.getOrientation(rotationMx, tmpOrient); + rend.getInstance().onOrientationChange(-tmpOrient[0], tmpOrient[1], -tmpOrient[2]); + } + return; + case Sensor.TYPE_ACCELEROMETER: + newevent=true; + acceleration = event.values.clone(); + break; + case Sensor.TYPE_MAGNETIC_FIELD: + newevent=true; + magnetic = event.values.clone(); + break; + default: + return; + } + if(newevent){ + newOrientation = calculateRotationMx(); + if (!newOrientation) return; + calculateOrientation(); + updateOrientation(); + } + } + + /** + * Calculate orientation X,Y,Z from Acc and Magn + * Orientation is stored in prevOrient + * Rotation matrix is stored in rotationMx + * + * @return true if rotationMatrix was updated + */ + private boolean calculateRotationMx() { + boolean gotRotation = false; + + + if(useRotationVector){ + try { + SensorManager.getRotationMatrixFromVector(rotationMxRaw, rotationValues); + gotRotation = true; + } catch (Exception e) { + gotRotation = false; + Log.e(LOG_TAG, "Error getting rotation matrix" + e.getMessage()); + } + }else{ + try { + gotRotation = SensorManager.getRotationMatrix(rotationMxRaw, null, acceleration, magnetic); + } catch (Exception e) { + gotRotation = false; + Log.e(LOG_TAG, "Error getting rotation matrix" + e.getMessage()); + } + } + + if (gotRotation) { + //NOTE: the rotation considered is according to device natural orientation + //and it might NOT be the same as the screen orientation + switch (displayDev.getRotation()) { + case 1: //Surface.ROTATION_90 + rotationMx = rotationMxRaw.clone(); + break; + case 2: //Surface.ROTATION_180 + SensorManager.remapCoordinateSystem(rotationMxRaw, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, rotationMx); + break; + case 3: //Surface.ROTATION_270 + SensorManager.remapCoordinateSystem(rotationMxRaw, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y, rotationMx); + break; + case 0: //no rotation (= Surface.ROTATION_0) + SensorManager.remapCoordinateSystem(rotationMxRaw, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X, rotationMx); + break; + } + } + + return gotRotation; + } + + private void calculateOrientation() { + float[] tmpOrient = new float[3]; + SensorManager.getOrientation(rotationMx, tmpOrient); + orientation = tmpOrient.clone(); + } + + private void updateOrientation() { + lastOrient = orientation.clone(); + boolean refreshOrientation = true; + if (USE_ORIENTATION_THRESHOLD) { + refreshOrientation = keepOrientation(lastOrient, prevOrient); + } + + if (refreshOrientation) { + if (USE_ORIENTATION_FILTER) { + prevOrient = smoothSensorMeasurement(lastOrient, prevOrient); + } else { + prevOrient = lastOrient; + } + } + + //NOTE: we invert yaw and roll (for 360 navigation) + rend.getInstance().onOrientationChange(-prevOrient[0], prevOrient[1], -prevOrient[2]); + newOrientation = false; + } + + private float[] getRotationMxFromOrientation(float[] o) { + float[] xM = new float[9]; + float[] yM = new float[9]; + float[] zM = new float[9]; + + float sinX = (float) Math.sin(o[1]); + float cosX = (float) Math.cos(o[1]); + float sinY = (float) Math.sin(o[2]); + float cosY = (float) Math.cos(o[2]); + float sinZ = (float) Math.sin(o[0]); + float cosZ = (float) Math.cos(o[0]); + + // rotation about x-axis (pitch) + xM[0] = 1.0f; + xM[1] = 0.0f; + xM[2] = 0.0f; + xM[3] = 0.0f; + xM[4] = cosX; + xM[5] = sinX; + xM[6] = 0.0f; + xM[7] = -sinX; + xM[8] = cosX; + + // rotation about y-axis (roll) + yM[0] = cosY; + yM[1] = 0.0f; + yM[2] = sinY; + yM[3] = 0.0f; + yM[4] = 1.0f; + yM[5] = 0.0f; + yM[6] = -sinY; + yM[7] = 0.0f; + yM[8] = cosY; + + // rotation about z-axis (azimuth) + zM[0] = cosZ; + zM[1] = sinZ; + zM[2] = 0.0f; + zM[3] = -sinZ; + zM[4] = cosZ; + zM[5] = 0.0f; + zM[6] = 0.0f; + zM[7] = 0.0f; + zM[8] = 1.0f; + + // rotation order is y, x, z (roll, pitch, azimuth) + float[] resultMatrix = multiplyMx(xM, yM); + resultMatrix = multiplyMx(zM, resultMatrix); + return resultMatrix; + } + + private float[] multiplyMx(float[] A, float[] B) { + float[] result = new float[9]; + + result[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6]; + result[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7]; + result[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8]; + + result[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6]; + result[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7]; + result[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8]; + + result[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6]; + result[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7]; + result[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8]; + + return result; + } + + private static boolean keepOrientation(float[] in, float[] out) { + + if (out == null) return true; + + for (int i = 0; i < in.length; i++) { + if (Math.abs(in[i] - out[i]) > ORIENTATION_THRESHOLD[i]) return true; + } + + return false; + } + + + private static float[] smoothSensorMeasurement(float[] in, float[] out) { + + if (out == null) return in; + + float[] output = {0.0f, 0.0f, 0.0f}; + float diff = 0.0f; + + + for (int i = 0; i < in.length; i++) { + + diff = (in[i] - out[i]); + + if (Math.abs(diff) > Math.PI) { + float diff_f = 0.0f; + if (diff > Math.PI) { + diff = 2 * _PI_ - diff; + diff_f = out[i] - ORIENTATION_FILTER_LVL * diff; + if (diff_f < -Math.PI) { + output[i] = (2 * _PI_ + diff_f); + } else { + output[i] = diff_f; + } + } else if (diff < -Math.PI) { + diff = 2 * _PI_ + diff; + diff_f = out[i] + ORIENTATION_FILTER_LVL * diff; + if (diff_f > Math.PI) { + output[i] = -2 * _PI_ + diff_f; + } else { + output[i] = diff_f; + } + + } + + } else { + output[i] = out[i] + ORIENTATION_FILTER_LVL * diff; + } + } + + return output; + } + + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + //required - but not used + } + + @Override + public native void setGpacLogs(String tools_at_levels); + + @Override + public native void setGpacPreference(String category, String name, String value); + + @Override + public void destroy() { + } + + @Override + public void connect(String pop) { + } + + @Override + public void disconnect() { + } + +} \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditor.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditor.java new file mode 100644 index 0000000..6fbb33d --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditor.java @@ -0,0 +1,326 @@ +package com.gpac.Osmo4.extra; + +import android.content.Context; +import android.util.Log; + +import com.gpac.Osmo4.GpacConfig; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + + +public class ConfigFileEditor { + + private String TAG = "ConfigFileEditor"; + + private String ATTRIBUTE_NAME = "name"; + private String ATTRIBUTE_TYPE = "type"; + private String ATTRIBUTE_DEFAULT = "default"; + private String ATTRIBUTE_USAGE = "usage"; + + private final String TYPE_PATH = "path"; + private final String TYPE_FILENAME = "filename"; + private final String TYPE_STRING = "string"; + private final String TYPE_BOOLEAN = "boolean"; + private final String TYPE_UINT = "uint"; + + private File configFile; + + private XmlPullParserFactory xmlFactoryObject; + private XmlPullParser parser; + private GpacConfig config; + private Context context; + + public ConfigFileEditor(Context context) { + this.context = context; + config = new GpacConfig(context); + configFile = new File(config.getGpacConfigDirectory(), "GPAC.cfg"); + + try { + xmlFactoryObject = XmlPullParserFactory.newInstance(); + } catch (XmlPullParserException e) { + Log.v(TAG, "Cannot create xml parser new instance"); + e.printStackTrace(); + } + } + + private void start() { + InputStream inputStream = null; + try { + inputStream = context.getAssets().open("configuration.xml"); + parser = xmlFactoryObject.newPullParser(); + parser.setInput(inputStream, null); + } catch (XmlPullParserException | IOException e) { + e.printStackTrace(); + } + } + + /** + * get all the keys from the xml file + * + * @return array of all keys + */ + public String[] getAllKeys() { + ArrayList list = new ArrayList<>(); + int event = 0; + try { + start(); + event = parser.getEventType(); + + while (event != XmlPullParser.END_DOCUMENT) { + String name = parser.getName(); + switch (event) { + case XmlPullParser.START_TAG: + if (name.equals("key")) { + String attrName = parser.getAttributeValue(null, ATTRIBUTE_NAME).trim(); + list.add(attrName); + } + break; + + case XmlPullParser.END_TAG: + break; + } + event = parser.next(); + } + } catch (XmlPullParserException e) { + Log.e(TAG, "XML Exception"); + e.printStackTrace(); + } catch (IOException e) { + Log.e(TAG, "IOException"); + e.printStackTrace(); + } + return list.toArray(new String[0]); + } + + /** + * get all the attributes for a single key + * + * @param key key to find attributes for + * @return Attribute object with all attributes set. If key not found, returns null + */ + public Attribute getAllAttributesForKey(String key) { + Attribute attribute = null; + String section = null; + String attrName = null; + String attrType = null; + String attrDfault = null; + String attrUsage = null; + StringBuilder attrDescription = new StringBuilder(); + + boolean keyFound = false; + boolean exit = false; + int depth = 0; + int event; + try { + start(); //start from beginning + event = parser.getEventType(); + while (event != XmlPullParser.END_DOCUMENT && !exit) { + String name = parser.getName(); + switch (event) { + case XmlPullParser.START_TAG: + + if(name.equals("section")){ + section = parser.getAttributeValue(null, ATTRIBUTE_NAME); + } + if (name.equals("key") && parser.getAttributeValue(null, ATTRIBUTE_NAME).equals(key)) { + attrName = parser.getAttributeValue(null, ATTRIBUTE_NAME); + attrType = parser.getAttributeValue(null, ATTRIBUTE_TYPE); + attrDfault = parser.getAttributeValue(null, ATTRIBUTE_DEFAULT); + attrUsage = parser.getAttributeValue(null, ATTRIBUTE_USAGE); + keyFound = true; + } + if(keyFound) + ++depth; + if (keyFound && depth > 1){ + attrDescription.append("<").append(parser.getName()).append(">"); + } + break; + + case XmlPullParser.TEXT: + if(keyFound) { + attrDescription.append(parser.getText().trim()); + } + break; + + case XmlPullParser.END_TAG: + if(keyFound) + --depth; + + if (keyFound && depth > 0){ + attrDescription.append(""); + } + + if(name.equals("key") && keyFound){ + attribute = new Attribute(section, attrName, attrType, attrDfault, attrUsage, attrDescription.toString()); + keyFound = false; + exit = true; + } + break; + } + event = parser.next(); + } + } catch (XmlPullParserException e) { + Log.e(TAG, "XML Exception"); + e.printStackTrace(); + } catch (IOException e) { + Log.e(TAG, "IOException"); + e.printStackTrace(); + } + return attribute; + } + + + /** + * get value for key from the config file + * + * @param key key to find + * @return the value from the config file, if key not found, returns null. + */ + public String getValue(String key) { + String line; + try { + BufferedReader br = new BufferedReader(new FileReader(configFile)); + + while ((line = br.readLine()) != null) { + String[] parts = line.split("="); + if(parts[0].trim().equals(key)){ + return parts[1]; + } + } + br.close(); + } catch (FileNotFoundException e) { + Log.e(TAG, "GPAC.cfg not found"); + e.printStackTrace(); + } catch (IOException e) { + Log.e(TAG, "IO Exception while parsing GPAC.cfg"); + e.printStackTrace(); + } + return null; + } + + /** + * checks if the new value is valid or not. + * @param type type of newValue + * @param newValue value to check + * @return true if valid, otherwise false + */ + public boolean isValueValid(String type, String newValue) { + + switch (type) { + /* case TYPE_PATH: + case TYPE_FILENAME: + File file = new File(newValue); + if(!file.exists()){ + Log.e(TAG, "The path does not exist : " + newValue); + return false; + } + break; + */ + + case TYPE_BOOLEAN: + return newValue.equals("yes") || newValue.equals("no"); + + case TYPE_UINT: + try { + int num = Integer.parseInt(newValue); + return num >= 0; + } catch(Exception e) { + Log.e(TAG, "The type is uint but value provided: "+ newValue); + return false; + } + + case TYPE_STRING: + default: + return true; + + } + } + + /** + * set the value in the config file + * @param key key for newValue + * @param newValue + */ + public void setValue(String key, String newValue) { + + String line = null; + try { + File tempFile = new File(config.getGpacConfigDirectory(), "temp.cfg"); + BufferedReader br = new BufferedReader(new FileReader(configFile)); + BufferedWriter bw = new BufferedWriter(new FileWriter(tempFile)); + + while ((line = br.readLine()) != null) { + String parts[] = line.split("="); + if(parts[0].equals(key)){ + line = key + "=" + newValue; + } + bw.write(line); + bw.newLine(); + } + br.close(); + bw.close(); + + if(!configFile.delete()) { + Log.e(TAG, "Cannot delete config file"); + } + + if(!tempFile.renameTo(configFile)) { + Log.e(TAG, "Cannot rename temp file to GPAC.cfg"); + } + + } catch (IOException e) { + Log.e(TAG, "IOException "); + e.printStackTrace(); + } + } + + class Attribute { + private String section; + private String name; + private String type; + private String dfault; + private String usage; + private String desciption; + + public Attribute(String section, String name, String type, String dfault, String usage, String desciption) { + this.section = section; + this.name = name; + this.type = type; + this.dfault = dfault; + this.usage = usage; + this.desciption = desciption; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public String getDefault() { + return dfault; + } + + public String getUsage() { + return usage; + } + + public String getDesciption() { + return desciption; + } + } + +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditorActivity.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditorActivity.java new file mode 100644 index 0000000..49c6f86 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/ConfigFileEditorActivity.java @@ -0,0 +1,150 @@ +package com.gpac.Osmo4.extra; + +import android.app.Activity; +import android.os.Bundle; +import android.text.Html; +import android.text.method.ScrollingMovementMethod; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.gpac.Osmo4.R; + + +public class ConfigFileEditorActivity extends Activity { + + private String TAG = "ConfigFileEditorActivity"; + + private AutoCompleteTextView optionsTextView; + private TextView typeTextView; + private TextView dfaultTextView; + private TextView usageTextView; + private TextView descriptionTextView; + private TextView currentValueTextView; + private EditText newValueEditText; + private Button saveButton; + private String currentValue; + + private ConfigFileEditor editor; + private ConfigFileEditor.Attribute attribute; + private String currentName; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_config_file_editor); + + optionsTextView = (AutoCompleteTextView) findViewById(R.id.optionsTextView); + typeTextView = (TextView) findViewById(R.id.typeTextView); + dfaultTextView = (TextView) findViewById(R.id.dfaultTextView); + usageTextView = (TextView) findViewById(R.id.usageTextView); + descriptionTextView = (TextView) findViewById(R.id.descriptionTextView); + currentValueTextView = (TextView) findViewById(R.id.currentValueEditText); + newValueEditText = (EditText) findViewById(R.id.newValueEditText); + saveButton = (Button) findViewById(R.id.saveButton); + + descriptionTextView.setMovementMethod(new ScrollingMovementMethod()); + editor = new ConfigFileEditor(this); + final String[]keys = editor.getAllKeys(); + final ArrayAdapter adapter = new ArrayAdapter<>(this, + android.R.layout.simple_dropdown_item_1line, keys); + optionsTextView.setAdapter(adapter); + + optionsTextView.setOnClickListener(onOptionTextViewClick); + optionsTextView.setOnItemClickListener(onItemClick); + optionsTextView.setOnKeyListener(keyListener); + saveButton.setOnClickListener(onSaveButtonClick); + } + + private View.OnClickListener onOptionTextViewClick = new View.OnClickListener() { + @Override + public void onClick(View v) { + optionsTextView.showDropDown(); + } + }; + + private AdapterView.OnItemClickListener onItemClick = new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + setAllFields((String) parent.getItemAtPosition(position)); + } + }; + + private View.OnKeyListener keyListener = new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if(event.getAction() == KeyEvent.ACTION_DOWN && + keyCode == KeyEvent.KEYCODE_ENTER) { + currentName = optionsTextView.getText().toString().trim(); + if (currentName == null || currentName.equals("")) { + return false; + } else { + optionsTextView.dismissDropDown(); + setAllFields(currentName); + return true; + } + } + return false; + } + }; + + private View.OnClickListener onSaveButtonClick = new View.OnClickListener() { + @Override + public void onClick(View v) { + String newValue = newValueEditText.getText().toString().trim(); + if(newValue == null || newValue.equals("")) { + Toast.makeText(ConfigFileEditorActivity.this, "New value is empty", Toast.LENGTH_LONG).show(); + return; + } + + if(currentValue == null){ + Log.e(TAG, getString(R.string.noKey)); + return; + } + + if (newValue.equals(currentValue)){ + Toast.makeText(ConfigFileEditorActivity.this, getString(R.string.noChange), Toast.LENGTH_LONG).show(); + return; + } + + if(editor.isValueValid(currentName, newValue)){ + editor.setValue(currentName, newValue); + setAllFields(currentName); + Toast.makeText(ConfigFileEditorActivity.this, getString(R.string.valueUpdated), Toast.LENGTH_LONG).show(); + newValueEditText.setText(""); + } else { + Toast.makeText(ConfigFileEditorActivity.this, getString(R.string.valueNotValid), Toast.LENGTH_LONG).show(); + Log.e(TAG, getString(R.string.valueNotValid)); + } + + } + }; + + private void setAllFields(String key) { + currentName = key; + attribute = editor.getAllAttributesForKey(key); + if(attribute == null) { + Log.v(TAG, "no attribute found for the given key in the option file : " + key); + typeTextView.setText(getString(R.string.noAttribute)); + dfaultTextView.setText(getString(R.string.noAttribute)); + usageTextView.setText(getString(R.string.noAttribute)); + descriptionTextView.setText(getString(R.string.noAttribute)); + } + else { + typeTextView.setText(attribute.getType()); + dfaultTextView.setText(attribute.getDefault()); + usageTextView.setText(attribute.getUsage()); + descriptionTextView.setText(Html.fromHtml(attribute.getDesciption(), null, new XMLTagHandler())); + Log.v(TAG, "description " + attribute.getDesciption()); + } + currentValue = editor.getValue(key); + if (currentValue == null) currentValueTextView.setText(getString(R.string.noKey)); else currentValueTextView.setText(currentValue); + } +} \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileArrayAdapter.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileArrayAdapter.java new file mode 100644 index 0000000..33330db --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileArrayAdapter.java @@ -0,0 +1,144 @@ +package com.gpac.Osmo4.extra; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v7.widget.CardView; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.gpac.Osmo4.R; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; + + +public class FileArrayAdapter extends RecyclerView.Adapter { + + public interface OnItemClickListener { + void onItemClick(View view, int position); + } + + private ArrayList files; + private OnItemClickListener onItemClickListener; + private Context context; + + public FileArrayAdapter(ArrayList files, OnItemClickListener onItemClickListener, Context context) { + this.files = files; + this.onItemClickListener = onItemClickListener; + this.context = context; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ListItemViewHolder( + LayoutInflater + .from(parent.getContext()) + .inflate(R.layout.list_item_file_chooser, parent, false)); + } + + @Override + public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) { + + ListItemViewHolder holder = (ListItemViewHolder) viewHolder; + File file = getItem(position); + holder.title.setText(file.getName()); + holder.lastModified.setText(new Date(file.lastModified()).toString()); + setIcon(file, holder); + holder.cardView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onItemClickListener.onItemClick(v, position); + } + }); + } + + public void setIcon(File file, ListItemViewHolder holder) { + + String extension; + Drawable drawable = null; + + try { + extension = FileManager.getExtension(file.getAbsolutePath()); + + if (file.isFile()) { + switch (extension) { + + case ".c": case ".cpp": case ".doc": case ".docx": case ".exe": + case ".h": case ".html": case ".java": case ".log": case ".txt": + case ".pdf": case ".ppt": case ".xls": + drawable = ContextCompat.getDrawable(context, R.drawable.ic_file); + break; + + case ".3ga": case ".aac": case ".mp3": case ".m4a": case ".ogg": + case ".wav": case ".wma": + drawable = ContextCompat.getDrawable(context, R.drawable.ic_audio); + break; + + case ".3gp": case ".avi": case ".mpg": case ".mpeg": case ".mp4": + case ".mkv": case ".webm": case ".wmv": case ".vob": + drawable = ContextCompat.getDrawable(context, R.drawable.ic_video); + break; + + case ".ai": case ".bmp": case ".exif": case ".gif": case ".jpg": + case ".jpeg": case ".png": case ".svg": + drawable = ContextCompat.getDrawable(context, R.drawable.ic_image); + break; + + case ".rar": case ".zip": case ".ZIP": + drawable = ContextCompat.getDrawable(context, R.drawable.ic_compressed); + break; + + default: + drawable = ContextCompat.getDrawable(context, R.drawable.ic_error); + break; + } + } else if (file.isDirectory()) { + drawable = ContextCompat.getDrawable(context, R.drawable.ic_folder); + } else drawable = ContextCompat.getDrawable(context, R.drawable.ic_error); + + } catch (Exception e) { + drawable = ContextCompat.getDrawable(context, R.drawable.ic_error); + } + drawable = DrawableCompat.wrap(drawable); + holder.icon.setImageDrawable(drawable); + } + + @Override + public int getItemCount() { + return files.size(); + } + + public File getItem(int position) { + return files.get(position); + } + + static class ListItemViewHolder extends RecyclerView.ViewHolder { + + CardView cardView; + TextView title; + TextView lastModified; + ImageView icon; + LinearLayout linearLayout; + + public ListItemViewHolder(View itemView) { + super(itemView); + cardView = (CardView) itemView.findViewById(R.id.cardView); + title = (TextView) itemView.findViewById(R.id.title); + icon = (ImageView) itemView.findViewById(R.id.icon); + linearLayout = (LinearLayout) itemView.findViewById(R.id.linearLayout); + lastModified = (TextView) itemView.findViewById(R.id.lastModified); + } + } + + public ArrayList getFiles() { + return files; + } +} \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserActivity.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserActivity.java new file mode 100644 index 0000000..c2bd94f --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserActivity.java @@ -0,0 +1,97 @@ +/** + * $URL$ + *

+ * $LastChangedBy$ - $LastChangedDate$ + */ +package com.gpac.Osmo4.extra; + +import android.Manifest; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.FragmentManager; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.view.Menu; +import android.view.MenuItem; + +import com.gpac.Osmo4.R; + + +public class FileChooserActivity extends Activity { + + final String FILE_CHOOSER_FRAGMENT = "fileChooserFragment"; + public final static String TITLE_PARAMETER = "org.openintents.extra.TITLE"; + + private FragmentManager fm; + private FileChooserFragment fileChooserFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_file_chooser); + + requestForPermission(); + fm = getFragmentManager(); + + if (fm.findFragmentById(R.id.fileChooserLayout) == null) { + fileChooserFragment = new FileChooserFragment(); + fm.beginTransaction() + .add(R.id.fileChooserLayout, fileChooserFragment, FILE_CHOOSER_FRAGMENT) + .addToBackStack(FILE_CHOOSER_FRAGMENT) + .commit(); + } + } + + private void requestForPermission() { + + if (ContextCompat.checkSelfPermission(FileChooserActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + + if (ActivityCompat.shouldShowRequestPermissionRationale(FileChooserActivity.this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + + promptForPermissionsDialog(getString(R.string.requestPermissionStorage), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ActivityCompat.requestPermissions(FileChooserActivity.this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 100); + } + }); + } else { + ActivityCompat.requestPermissions(FileChooserActivity.this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 100); + } + } + } + + private void promptForPermissionsDialog(String message, DialogInterface.OnClickListener onClickListener) { + new AlertDialog.Builder(FileChooserActivity.this) + .setMessage(message) + .setPositiveButton(getString(R.string.yes), onClickListener) + .setNegativeButton(getString(R.string.no), null) + .create() + .show(); + } + + @Override + public void onBackPressed() { + fileChooserFragment.backPressed(); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } + +} \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserFragment.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserFragment.java new file mode 100644 index 0000000..c197830 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileChooserFragment.java @@ -0,0 +1,160 @@ +package com.gpac.Osmo4.extra; + +import android.Manifest; +import android.app.ActionBar; +import android.app.Activity; +import android.app.Fragment; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import com.gpac.Osmo4.R; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; + +public class FileChooserFragment extends Fragment { + + private final String PREF_SHOW_HIDDEN_FILES = "SHOW_HIDDEN_FILES"; + private final String PREF_SORT_ORDER = "SORT_ORDER"; + private final String PREF_SORT_BY = "SORT_BY"; + private final String PREF_FOLDERS_FIRST = "FOLDERS_FIRST"; + + private File currDir; + private ArrayList files; + private FileArrayAdapter adapter; + private SharedPreferences prefs; + private ActionBar actionBar; + + private boolean showHiddenFiles; + private String sortOrder; + private String sortBy; + private boolean foldersFirst; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) + currDir = new File("/"); + + else currDir = Environment.getExternalStorageDirectory(); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_file_chooser, container, false); + setRetainInstance(true); + + RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); + GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2); + gridLayoutManager.setOrientation(GridLayoutManager.VERTICAL); + files = new ArrayList<>(); + actionBar = getActivity().getActionBar(); + adapter = new FileArrayAdapter(files, onItemClickListenerCallback, getActivity()); + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + setPreferences(); + recyclerView.setLayoutManager(gridLayoutManager); + populateList(currDir); + recyclerView.setAdapter(adapter); + return view; + } + + @Override + public void onResume() { + super.onResume(); + setPreferences(); + } + + private void setPreferences() { + showHiddenFiles = prefs.getBoolean(PREF_SHOW_HIDDEN_FILES, true); + sortOrder = prefs.getString(PREF_SORT_ORDER, FileManager.SORT_ORDER_ASC); + sortBy = prefs.getString(PREF_SORT_BY, FileManager.SORT_BY_NAME); + foldersFirst = prefs.getBoolean(PREF_FOLDERS_FIRST, true); + } + + public void backPressed() { + if (currDir.getAbsolutePath().equals("/") || !currDir.getParentFile().canRead()) + getActivity().finish(); + else populateList(currDir.getParentFile()); + } + + private FileArrayAdapter.OnItemClickListener onItemClickListenerCallback = new FileArrayAdapter.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + File f = adapter.getItem(position); + if (f.isDirectory()) + onDirectoryClick(f); + else if (f.isFile()) + onFileClick(f); + } + }; + + private void onFileClick(File f) { + Intent data = new Intent(); + data.setData(Uri.fromFile(f)); + getActivity().setResult(Activity.RESULT_OK, data); + getActivity().finish(); + } + + private void onDirectoryClick(File f) { + if (f.canRead()) + populateList(f); + else Toast.makeText(getActivity(), "Cannot read " + f, Toast.LENGTH_LONG).show(); + } + + public void populateList(File file) { + new BackgroundWork(file).execute(); + } + + class BackgroundWork extends AsyncTask { + + private File file; + public BackgroundWork(File file) { + this.file = file; + } + + @Override + protected Boolean doInBackground(File... params) { + + if (!file.canRead()) { + Toast.makeText(getActivity(), "Directory cannot be read", Toast.LENGTH_LONG).show(); + return false; + } + files.clear(); + ArrayList list = new ArrayList<>(Arrays.asList(file.listFiles())); + + files.addAll( + FileManager.sort( + showHiddenFiles? list : FileManager.removeHiddenFiles(list), + sortOrder, + sortBy, + foldersFirst + )); + currDir = file; + return true; + } + + @Override + protected void onPostExecute(Boolean aVoid) { + actionBar.setTitle(file.getAbsolutePath()); + adapter.notifyDataSetChanged(); + } + } +} \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileManager.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileManager.java new file mode 100644 index 0000000..32ef8ec --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/FileManager.java @@ -0,0 +1,189 @@ +package com.gpac.Osmo4.extra; + +import android.os.Build; +import android.support.annotation.Nullable; +import android.util.Log; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + + +public class FileManager { + + public static final String SORT_ORDER_ASC = "ASC"; + public static final String SORT_ORDER_DESC = "DESC"; + + public static final String SORT_BY_NAME = "NAME"; + public static final String SORT_BY_SIZE = "SIZE"; + public static final String SORT_BY_LAST_MODIFIED = "LAST_MODIFIED"; + + public static String getExtension(String url) { + + if (url.contains("?")) { + url = url.substring(0, url.indexOf("?")); + } + if (url.lastIndexOf(".") == -1) { + return null; + } else { + String ext = url.substring(url.lastIndexOf(".")); + if (ext.contains("%")) { + ext = ext.substring(0, ext.indexOf("%")); + } + if (ext.contains("/")) { + ext = ext.substring(0, ext.indexOf("/")); + } + return ext.toLowerCase(); + } + } + + public static ArrayList sort(ArrayList files, String sortOrder, String sortBy, boolean folderFirst) { + + switch (sortOrder) { + + case SORT_ORDER_ASC: + switch (sortBy) { + case SORT_BY_SIZE: + return sortBySize(files, SORT_ORDER_ASC, folderFirst); + + case SORT_BY_LAST_MODIFIED: + return sortByLastModified(files, SORT_ORDER_ASC, folderFirst); + + case SORT_BY_NAME: + default: + return sortByName(files, SORT_ORDER_ASC, folderFirst); + } + + case SORT_ORDER_DESC: + switch (sortBy) { + case SORT_BY_NAME: + return sortByName(files, SORT_ORDER_DESC, folderFirst); + + case SORT_BY_LAST_MODIFIED: + return sortByLastModified(files, SORT_ORDER_DESC, folderFirst); + + case SORT_BY_SIZE: + default: + return sortBySize(files, SORT_ORDER_DESC, folderFirst); + } + + default: + return sortByName(files, SORT_ORDER_ASC, folderFirst); + } + + } + + private static ArrayList sortByName(final ArrayList files, final String sortOrder, final boolean folderFirst) { + + Collections.sort(files, new Comparator() { + @Override + public int compare(File lhs, File rhs) { + if(folderFirst) { + if (lhs.isDirectory() && !rhs.isDirectory()) return -1; + if (!lhs.isDirectory() && rhs.isDirectory()) return 1; + } + switch (sortOrder) { + case SORT_ORDER_DESC: + return rhs.getName().compareToIgnoreCase(lhs.getName()); + + case SORT_ORDER_ASC: + default: + return lhs.getName().compareToIgnoreCase(rhs.getName()); + } + } + }); + return files; + } + + private static ArrayList sortBySize(ArrayList files, final String sortOrder, final boolean folderFirst) { + + Collections.sort(files, new Comparator() { + @Override + public int compare(File lhs, File rhs) { + + if(folderFirst) { + if (lhs.isDirectory() && !rhs.isDirectory()) return -1; + if (!lhs.isDirectory() && rhs.isDirectory()) return 1; + } + + long lhsLength = 0, rhsLength = 0, diff; + + if(lhs.isDirectory()) lhsLength = getFolderSize(lhs); + if(lhs.isFile()) lhsLength = lhs.length(); + if(rhs.isDirectory()) rhsLength = getFolderSize(rhs); + if(rhs.isFile()) rhsLength = rhs.length(); + + switch (sortOrder) { + case SORT_ORDER_DESC: + diff = rhsLength - lhsLength; + break; + case SORT_ORDER_ASC: + default: + diff = lhsLength - rhsLength; + break; + } + + if (diff < 0) return -1; + else if (diff > 0) return 1; + else return 0; + } + }); + return files; + } + + private static ArrayList sortByLastModified(ArrayList files, final String sortOrder, final boolean foldersFirst) { + + Collections.sort(files, new Comparator() { + @Override + public int compare(File lhs, File rhs) { + + if (foldersFirst){ + if(lhs.isDirectory() && !rhs.isDirectory()) return -1; + if(!lhs.isDirectory() && rhs.isDirectory()) return 1; + } + + long diff; + switch (sortOrder) { + case SORT_ORDER_DESC: + diff = rhs.lastModified() - lhs.lastModified(); + break; + + case SORT_ORDER_ASC: + default: + diff = lhs.lastModified() - rhs.lastModified(); + break; + } + + if (diff < 0) return -1; + else if (diff > 0) return 1; + else return 0; + } + }); + return files; + } + + public static long getFolderSize(File file) { + + long size = 0; + for (File f : file.listFiles()) { + if (f.isFile()) size += f.length(); + else size += getFolderSize(f); + } + return size; + } + + public static boolean isHiddenFile(File file) { + return file.getName().startsWith("."); + } + + public static ArrayList removeHiddenFiles(ArrayList files) { + ArrayList list = new ArrayList<>(); + + for (File file : files) { + if (!isHiddenFile(file)) + list.add(file); + } + return list; + } +} \ No newline at end of file diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/PrefsActivity.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/PrefsActivity.java new file mode 100644 index 0000000..f4d01a8 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/PrefsActivity.java @@ -0,0 +1,31 @@ +package com.gpac.Osmo4.extra; + +import android.app.Activity; +import android.os.Bundle; +import android.preference.PreferenceFragment; + + +import com.gpac.Osmo4.R; + + +public class PrefsActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getFragmentManager().beginTransaction().replace(android.R.id.content, + new PrefsFragment()).commit(); + } + + + public static class PrefsFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preference); + } + } + +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/XMLTagHandler.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/XMLTagHandler.java new file mode 100644 index 0000000..ed97ec4 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/extra/XMLTagHandler.java @@ -0,0 +1,40 @@ +package com.gpac.Osmo4.extra; + +import android.text.Editable; +import android.text.Html.TagHandler; + +import org.xml.sax.XMLReader; + +public class XMLTagHandler implements TagHandler{ + boolean first= true; + String parent=null; + int index=1; + @Override + public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { + + if(tag.equals("ul")) { + parent = "ul"; + output.append("\n"); + } + else if(tag.equals("ol")) parent="ol"; + if(tag.equals("li")){ + if(parent.equals("ul")){ + if(first){ + output.append("\n\t•"); + first= false; + }else{ + first = true; + } + } + else{ + if(first){ + output.append("\n\t"+index+". "); + first= false; + index++; + }else{ + first = true; + } + } + } + } +} diff --git a/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/logs/GpacLogger.java b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/logs/GpacLogger.java new file mode 100644 index 0000000..ce60a55 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/java/com/gpac/Osmo4/logs/GpacLogger.java @@ -0,0 +1,159 @@ +/** + * $URL$ + * + * $LastChangedBy$ - $LastChangedDate$ + */ +package com.gpac.Osmo4.logs; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.Date; +import java.util.SortedSet; +import java.util.TreeSet; +import android.util.Log; +import com.gpac.Osmo4.GpacCallback.GF_Log_Module; +import com.gpac.Osmo4.GpacConfig; + +/** + * This class handles logging. + * + * It will be extended soon to be configurable and enable saving files on disk + * + * @version $Revision$ + * + */ +public class GpacLogger { + + /** + * Default Constructor + * + * @param gpacConfig + */ + public GpacLogger(GpacConfig gpacConfig) { + loggedModules.add(GF_Log_Module.GF_LOG_AUDIO); + loggedModules.add(GF_Log_Module.GF_LOG_MEDIA); + loggedModules.add(GF_Log_Module.GF_LOG_MODULE); + loggedModules.add(GF_Log_Module.GF_LOG_CORE); + logDir = gpacConfig.getGpacLogDirectory(); //$NON-NLS-1$ + } + + private boolean enableLogOnDisk = false; + + /** + * @return the enableLogOnDisk + */ + public synchronized boolean isEnableLogOnDisk() { + return enableLogOnDisk; + } + + /** + * @param enableLogOnDisk the enableLogOnDisk to set + */ + public synchronized void setEnableLogOnDisk(boolean enableLogOnDisk) { + this.enableLogOnDisk = enableLogOnDisk; + } + + private String logDir; + private String logFile; + + public synchronized void setLogFile(String logFile) { + //reset writer + writer = null; + this.logFile = logDir + logFile; + } + + /** + * Called when creating logger + */ + public void onCreate() { + if (!enableLogOnDisk) + return; + if (writer == null) { + try { + writer = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(logFile)), 128), true, "UTF-8"); //$NON-NLS-1$ + } catch (Exception e) { + Log.e(GpacLogger.class.getSimpleName(), "Failed to create writer", e); //$NON-NLS-1$ + } + } + if (writer != null) + writer.println("New log $Revision$ at " + new Date()); //$NON-NLS-1$ + } + + /** + * Called when stopping logger + */ + public void onDestroy() { + if (!enableLogOnDisk) + return; + PrintStream w = this.writer; + writer = null; + if (w != null) { + w.println("Closing log file at " + new Date()); //$NON-NLS-1$ + w.close(); + } + } + + /** + * Logs from C-code + * + * @param level + * @param module + * @param message + */ + public void onLog(int level, int module, String message) { + GF_Log_Module gModule = GF_Log_Module.getModule(module); + doLog(gModule, level, message); + } + + private void doLog(GF_Log_Module module, int level, String message) { + Log.println(4, module.name(), message); + if (enableLogOnDisk) { + PrintStream s = writer; + if (s != null) { + s.println(module.name() + "\t" + message); //$NON-NLS-1$ + s.flush(); + } + } + } + + private final SortedSet loggedModules = new TreeSet(); + + // The log level used by GPAC modules that are part of loggedModules collection + private int loggedLevel = Log.DEBUG; + + // The log level used by GPAC modules not part of loggedModules collection + private int defaultLoggedLevel = Log.INFO; + + /** + * @return the loggedLevel + */ + public synchronized int getLoggedLevel() { + return loggedLevel; + } + + /** + * @param loggedLevel the loggedLevel to set + */ + public synchronized void setLoggedLevel(int loggedLevel) { + this.loggedLevel = loggedLevel; + } + + /** + * @return the defaultLoggedLevel + */ + public synchronized int getDefaultLoggedLevel() { + return defaultLoggedLevel; + } + + /** + * @param defaultLoggedLevel the defaultLoggedLevel to set + */ + public synchronized void setDefaultLoggedLevel(int defaultLoggedLevel) { + this.defaultLoggedLevel = defaultLoggedLevel; + } + + private volatile PrintStream writer; + +} diff --git a/applications/osmo4_android_studio/app/src/main/jni/README.txt b/applications/osmo4_android_studio/app/src/main/jni/README.txt new file mode 100644 index 0000000..05c508f --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/jni/README.txt @@ -0,0 +1,2 @@ +To build Android version, Please execute the script : +../../../build/android/jni/gpac_build_android diff --git a/applications/osmo4_android_studio/app/src/main/jni/wrapper.cpp b/applications/osmo4_android_studio/app/src/main/jni/wrapper.cpp new file mode 100644 index 0000000..73aa32a --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/jni/wrapper.cpp @@ -0,0 +1,1098 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2009- + * All rights reserved + * + * Created by NGO Van Luyen, Ivica ARSOV / ARTEMIS / Telecom SudParis /Institut TELECOM on Oct, 2010 + * + * This file is part of GPAC / Wrapper + * + * 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 +#include +#include +#include +#include + +#include "wrapper.h" +#include "wrapper_jni.hpp" + +#include +#include + +#define TAG "GPAC_WRAPPER" + +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) +#include + +static JavaVM* javaVM = NULL; + +static pthread_key_t jni_thread_env_key = 0; + +//these two are used by modumles - define them when using static module build +#ifdef GPAC_STATIC_MODULES + +#ifdef __cplusplus +extern "C" { +#endif + +JavaVM* GetJavaVM() +{ + return javaVM; +} + +JNIEnv* GetEnv() +{ + JNIEnv* env = 0; + if (javaVM) javaVM->GetEnv((void**)(&env), JNI_VERSION_1_2); + return env; +} + +#ifdef __cplusplus +} +#endif + +#endif + + +/** + * This method is called when a pthread is destroyed, so we can delete the JNI env + */ +static void jni_destroy_env_func(void * env) { + LOGI("Destroying a thread with attached data, env=%p.\n", env); + JavaEnvTh * jniEnv = (JavaEnvTh *) env; + if (jniEnv) { + /*jniEnv->env->DeleteLocalRef(&jniEnv->cbk_displayMessage); + jniEnv->env->DeleteLocalRef(&jniEnv->cbk_onProgress); + jniEnv->env->DeleteLocalRef(&jniEnv->cbk_showKeyboard); + jniEnv->env->DeleteLocalRef(&jniEnv->cbk_setCaption); + jniEnv->env->DeleteLocalRef(&jniEnv->cbk_onLog);*/ + memset(jniEnv, 0, sizeof(JavaEnvTh)); + gf_free(jniEnv); + } + pthread_setspecific(jni_thread_env_key, NULL); + if (javaVM) + javaVM->DetachCurrentThread(); +} + +static int jniRegisterNativeMethods(JNIEnv* env, const char* className, + const JNINativeMethod* gMethods, int numMethods) +{ + int res; + jclass clazz; + clazz = env->FindClass(className); + if (clazz == NULL) { + LOGE("Native registration unable to find class '%s'\n", className); + return -1; + } + LOGI("Registering %d methods...\n", numMethods ); + res = env->RegisterNatives(clazz, gMethods, numMethods); + if (res < 0) { + LOGE("RegisterNatives failed for '%s'\n", className); + return res; + } + return 0; +} + +static JNINativeMethod sMethods[] = { + /* name, signature, funcPtr */ + + { "createInstance", + "(Lcom/gpac/Osmo4/GpacCallback;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", + (void*)&Java_com_gpac_Osmo4_GPACInstance_createInstance + }, + { "gpacdisconnect", + "()V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpacdisconnect + }, + { "gpacrender", + "()V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpacrender + }, + { "gpacresize", + "(II)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpacresize + }, + { "gpacfree", + "()V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpacfree + }, + { "gpaceventkeypress", + "(IIIII)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventkeypress + }, + { "gpaceventmousedown", + "(FF)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventmousedown + }, + { "gpaceventmouseup", + "(FF)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventmouseup + }, + { "gpaceventmousemove", + "(FF)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventmousemove + }, + { "gpaceventorientationchange", + "(FFF)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_gpaceventorientationchange + }, + { "setGpacPreference", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_setGpacPreference + }, + { "setGpacLogs", + "(Ljava/lang/String;)V", + (void*)Java_com_gpac_Osmo4_GPACInstance_setGpacLogs + }, + NULL +}; + + +jint JNI_OnUnLoad(JavaVM* vm, void* reserved) { + LOGI("Deleting library, vm=%p...\n", vm); + if (pthread_key_delete(jni_thread_env_key)) { + LOGW("Failed to delete key jni_thread_env_key jni_thread_env_key=%d\n", jni_thread_env_key); + } + javaVM = NULL; + jni_thread_env_key = (int) NULL; +} + +#define NUM_JNI_VERSIONS 4 +//--------------------------------------------------------------------------------------------------- +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + int res; + int jniV; + int allowedVersions[NUM_JNI_VERSIONS]; + const char * className = "com/gpac/Osmo4/GPACInstance"; + allowedVersions[0] = JNI_VERSION_1_6; + allowedVersions[1] = JNI_VERSION_1_4; + allowedVersions[2] = JNI_VERSION_1_2; + allowedVersions[3] = JNI_VERSION_1_1; + JNIEnv * env; + if (!vm) + return -1; + for (int i = 0 ; i < NUM_JNI_VERSIONS; i++) { + jniV = allowedVersions[i]; + if (vm->GetEnv((void**)(&env), jniV) == JNI_OK) { + LOGI("Selected JNI VERSION[%d]\n", i); + break; + } else { + if (i == NUM_JNI_VERSIONS - 1) { + LOGW("Failed to find any supported JNI VERSION of the %d proposed.", NUM_JNI_VERSIONS); + return -1; + } + } + + } + javaVM = vm; + LOGI("Registering %s natives\n", className); + res = jniRegisterNativeMethods(env, className, sMethods, (sizeof(sMethods) - 1)/sizeof(JNINativeMethod)); + if (res < 0) { + LOGE("Failed to register native methods, result was = %d, try to continue anyway...\n", res); + /*return -1;*/ + } + LOGI("Registering natives DONE, now registering pthread_keys with destructor=%p\n", &jni_destroy_env_func); + int ret = pthread_key_create(&jni_thread_env_key, &jni_destroy_env_func); + if (ret) { + LOGE("Failed to register jni_thread_env_key jni_thread_env_key=%d\n", jni_thread_env_key); + } + return jniV; +} + +//--------------------------------------------------------------------------------------------------- +//CNativeWrapper +//------------------------------- + +CNativeWrapper::CNativeWrapper() { + do_log = 1; + m_term = NULL; + m_mx = NULL; + mainJavaEnv = NULL; +#ifndef GPAC_GUI_ONLY + memset(&m_user, 0, sizeof(GF_User)); + memset(&m_rti, 0, sizeof(GF_SystemRTInfo)); +#endif +} +//------------------------------- +CNativeWrapper::~CNativeWrapper() { + debug_log("~CNativeWrapper()"); + JavaEnvTh * env = getEnv(); + if (env && env->cbk_obj) + env->env->DeleteGlobalRef(env->cbk_obj); + Shutdown(); + debug_log("~CNativeWrapper() : DONE\n"); +} +//------------------------------- +void CNativeWrapper::debug_log(const char* msg) { + LOGV("%s", msg); +} +//------------------------------- +void CNativeWrapper::Shutdown() +{ + debug_log("shutdown"); + if (m_term) + gf_term_disconnect(m_term); + if (m_mx) + gf_mx_del(m_mx); + m_mx = NULL; +#ifndef GPAC_GUI_ONLY + if (m_term) { + GF_Terminal *t = m_term; + m_term = NULL; + gf_term_del(t); + } + if (m_user.config) { + gf_cfg_del(m_user.config); + m_user.config = NULL; + } + if (m_user.modules) { + gf_modules_del(m_user.modules); + m_user.modules = NULL; + } +#endif + m_term = NULL; + gf_sys_close(); + debug_log("shutdown end"); +} + +void CNativeWrapper::setJavaEnv(JavaEnvTh * envToSet, JNIEnv *env, jobject callback) { + assert( envToSet ); + jclass localRef = env->GetObjectClass(callback); + envToSet->env = env; + envToSet->javaThreadId = gf_th_id(); + envToSet->cbk_obj = callback; + envToSet->cbk_displayMessage = + env->GetMethodID(localRef, "displayMessage", "(Ljava/lang/String;Ljava/lang/String;I)V"); + envToSet->cbk_onProgress = + env->GetMethodID(localRef, "onProgress", "(Ljava/lang/String;II)V"); + envToSet->cbk_onLog = + env->GetMethodID(localRef, "onLog", "(IILjava/lang/String;)V"); + envToSet->cbk_setCaption = + env->GetMethodID(localRef, "setCaption", "(Ljava/lang/String;)V"); + envToSet->cbk_showKeyboard = + env->GetMethodID(localRef, "showKeyboard", "(Z)V"); + envToSet->cbk_setLogFile = + env->GetMethodID(localRef, "setLogFile", "(Ljava/lang/String;)V"); + envToSet->cbk_sensorSwitch = + env->GetMethodID(localRef, "sensorSwitch", "(Z)V"); + env->DeleteLocalRef(localRef); +} + +static u32 beforeThreadExits(void * param) { + /* Ivica - I think there is no need for this because the detach is done in jni_destroy_env_func() + /*LOGI("Before Thread exist, detach the JavaVM from Thread for thread %p...\n", gf_th_current()); + if (javaVM) + javaVM->DetachCurrentThread(); + */ +} + +JavaEnvTh * CNativeWrapper::getEnv() { + JNIEnv *env; + JavaEnvTh * javaEnv; + if (!javaVM) { + debug_log("************* No JVM Found ************"); + return NULL; + } + javaEnv = (JavaEnvTh*) pthread_getspecific( jni_thread_env_key ); + if (javaEnv) + return javaEnv; + javaEnv = (JavaEnvTh *) gf_malloc(sizeof(JavaEnvTh)); + if (!javaEnv) + return NULL; + memset(javaEnv, 0, sizeof(JavaEnvTh)); + javaVM->AttachCurrentThread(&env, NULL); + if (!env) { + LOGE("Attaching to thread did failed for thread id=%d", gf_th_id()); + gf_free(javaEnv); + return NULL; + } + LOGI("Rebuilding methods for thread %d", gf_th_id()); + setJavaEnv(javaEnv, env, mainJavaEnv->cbk_obj); + if (pthread_setspecific(jni_thread_env_key, javaEnv)) { + LOGE("Failed to set specific thread data to jni_thread_env_key for thread=%d. No ENV available !", gf_th_id()); + gf_free(javaEnv); + return NULL; + } + GF_Thread * t; + LOGI("Getting current Thread %d...", gf_th_id()); + t = gf_th_current(); + LOGI("Getting current Thread DONE = %p, now registering before exit...", t); + + if (GF_OK != gf_register_before_exit_function(gf_th_current(), &beforeThreadExits)) { + LOGE("Failed to register exit function for thread %p, no javaEnv for current thread.", gf_th_current()); + //javaVM->DetachCurrentThread(); + gf_free(javaEnv); + javaEnv = NULL; + } + LOGI("Registering DONE for %d", gf_th_id()); + return javaEnv; +} + + +//------------------------------- +int CNativeWrapper::MessageBox(const char* msg, const char* title, GF_Err status) { + LOGV("MessageBox start %s", msg); + JavaEnvTh * env = getEnv(); + if (!env || !env->cbk_displayMessage) + return 0; + env->env->PushLocalFrame(2); + jstring tit = env->env->NewStringUTF(title?title:"null"); + jstring mes = env->env->NewStringUTF(msg?msg:"null"); + env->env->CallVoidMethod(env->cbk_obj, env->cbk_displayMessage, mes, tit, status); + env->env->PopLocalFrame(NULL); + LOGV("MessageBox done %s", msg); + return 1; +} +//------------------------------- +void CNativeWrapper::DisplayRTI() { +#ifndef GPAC_GUI_ONLY + // display some system informations ? +#endif +} +//------------------------------- +int CNativeWrapper::Quit(int code) { + + Shutdown(); + // send shutdown request to java + return code; +} + +#include + +void CNativeWrapper::on_fm_request(void *cbk, u32 type, u32 param, int *value) { + CNativeWrapper * self = (CNativeWrapper *) cbk; + JavaEnvTh *envth = self->getEnv(); + + envth->env->PushLocalFrame(1); + switch(type) { + case 0: // Get PI + case 1: // Get RT + case 2: // Get PS + jint jvalue; + jvalue = envth->env->CallIntMethod(envth->cbk_obj, envth->cbk_onFmRequest, type, param); + *value = (int)jvalue; + break; + case 3: // Set Freq + case 4: // Set Volume + envth->env->CallVoidMethod(envth->cbk_obj, envth->cbk_onFmRequest, type, param); + break; + } + envth->env->PopLocalFrame(NULL); +} + + +//------------------------------- +void CNativeWrapper::on_gpac_log(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *fmt, va_list list) { + char szMsg[4096]; + const char * tag; + char unknTag[32]; + int level = (ll == GF_LOG_ERROR) ? ANDROID_LOG_ERROR : ANDROID_LOG_DEBUG; + vsnprintf(szMsg, 4096, fmt, list); + CNativeWrapper * self = (CNativeWrapper *) cbk; + if (!self) + goto displayInAndroidlogs; + + { + JavaEnvTh *env = self->getEnv(); + jstring msg; + + if (!env || !env->cbk_onLog) + goto displayInAndroidlogs; + + env->env->PushLocalFrame(1); + msg = env->env->NewStringUTF(szMsg); + env->env->CallVoidMethod(env->cbk_obj, env->cbk_onLog, level, lm, msg); + env->env->PopLocalFrame(NULL); + return; + } +displayInAndroidlogs: + { + /* When no callback is properly set, we use direct logging */ + switch( lm) { + case GF_LOG_CORE: + tag="GF_LOG_CORE"; + break; + case GF_LOG_CODING: + tag="GF_LOG_CODING"; + break; + case GF_LOG_CONTAINER: + tag="GF_LOG_CONTAINER"; + break; + case GF_LOG_NETWORK: + tag="GF_LOG_NETWORK"; + break; + case GF_LOG_RTP: + tag="GF_LOG_RTP"; + break; + case GF_LOG_AUTHOR: + tag="GF_LOG_AUTHOR"; + break; + case GF_LOG_SYNC: + tag="GF_LOG_SYNC"; + break; + case GF_LOG_CODEC: + tag="GF_LOG_CODEC"; + break; + case GF_LOG_PARSER: + tag="GF_LOG_PARSER"; + break; + case GF_LOG_MEDIA: + tag="GF_LOG_MEDIA"; + break; + case GF_LOG_SCENE: + tag="GF_LOG_SCENE"; + break; + case GF_LOG_SCRIPT: + tag="GF_LOG_SCRIPT"; + break; + case GF_LOG_INTERACT: + tag="GF_LOG_INTERACT"; + break; + case GF_LOG_COMPOSE: + tag="GF_LOG_COMPOSE"; + break; + case GF_LOG_CACHE: + tag="GF_LOG_CACHE"; + break; + case GF_LOG_MMIO: + tag="GF_LOG_MMIO"; + break; + case GF_LOG_RTI: + tag="GF_LOG_RTI"; + break; + case GF_LOG_SMIL: + tag="GF_LOG_SMIL"; + break; + case GF_LOG_MEMORY: + tag="GF_LOG_MEMORY"; + break; + case GF_LOG_AUDIO: + tag="GF_LOG_AUDIO"; + break; + case GF_LOG_MODULE: + tag="GF_LOG_MODULE"; + break; + case GF_LOG_MUTEX: + tag="GF_LOG_MUTEX"; + break; + case GF_LOG_CONDITION: + tag="GF_LOG_CONDITION"; + break; + case GF_LOG_DASH: + tag="GF_LOG_DASH"; + break; + case GF_LOG_CONSOLE: + tag="GF_LOG_CONSOLE"; + break; + case GF_LOG_APP: + tag="GF_LOG_APP"; + break; + case GF_LOG_SCHEDULER: + tag="GF_LOG_SCHEDULER"; + break; + default: + snprintf(unknTag, 32, "GPAC_UNKNOWN[%d]", lm); + tag = unknTag; + } + __android_log_print(level, tag, "%s\n", szMsg); + } +} +//------------------------------- +Bool CNativeWrapper::GPAC_EventProc(void *cbk, GF_Event *evt) { + if (cbk) + { + CNativeWrapper* ptr = (CNativeWrapper*)cbk; + char msg[4096]; + msg[0] = 0; + LOGD("GPAC_EventProc() Message=%d", evt->type); + switch (evt->type) { + case GF_EVENT_CLICK: + case GF_EVENT_MOUSEUP: + case GF_EVENT_MOUSEDOWN: + case GF_EVENT_MOUSEOVER: + case GF_EVENT_MOUSEOUT: + case GF_EVENT_MOUSEMOVE: + case GF_EVENT_MOUSEWHEEL: + case GF_EVENT_KEYUP: + case GF_EVENT_KEYDOWN: + case GF_EVENT_LONGKEYPRESS: + case GF_EVENT_TEXTINPUT: + /* We ignore all these events */ + break; + case GF_EVENT_MEDIA_SETUP_BEGIN: + case GF_EVENT_MEDIA_SETUP_DONE: + case GF_EVENT_MEDIA_LOAD_START: + case GF_EVENT_MEDIA_PLAYING: + case GF_EVENT_MEDIA_WAITING: + case GF_EVENT_MEDIA_PROGRESS: + case GF_EVENT_MEDIA_LOAD_DONE: + case GF_EVENT_ABORT: + case GF_EVENT_ERROR: + LOGD("GPAC_EventProc() Media Event detected = [index=%d]", evt->type - GF_EVENT_MEDIA_SETUP_BEGIN); + break; + case GF_EVENT_MESSAGE: + { + ptr->debug_log("GPAC_EventProc start"); + if ( evt->message.message ) + { + strcat(msg, evt->message.message); + strcat(msg, ": "); + } + strcat(msg, gf_error_to_string(evt->message.error)); + + ptr->debug_log(msg); + //ptr->MessageBox(msg, evt->message.service ? evt->message.service : "GF_EVENT_MESSAGE", evt->message.error); + ptr->debug_log("GPAC_EventProc end"); + }; + break; + case GF_EVENT_CONNECT: + if (evt->connect.is_connected) + ptr->MessageBox("Connected", "Connected to scene", GF_OK); + else + ptr->MessageBox("Disconnected", "Disconnected from scene.", GF_OK); + break; + case GF_EVENT_PROGRESS: + { + const char * szTitle;; + if (evt->progress.progress_type==0) + szTitle = "Buffering"; + else if (evt->progress.progress_type==1) + szTitle = "Downloading..."; + else if (evt->progress.progress_type==2) + szTitle = "Import "; + else + szTitle = "Unknown Progress Event"; + ptr->Osmo4_progress_cbk(ptr, szTitle, evt->progress.done, evt->progress.total); + gf_set_progress(szTitle, evt->progress.done, evt->progress.total); + } + break; + case GF_EVENT_TEXT_EDITING_START: + case GF_EVENT_TEXT_EDITING_END: + { + JavaEnvTh * env = ptr->getEnv(); + if (!env || !env->cbk_showKeyboard) + return GF_FALSE; + LOGI("Needs to display/hide the Virtual Keyboard (%d)", evt->type); + env->env->CallVoidMethod(env->cbk_obj, env->cbk_showKeyboard, GF_EVENT_TEXT_EDITING_START == evt->type); + LOGV("Done showing virtual keyboard (%d)", evt->type); + } + break; + case GF_EVENT_EOS: + LOGI("EOS Reached (%d)", evt->type); + break; + case GF_EVENT_DISCONNECT: + /* FIXME : not sure about this behaviour */ + if (ptr) + ptr->disconnect(); + break; + case GF_EVENT_NAVIGATE: + ptr->navigate( evt); + break; + case GF_EVENT_SENSOR_REQUEST: + if(evt->activate_sensor.sensor_type == GF_EVENT_SENSOR_ORIENTATION){ + if(evt->activate_sensor.activate){ + LOGV("We received Sensor Request for turning ON location sensors"); + JavaEnvTh * env = ptr->getEnv(); + if (!env || !env->cbk_sensorSwitch) + return GF_FALSE; + env->env->CallVoidMethod(env->cbk_obj, env->cbk_sensorSwitch, evt->activate_sensor.activate); + }else{ + LOGV("We received Sensor Request for turning OFF location sensors"); + JavaEnvTh * env = ptr->getEnv(); + if (!env || !env->cbk_sensorSwitch) + return GF_FALSE; + env->env->CallVoidMethod(env->cbk_obj, env->cbk_sensorSwitch, evt->activate_sensor.activate); + } + return GF_TRUE; + } + break; + case GF_EVENT_SENSOR_ORIENTATION: + /* Ignore this event */ + /* + LOGV("We received Sensor Orientation event (x: %f, y: %f, z: %f)",evt->sensor.x, evt->sensor.y, evt->sensor.z); + */ + break; + default: + LOGI("Unknown Message %d", evt->type); + } + } + return GF_FALSE; +} + +void CNativeWrapper::navigate( GF_Event* evt) +{ + if (gf_term_is_supported_url(m_term, evt->navigate.to_url, GF_TRUE, GF_TRUE)) + { + gf_term_navigate_to(m_term, evt->navigate.to_url); + } +} + +void CNativeWrapper::progress_cbk(const char *title, u64 done, u64 total) { + JavaEnvTh *env = getEnv(); + if (!env || !env->cbk_onProgress) + return; + //debug_log("Osmo4_progress_cbk start"); + env->env->PushLocalFrame(1); + jstring js = env->env->NewStringUTF(title); + env->env->CallVoidMethod(env->cbk_obj, env->cbk_onProgress, js, done, total); + env->env->PopLocalFrame(NULL); + //debug_log("Osmo4_progress_cbk end"); +} + + +//------------------------------- +void CNativeWrapper::Osmo4_progress_cbk(const void *usr, const char *title, u64 done, u64 total) { + if (!usr) + return; + CNativeWrapper * self = (CNativeWrapper *) usr; + self->progress_cbk(title, done, total); +} +//------------------------------- +void CNativeWrapper::SetupLogs() { + const char *opt; + debug_log("SetupLogs()"); + + gf_mx_p(m_mx); + gf_log_set_tools_levels( gf_cfg_get_key(m_user.config, "General", "Logs") ); + gf_log_set_callback(this, on_gpac_log); + opt = gf_cfg_get_key(m_user.config, "General", "LogFile"); + if (opt) { + JavaEnvTh *env = getEnv(); + if (env && env->cbk_setLogFile) { + env->env->PushLocalFrame(1); + jstring js = env->env->NewStringUTF(opt); + env->env->CallVoidMethod(env->cbk_obj, env->cbk_setLogFile, js); + env->env->PopLocalFrame(NULL); + } + } + gf_mx_v(m_mx); + + GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Osmo4 logs initialized\n")); + /* Test for JNI invocations, should work properly + int k; + for (k = 0 ; k < 512; k++){ + GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Message %d\n", k)); + }*/ +} +//------------------------------- +// dir should end with / +int CNativeWrapper::init(JNIEnv * env, void * bitmap, jobject * callback, int width, int height, const char * cfg_dir, const char * modules_dir, const char * cache_dir, const char * font_dir, const char * gui_dir, const char * urlToLoad) { + LOGI("Initializing GPAC with URL=%s...", urlToLoad); + strcpy(m_modules_dir, modules_dir); + strcpy(m_cache_dir, cache_dir); + strcpy(m_font_dir, font_dir); + if (cfg_dir) + strcpy(m_cfg_dir, cfg_dir); + + char m_cfg_filename[GF_MAX_PATH]; + if (m_cfg_dir) { + LOGI("GPAC.cfg found in %s, force using it.\n", m_cfg_dir); + strcpy(m_cfg_filename, m_cfg_dir); + strcat(m_cfg_filename, "GPAC.cfg"); + } + + int m_Width = width; + int m_Height = height; + + int first_launch = 0; + const char *opt; + + m_window = env; + m_session = bitmap; + if (!mainJavaEnv) + mainJavaEnv = (JavaEnvTh *) gf_malloc(sizeof(JavaEnvTh)); + memset(mainJavaEnv, 0, sizeof(JavaEnvTh)); + setJavaEnv(mainJavaEnv, env, env->NewGlobalRef(*callback)); + if (pthread_setspecific( jni_thread_env_key, mainJavaEnv)) { + LOGE("Failed to set specific thread data to jni_thread_env_key=%d for main thread !", jni_thread_env_key); + } + + m_mx = gf_mx_new("Osmo4"); + + //load config file + LOGI("Loading User Config %s...", "GPAC.cfg"); + m_user.config = gf_cfg_init(m_cfg_dir ? m_cfg_filename : NULL, NULL); + gf_set_progress_callback(this, Osmo4_progress_cbk); + + + char path[512]; + strcpy(path, gui_dir); + char vertex_path[512], fragment_path[512]; + strcpy(vertex_path, path); + strcpy(fragment_path, path); + strcat(vertex_path, "/../shaders/vertex.glsl"); + strcat(fragment_path, "/../shaders/fragment.glsl"); + + gf_cfg_set_key(m_user.config, "Compositor", "VertexShader", vertex_path); + gf_cfg_set_key(m_user.config, "Compositor", "FragmentShader", fragment_path); + gf_cfg_set_key(m_user.config, "Compositor", "OpenGLMode", "hybrid"); + opt = gf_cfg_get_key(m_user.config, "General", "ModulesDirectory"); + LOGI("loading modules in directory %s...", opt); + m_user.modules = gf_modules_new(opt, m_user.config); + if (!m_user.modules || !gf_modules_get_count(m_user.modules)) { + LOGE("No modules found in directory %s !", opt); + if (m_user.modules) + gf_modules_del(m_user.modules); + gf_cfg_del(m_user.config); + m_user.config = NULL; + return Quit(KErrGeneral); + } + + /*we don't thread the visual compositor to be able to minimize the app and still have audio running*/ + m_user.init_flags = GF_TERM_NO_COMPOSITOR_THREAD; + m_user.opaque = this; + + m_user.os_window_handler = m_window; + m_user.os_display = m_session; + m_user.EventProc = GPAC_EventProc; + if (!javaVM) { + LOGE("NO JAVA VM FOUND, m_user=%p !!!!\n", &m_user); + return Quit(KErrGeneral); + } + + LOGD("Loading GPAC terminal, m_user=%p...", &m_user); + gf_sys_init(GF_MemTrackerNone); + gf_fm_request_set_callback(this, on_fm_request); + SetupLogs(); + m_term = gf_term_new(&m_user); + if (!m_term) { + LOGE("Cannot load GPAC Terminal with m_user=%p", &m_user); + MessageBox("Cannot load GPAC terminal", "Fatal Error", GF_SERVICE_ERROR); + gf_modules_del(m_user.modules); + m_user.modules = NULL; + gf_cfg_del(m_user.config); + m_user.config = NULL; + return Quit(KErrGeneral); + } + + /*force fullscreen*/ + gf_term_set_option(m_term, GF_OPT_FULLSCREEN, 1); + + //setAudioEnvironment(javaVM); + + LOGD("Setting term size m_user=%p...", &m_user); + gf_term_set_size(m_term, m_Width, m_Height); + + opt = gf_cfg_get_key(m_user.config, "General", "StartupFile"); + LOGD("File loaded at startup=%s.", opt); + + if (!urlToLoad) + urlToLoad = opt; + if (urlToLoad) { + LOGI("Connecting to %s...", urlToLoad); + gf_term_connect(m_term, urlToLoad); + } + debug_log("init end"); + LOGD("Saving config file...\n"); + gf_cfg_save(m_user.config); + LOGI("Initialization complete, config file saved.\n"); + + return 0; +} +//------------------------------- +int CNativeWrapper::connect(const char *url) +{ + const char *str; + char the_url[256]; + + if (m_term) + { + debug_log("Starting to connect ..."); + str = gf_cfg_get_key(m_user.config, "General", "StartupFile"); + if (str) + { + gf_cfg_set_key(m_user.config, "Temp", "GUIStartupFile", url); + gf_term_connect(m_term, str); + } + if( url ) + { + gf_term_connect_from_time(m_term, url, 0, GF_FALSE); + } + } + debug_log("connected ..."); +} + +void CNativeWrapper::setGpacPreference( const char * category, const char * name, const char * value) +{ + if (m_user.config) { + gf_cfg_set_key(m_user.config, category, name, value); + gf_cfg_save(m_user.config); + } +} + +//----------------------------------------------------- +void CNativeWrapper::disconnect() { + if (m_term) { + debug_log("disconnecting"); + gf_term_disconnect(m_term); + debug_log("disconnected ..."); + } +} +//----------------------------------------------------- +void CNativeWrapper::step(void * env, void * bitmap) { + m_window = env; + m_session = bitmap; + //debug_log("Step ..."); + if (!m_term) { + debug_log("step(): No m_term found."); + return; + } else if (!m_term->compositor) + debug_log("step(): No compositor found."); + else if (!m_term->compositor->video_out) + debug_log("step(): No video_out found"); + else if (!m_term->compositor->video_out->Setup) + debug_log("step(): No video_out->Setup found"); + else { + m_term->compositor->frame_draw_type = GF_SC_DRAW_FRAME; + gf_term_process_step(m_term); + } +} + +//----------------------------------------------------- +void CNativeWrapper::setAudioEnvironment(JavaVM* javaVM) { + if (!m_term) { + debug_log("setAudioEnvironment(): no m_term found."); + return; + } + debug_log("setAudioEnvironment start"); + m_term->compositor->audio_renderer->audio_out->Setup(m_term->compositor->audio_renderer->audio_out, javaVM, 0, 0); + debug_log("setAudioEnvironment end"); +} +//----------------------------------------------------- +void CNativeWrapper::resize(int w, int h) { + if (!m_term) + return; + debug_log("resize start"); + gf_term_set_size(m_term, w, h); + debug_log("resize end"); +} + +//----------------------------------------------------- +void CNativeWrapper::onMouseDown(float x, float y) { + if (!m_term) + return; + debug_log("onMouseDown start"); + //char msg[100]; + //sprintf(msg, "onMousedown x=%f, y=%f", x, y ); + //debug_log(msg); + + GF_Event evt; + evt.type = GF_EVENT_MOUSEDOWN; + evt.mouse.button = GF_MOUSE_LEFT; + evt.mouse.x = x; + evt.mouse.y = y; + + int ret = gf_term_user_event(m_term, &evt); + debug_log("onMouseDown end"); +} +//----------------------------------------------------- +void CNativeWrapper::onMouseUp(float x, float y) { + if (!m_term) + return; + debug_log("onMouseUp start"); + //char msg[100]; + //sprintf(msg, "onMouseUp x=%f, y=%f", x, y ); + //debug_log(msg); + + GF_Event evt; + evt.type = GF_EVENT_MOUSEUP; + evt.mouse.button = GF_MOUSE_LEFT; + evt.mouse.x = x; + evt.mouse.y = y; + + int ret = gf_term_user_event(m_term, &evt); + debug_log("onMouseUp end"); +} +//----------------------------------------------------- +void CNativeWrapper::onMouseMove(float x, float y) { + if (!m_term) + return; + GF_Event evt; + evt.type = GF_EVENT_MOUSEMOVE; + evt.mouse.button = GF_MOUSE_LEFT; + evt.mouse.x = x; + evt.mouse.y = y; + + int ret = gf_term_user_event(m_term, &evt); +} +//----------------------------------------------------- +void CNativeWrapper::onKeyPress(int keycode, int rawkeycode, int up, int flag, int unicode) { + if (!m_term) + return; + debug_log("onKeyPress start"); + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + if (up == 0) evt.type = GF_EVENT_KEYUP; + else evt.type = GF_EVENT_KEYDOWN; + + evt.key.flags = 0; + evt.key.hw_code = rawkeycode; + + translate_key(keycode, &evt.key); + //evt.key.key_code = GF_KEY_A; + int ret = gf_term_user_event(m_term, &evt); + + if (evt.type == GF_EVENT_KEYUP && unicode) { + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_TEXTINPUT; + evt.character.unicode_char = unicode; + ret = gf_term_user_event(m_term, &evt); + } +} +//----------------------------------------------------- +void CNativeWrapper::translate_key(ANDROID_KEYCODE keycode, GF_EventKey *evt) { + evt->flags = 0; + switch (keycode) { + case ANDROID_KEYCODE_BACK: + evt->key_code = GF_KEY_BACKSPACE; + evt->hw_code = 8; + break; + case ANDROID_KEYCODE_TAB: + evt->key_code = GF_KEY_TAB; + evt->hw_code = 9; + break; + case ANDROID_KEYCODE_CLEAR: + evt->key_code = GF_KEY_CLEAR; + break; + case ANDROID_KEYCODE_DPAD_CENTER: + case ANDROID_KEYCODE_ENTER: + evt->key_code = GF_KEY_ENTER; + evt->hw_code = 13; + break; + case ANDROID_KEYCODE_SHIFT_LEFT: + evt->key_code = GF_KEY_SHIFT; + break; + case ANDROID_KEYCODE_SHIFT_RIGHT: + evt->key_code = GF_KEY_SHIFT; + break; + case ANDROID_KEYCODE_ALT_LEFT: + evt->key_code = GF_KEY_ALT; + break; + case ANDROID_KEYCODE_ALT_RIGHT: + evt->key_code = GF_KEY_ALT; + break; + case ANDROID_KEYCODE_SPACE: + evt->key_code = GF_KEY_SPACE; + evt->hw_code = 32; + break; + case ANDROID_KEYCODE_HOME: + evt->key_code = GF_KEY_HOME; + break; + case ANDROID_KEYCODE_DPAD_LEFT: + evt->key_code = GF_KEY_LEFT; + break; + case ANDROID_KEYCODE_DPAD_UP: + evt->key_code = GF_KEY_UP; + break; + case ANDROID_KEYCODE_DPAD_RIGHT: + evt->key_code = GF_KEY_RIGHT; + break; + case ANDROID_KEYCODE_DPAD_DOWN: + evt->key_code = GF_KEY_DOWN; + break; + case ANDROID_KEYCODE_DEL: + evt->key_code = GF_KEY_BACKSPACE; + evt->hw_code = 8; + break; + case ANDROID_KEYCODE_0: + evt->key_code = GF_KEY_0; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_1: + evt->key_code = GF_KEY_1; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_2: + evt->key_code = GF_KEY_2; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_3: + evt->key_code = GF_KEY_3; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_4: + evt->key_code = GF_KEY_4; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_5: + evt->key_code = GF_KEY_5; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_6: + evt->key_code = GF_KEY_6; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_7: + evt->key_code = GF_KEY_7; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_8: + evt->key_code = GF_KEY_8; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + case ANDROID_KEYCODE_9: + evt->key_code = GF_KEY_9; + evt->flags = GF_KEY_EXT_NUMPAD; + break; + /*thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ + /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ + default: + if ((keycode>=ANDROID_KEYCODE_A) && (keycode<=ANDROID_KEYCODE_Z)) { + evt->key_code = GF_KEY_A + keycode - ANDROID_KEYCODE_A; + } else { + evt->key_code = GF_KEY_UNIDENTIFIED; + } + break; + } +} +//----------------------------------------------------- + /** + * x: yaw (azimuth - rotation around the -Z axis) range: [-PI, PI] + * y: pitch (rotation around the -X axis) range: [-PI/2, PI/2] + * z: roll (rotation around the Y axis) range: [-PI, PI] + */ +void CNativeWrapper::onOrientationChange(float x, float y, float z) { + if (!m_term) + return; + GF_Event evt; + evt.type = GF_EVENT_SENSOR_ORIENTATION; + evt.sensor.x = x; + evt.sensor.y = y; + evt.sensor.z = z; + evt.sensor.w = 0; + + int ret = gf_term_user_event(m_term, &evt); +} +//----------------------------------------------------- +void CNativeWrapper::setGpacLogs(const char *tools_at_level) +{ + gf_log_set_tools_levels(tools_at_level); +} + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- diff --git a/applications/osmo4_android_studio/app/src/main/jni/wrapper.h b/applications/osmo4_android_studio/app/src/main/jni/wrapper.h new file mode 100644 index 0000000..fabed20 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/jni/wrapper.h @@ -0,0 +1,239 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2009- + * All rights reserved + * + * Created by NGO Van Luyen, Ivica ARSOV / ARTEMIS / Telecom SudParis /Institut TELECOM on Oct, 2010 + * + * This file is part of GPAC / Wrapper + * + * 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 WRAPPER +#define WRAPPER + +#include + +#include +#include +#include +#include + +//#define MAX_PATH 255 + +#define KErrGeneral 1 +//#define GPAC_CFG_DIR "/data/osmo/" +#define GPAC_CFG_DIR m_cfg_dir +//#define GPAC_MODULES_DIR "/data/osmo/modules/" +#define GPAC_MODULES_DIR m_modules_dir +//#define GPAC_MODULES_PATH "/data/osmo/modules/" +#define GPAC_MODULES_PATH m_modules_dir +//#define GPAC_CACHE_DIR "/data/osmo/cache/" +#define GPAC_CACHE_DIR m_cache_dir +//#define GPAC_LOG_FILE "/data/osmo/gpac_logs.txt" +#define GPAC_LOG_FILE m_log_filename +//#define GPAC_FONT_DIR "/system/fonts/" +#define GPAC_FONT_DIR m_font_dir + +#define DEBUG_MODE 1 +//#define DEBUG_FILE "/data/osmo/osmo_debug.txt" +#define DEBUG_FILE m_debug_filename + +// keyboard code +#define ANDROID_KEYCODE int +#define ANDROID_KEYCODE_0 7 +#define ANDROID_KEYCODE_1 8 +#define ANDROID_KEYCODE_2 9 +#define ANDROID_KEYCODE_3 10 +#define ANDROID_KEYCODE_4 11 +#define ANDROID_KEYCODE_5 12 +#define ANDROID_KEYCODE_6 13 +#define ANDROID_KEYCODE_7 14 +#define ANDROID_KEYCODE_8 15 +#define ANDROID_KEYCODE_9 16 +#define ANDROID_KEYCODE_A 29 +#define ANDROID_KEYCODE_B 30 +#define ANDROID_KEYCODE_C 31 +#define ANDROID_KEYCODE_D 32 +#define ANDROID_KEYCODE_E 33 +#define ANDROID_KEYCODE_F 34 +#define ANDROID_KEYCODE_G 35 +#define ANDROID_KEYCODE_H 36 +#define ANDROID_KEYCODE_I 37 +#define ANDROID_KEYCODE_J 38 +#define ANDROID_KEYCODE_K 39 +#define ANDROID_KEYCODE_L 40 +#define ANDROID_KEYCODE_M 41 +#define ANDROID_KEYCODE_N 42 +#define ANDROID_KEYCODE_O 43 +#define ANDROID_KEYCODE_P 44 +#define ANDROID_KEYCODE_Q 45 +#define ANDROID_KEYCODE_R 46 +#define ANDROID_KEYCODE_S 47 +#define ANDROID_KEYCODE_T 48 +#define ANDROID_KEYCODE_U 49 +#define ANDROID_KEYCODE_V 50 +#define ANDROID_KEYCODE_W 51 +#define ANDROID_KEYCODE_X 52 +#define ANDROID_KEYCODE_Y 53 +#define ANDROID_KEYCODE_Z 54 +#define ANDROID_KEYCODE_ALT_LEFT 57 +#define ANDROID_KEYCODE_ALT_RIGHT 58 +#define ANDROID_KEYCODE_AT 77 +#define ANDROID_KEYCODE_BACK 4 +#define ANDROID_KEYCODE_BACKSLASH 73 +#define ANDROID_KEYCODE_CALL 5 +#define ANDROID_KEYCODE_CAMERA 27 +#define ANDROID_KEYCODE_CLEAR 28 +#define ANDROID_KEYCODE_COMMA 55 +#define ANDROID_KEYCODE_DEL 67 +#define ANDROID_KEYCODE_DPAD_CENTER 23 +#define ANDROID_KEYCODE_DPAD_DOWN 20 +#define ANDROID_KEYCODE_DPAD_LEFT 21 +#define ANDROID_KEYCODE_DPAD_RIGHT 22 +#define ANDROID_KEYCODE_DPAD_UP 19 +#define ANDROID_KEYCODE_ENDCALL 6 +#define ANDROID_KEYCODE_ENTER 66 +#define ANDROID_KEYCODE_ENVELOPE 65 +#define ANDROID_KEYCODE_EQUALS 70 +#define ANDROID_KEYCODE_EXPLORER 64 +#define ANDROID_KEYCODE_FOCUS 80 +#define ANDROID_KEYCODE_GRAVE 68 +#define ANDROID_KEYCODE_HEADSETHOOK 79 +#define ANDROID_KEYCODE_HOME 3 +#define ANDROID_KEYCODE_LEFT_BRACKET 71 +#define ANDROID_KEYCODE_MEDIA_FAST_FORWARD 90 +#define ANDROID_KEYCODE_MEDIA_NEXT 87 +#define ANDROID_KEYCODE_MEDIA_PLAY_PAUSE 85 +#define ANDROID_KEYCODE_MEDIA_PREVIOUS 88 +#define ANDROID_KEYCODE_MEDIA_REWIND 89 +#define ANDROID_KEYCODE_MEDIA_STOP 86 +#define ANDROID_KEYCODE_MENU 82 +#define ANDROID_KEYCODE_MINUS 69 +#define ANDROID_KEYCODE_MUTE 91 +#define ANDROID_KEYCODE_NUM 78 +#define ANDROID_KEYCODE_PLUS 81 +#define ANDROID_KEYCODE_POWER 26 +#define ANDROID_KEYCODE_RIGHT_BRACKET 72 +#define ANDROID_KEYCODE_SEARCH 84 +#define ANDROID_KEYCODE_SEMICOLON 74 +#define ANDROID_KEYCODE_SHIFT_LEFT 59 +#define ANDROID_KEYCODE_SHIFT_RIGHT 60 +#define ANDROID_KEYCODE_SLASH 76 +#define ANDROID_KEYCODE_SOFT_LEFT 1 +#define ANDROID_KEYCODE_SOFT_RIGHT 2 +#define ANDROID_KEYCODE_SPACE 62 +#define ANDROID_KEYCODE_STAR 17 +#define ANDROID_KEYCODE_SYM 63 +#define ANDROID_KEYCODE_TAB 61 + +#define ANDROID_KEYCODE_UNKWON -1 + +#include + +typedef struct _JavaEnvTh { + JNIEnv * env; + u32 javaThreadId; + jobject cbk_obj; + jmethodID cbk_displayMessage; + jmethodID cbk_onProgress; + jmethodID cbk_showKeyboard; + jmethodID cbk_setCaption; + jmethodID cbk_onLog; + jmethodID cbk_onFmRequest; + jmethodID cbk_setLogFile; + jmethodID cbk_sensorSwitch; +} JavaEnvTh; + + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- +class CNativeWrapper { + +private: + void* m_window; + void* m_session; + + GF_User *GetUser() { + return &m_user; + } + GF_Terminal *m_term; + + /* + * Callback management + */ + JavaEnvTh *mainJavaEnv; + + GF_Mutex *m_mx; + GF_User m_user; + GF_SystemRTInfo m_rti; + + int do_log; +private: + char m_cfg_dir[GF_MAX_PATH]; + char m_modules_dir[GF_MAX_PATH]; + char m_cache_dir[GF_MAX_PATH]; + char m_font_dir[GF_MAX_PATH]; + void setJavaEnv(JavaEnvTh * envToSet, JNIEnv *env, jobject callback); +private: + void SetupLogs(); + void Shutdown(); + void DisplayRTI(); +protected: + JavaEnvTh * getEnv(); + +public: + CNativeWrapper(); + ~CNativeWrapper(); + int init(JNIEnv * env, void * bitmap, jobject * callback, int width, int height, const char * cfg_dir, const char * modules_dir, const char * cache_dir, const char * font_dir, const char * gui_dir, const char * urlToLoad); + + int connect(const char *url); + void disconnect(); + void step(void * env, void * bitmap); + void resize(int w, int h); + void setAudioEnvironment(JavaVM* javaVM); + + void onMouseDown(float x, float y); + void onMouseUp(float x, float y); + void onMouseMove(float x, float y); + void onKeyPress(int keycode, int rawkeycode, int up, int flag, int unicode); + void onOrientationChange(float x, float y, float z); + void translate_key(ANDROID_KEYCODE keycode, GF_EventKey *evt); + void navigate( GF_Event* evt); + void setGpacPreference( const char * category, const char * name, const char * value); + void setGpacLogs(const char *tools_at_level); + +public: + int MessageBox(const char* msg, const char* title, GF_Err status); + int Quit(int code);WRAPPER + static void on_gpac_log(void *cbk, GF_LOG_Level ll, GF_LOG_Tool lm, const char *fmt, va_list list); + static void on_fm_request(void *cbk, u32 type, u32 param, int *value); + static Bool GPAC_EventProc(void *cbk, GF_Event *evt); + void progress_cbk(const char *title, u64 done, u64 total); + static void Osmo4_progress_cbk(const void *usr, const char *title, u64 done, u64 total); + +private: +#ifdef DEBUG_MODE + FILE *debug_f; +#endif + void debug_log(const char* msg); + +}; + +#endif diff --git a/applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.cpp b/applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.cpp new file mode 100644 index 0000000..a0cdfb3 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.cpp @@ -0,0 +1,200 @@ +//#include "wrapper_jni.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include "wrapper_jni.hpp" + +/* + * Class: com_gpac_Osmo4_GPACInstance + * Method: createInstance + * Signature: (Lcom/gpac/Osmo4/GpacCallback;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jlong JNICALL Java_com_gpac_Osmo4_GPACInstance_createInstance(JNIEnv * env, jclass obj, jobject callback, jint width, jint height, jstring cfg_dir, jstring modules_dir, jstring cache_dir, jstring font_dir, jstring gui_dir, jstring url_to_open) +{ + jboolean isCopy; + const char * s1 = NULL; + if (cfg_dir) + s1 = env->GetStringUTFChars(cfg_dir, &isCopy); + const char * s2 = env->GetStringUTFChars(modules_dir, &isCopy); + const char * s3 = env->GetStringUTFChars(cache_dir, &isCopy); + const char * s4 = env->GetStringUTFChars(font_dir, &isCopy); + const char * s5 = env->GetStringUTFChars(gui_dir, &isCopy); + const char * s6 = NULL; + if (url_to_open) + s6 = env->GetStringUTFChars(url_to_open, &isCopy); + else + s6 = NULL; + CNativeWrapper * gpac_obj = new CNativeWrapper(); + if (gpac_obj) { + int w = width; + int h = height; + jniLOGI("Calling gpac_obj->init()..."); + if (gpac_obj->init(env, NULL, &callback, + w, h, + s1, s2, s3, s4, s5, s6)) { + jniLOGE("FAILED to init(), return code not 0"); + delete gpac_obj; + gpac_obj = NULL; + } + } else { + jniLOGE("FAILED to create new CNativeWrapper() : not enough memory ?"); + } + + if (s1) + env->ReleaseStringUTFChars(cfg_dir, s1); + env->ReleaseStringUTFChars(modules_dir, s2); + env->ReleaseStringUTFChars(cache_dir, s3); + env->ReleaseStringUTFChars(font_dir, s4); + env->ReleaseStringUTFChars(gui_dir, s5); + if (s6) + env->ReleaseStringUTFChars(url_to_open, s6); + __android_log_print(ANDROID_LOG_VERBOSE, jniTAG, "Returned Handle = %p", gpac_obj); + return (jlong) gpac_obj; +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacconnect(JNIEnv * env, jobject obj, jstring fileName) +{ + CAST_HANDLE(wr); + jniLOGV("connect::start"); + if (!wr) { + jniLOGV("connect::end : aborted"); + return; + } + jboolean isCopy; + const char * cFileName = env->GetStringUTFChars(fileName, &isCopy); + + wr->connect(cFileName); + + env->ReleaseStringUTFChars(fileName, cFileName); + jniLOGV("connect::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacdisconnect(JNIEnv * env, jobject obj) { + CAST_HANDLE(wr); + jniLOGV("disconnect::start"); + if (wr) + wr->disconnect(); + jniLOGV("disconnect::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacfree(JNIEnv * env, jobject obj) +{ + CAST_HANDLE(wr); + jniLOGV("free::start"); + if (wr) + delete wr; + jniLOGV("free::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacrender (JNIEnv * env, jobject obj) +{ + CAST_HANDLE(wr); + //jniLOGV("render::start"); + if (wr) + wr->step(env, NULL); + //jniLOGV("render::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacresize (JNIEnv * env, jobject obj, jint width, jint height) +{ + CAST_HANDLE(wr); + jniLOGV("resize::start"); + if (wr) + wr->resize(width, height); + jniLOGV("resize::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventmousedown(JNIEnv * env, jobject obj, jfloat x, jfloat y) { + CAST_HANDLE(wr); + //jniLOGV("mouseDown::start"); + if (wr) + wr->onMouseDown(x, y); + //jniLOGV("mouseDown::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventmouseup(JNIEnv * env, jobject obj, jfloat x, jfloat y) { + CAST_HANDLE(wr); + //jniLOGV("mouseUp::start"); + if (wr) + wr->onMouseUp(x, y); + //jniLOGV("mouseUp::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventmousemove(JNIEnv * env, jobject obj, jfloat x, jfloat y) { + CAST_HANDLE(wr); + //jniLOGV("mouseMouv::start"); + if (wr) + wr->onMouseMove(x, y); + //jniLOGV("mouseMouv::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventkeypress(JNIEnv * env, jobject obj, jint keycode, jint rawkeycode, jint up, jint flag, jint unicode) { + CAST_HANDLE(wr); + //jniLOGV("keypress::start"); + if (wr) + wr->onKeyPress(keycode, rawkeycode, up, flag, unicode); + //jniLOGV("keypress::end"); +} +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventorientationchange(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z) { + CAST_HANDLE(wr); + if (wr) + wr->onOrientationChange(x, y, z); +} + +/* +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_getdpi(JNIEnv * env, jobject obj, jint keycode,jfloat x, jfloat y){ + CAST_HANDLE(wr); + jniLOGV("get DPI::start"); + jclass cls = (*env)->GetObjectClass(env, obj); + jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getdpi", "(FF)V"); + if (mid == 0) + return; + (*env)->CallStaticIntMethod(env, cls, mid, x,y); + jniLOGV("get DPI::end"); +} +*/ + +/* + * Class: com_gpac_Osmo4_GPACInstance + * Method: setGpacPreference + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_setGpacPreference +(JNIEnv * env, jobject obj, jstring category, jstring name, jstring value) { + CAST_HANDLE(wr); + jboolean isCopy; + const char * scat = env->GetStringUTFChars(category, &isCopy); + const char * sname = env->GetStringUTFChars(name, &isCopy); + const char * svalue; + if (value) + svalue = env->GetStringUTFChars(value, &isCopy); + else + svalue = NULL; + if (wr) + wr->setGpacPreference(scat, sname, svalue); + env->ReleaseStringUTFChars(category, scat); + env->ReleaseStringUTFChars(name, sname); + if (value) + env->ReleaseStringUTFChars(value, svalue); +} +//----------------------------------- + + + +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_setGpacLogs(JNIEnv * env, jobject obj, jstring tools_at_levels) { + CAST_HANDLE(wr); + jniLOGV("setDebug::start"); + if (wr) { + jboolean isCopy; + const char * string_tools_at_levels = env->GetStringUTFChars(tools_at_levels, &isCopy); + wr->setGpacLogs(string_tools_at_levels); + env->ReleaseStringUTFChars(tools_at_levels, string_tools_at_levels); + } + jniLOGV("setDebug::end"); +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.hpp b/applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.hpp new file mode 100644 index 0000000..62f827f --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/jni/wrapper_jni.hpp @@ -0,0 +1,83 @@ +//#include "wrapper_jni.h" +#ifndef WRAPPER_JNI +#define WRAPPER_JNI + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wrapper.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; +// __android_log_print(ANDROID_LOG_VERBOSE, jniTAG, "Handle = %p", wr); + +/* + * Class: com_gpac_Osmo4_GPACInstance + * Method: createInstance + * Signature: (Lcom/gpac/Osmo4/GpacCallback;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jlong JNICALL Java_com_gpac_Osmo4_GPACInstance_createInstance(JNIEnv * env, jclass obj, jobject callback, jint width, jint height, jstring cfg_dir, jstring modules_dir, jstring cache_dir, jstring font_dir, jstring gui_dir, jstring url_to_open); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacconnect(JNIEnv * env, jobject obj, jstring fileName); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacdisconnect(JNIEnv * env, jobject obj); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacfree(JNIEnv * env, jobject obj); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacrender (JNIEnv * env, jobject obj); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpacresize (JNIEnv * env, jobject obj, jint width, jint height); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventmousedown(JNIEnv * env, jobject obj, jfloat x, jfloat y); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventmouseup(JNIEnv * env, jobject obj, jfloat x, jfloat y); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventmousemove(JNIEnv * env, jobject obj, jfloat x, jfloat y); +//----------------------------------- +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventkeypress(JNIEnv * env, jobject obj, jint keycode, jint rawkeycode, jint up, jint flag, jint unicode); +/* +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_getdpi(JNIEnv * env, jobject obj, jint keycode,jfloat x, jfloat y){ + CAST_HANDLE(wr); + jniLOGV("get DPI::start"); + jclass cls = (*env)->GetObjectClass(env, obj); + jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getdpi", "(FF)V"); + if (mid == 0) + return; + (*env)->CallStaticIntMethod(env, cls, mid, x,y); + jniLOGV("get DPI::end"); +} +*/ + +/* + * Class: com_gpac_Osmo4_GPACInstance + * Method: setGpacPreference + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_setGpacPreference +(JNIEnv * env, jobject obj, jstring category, jstring name, jstring value); + + + +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_setGpacLogs(JNIEnv * env, jobject obj, jstring tools_at_levels); +JNIEXPORT void JNICALL Java_com_gpac_Osmo4_GPACInstance_gpaceventorientationchange(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-hdpi/icon.png b/applications/osmo4_android_studio/app/src/main/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3f988c171da4efbca50470c576d8aae36bb9b1b2 GIT binary patch literal 9339 zcmV->B!t_EP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_001BWNkllIzhlOnlf*2>eG-?6 z8OP`-Q88{r!7TAA_kg!Ay?5WWs(ydG+fBd6dkBe>{4;ejIx*d;0Rr@sDbcFIa%zFI@Pkk1Kzgg9#x{`2FwKt<#SD;0F=W-5n3d<54@2h*-&F zfO?*!8ip#Vs_fdf>)19EggAkk8dE4r+6L0$v18NGOD|1db<<7u-xGN9w+`^siWT_R zKl}lQha7+Aop;dnFaM%ChYxG2qJ$JhiBn0caZ;%!;W$ltDAeGZX04mc#VKQoq-jB_ zC@OOt%X3{v5Mrv4NK#PR?J?G_1cRNB)>$}a%%F2WbioB6 zgy0*mzWR@65Fx{3Y^_-nqK-3BBIInI&Cc{(cY^G?H3nl*g>zlWU^B2F^3!reSZ2n(o&|CB7 zp;pr{`K`A~#~!%rF2#G~k<(aL*EG#>rf7^!Ru~(na^9?RUafJi=|VsUp!!_~K!;3( z17HAL01g1F*eQigsclPApF_wIhmie_B<*9Gwu@I(>}uGzZ~tmScyXLd0DSAFn;?Y1 z=kLG&e;=Sn&pQu72#kOGZ7lMStrh|c7c5XoZ*Q1b*6FaU1t=6gt2)k^hU->_0fYbq z{H_B~d|>2(35a3lA^;Fp29)iCQ~;0zkO7b*1g0z}JyrdX8^-G}j14>#I>;3z^PTP6 zo$|RqvUDl_Y5n^DT@e#PfDnRlWyj9C^;TWva%b{%`b%;qv)Hh#Nl`-ds1RxtKm>qM zcA|22nErc?V<^FAl;n3AfaZf+{J-OalokSM*NvuKcVWgf&&;dpa<5Q$O{uSc@$Hvi z-n8hVi@d*8S=bnNc&<0mM|BqWI!B(bOLkNLejvV>)0Q&vK7lROjRWH0yI(FyTXRCqs_A!!ee^Jio zmm9V{uYz+_`4UrKpjA;0aO!$3IHJ?APq1|WPH$j0i+0V3x=`P3k05$8XMPgNou?K!w*aD!LO%J z$MxH`eL5mW2sw_P^vIC~qEJ|+<#Nm7oHtejsP^wT1&GfS^ihi5NCZ2Dz&6XmA;&?& zSGJrG2udLc0Uv4+g#ht8gn-OBG|o{0U<{?06%1ms>td8;p$0%0K$ZU*0njUi(pxCZ zNV#rx&a$S{c>LbGZoYZzckaE{J5_NzA%h-hZpIBqkCs0FcIC=oZvFaYx@le-a-1cV zp4V6dpwbs72S5ryx1u1aC`U88zT1w+_rL3Tq4zVH$*tM!EJp|hk|YQrpp-)LQ6YqY z6m^jh5C9nGU_uCRPQW=-Ld-fBh2uskfI43BeNFs4XCNCrSc1J+VV0O6d6UCz${A&T4H-g|LFL+?x7-Ofvi1YSxc z@ZiFQc<}@}>7=b#?u|E=>8|^&xMj_$;XGV7pl{#;qzga?A?OZ;T6-!hUv&)QnS3y~ z+om+7tXN^c_nq%_jGZungu~%Qj%|lL&x=w@K`AAKkdkN>Uxg5*UKDXzmZ53d#>VF6 z|0cSAWXIgO?(CM9R&V0Omv>|`OOK>dUzpU{Id_a{YR#M@0uZ_AYjH036bcumTU)D? znwr~xf9tKAzIx}K_FpYx*A-oM0FPXFp<39sZGIq?x+d&6m(?>CtQ)W>Z~^oXf=*e^ z_38S1ec|x>j^^e!-oELkZJSrG9yEd3vuB4gnas*mDs{DO+Y2eB@Wo6Vld=*(q6iRU zi~w*oP1_L&1RmJ8ckg4Wrg`OKFSzo`F{ka>bI!P)p3gU?(+isN`Oy;{=hz$pv;pX* zG@TCw*0_<#TyKMr^X1^J+?Pb-T zSJ~v7UJjrW5bcVR><$DzXs@sT?ZH{Ip1ptl`h6YGKFa{$mWwY&ZF4jBwzS~OU;eUZ z7)EDTS68DDVkQ8YQc5IA!caE(?~4tRB=tw5(I?{Z_^aRk_P4tMVD6MDXz%R>036-6 zEmiyCi@W;w?dxZzsk)w5ExWFvb1sL=+zlp#RuE#G5F&rctXT&ypED=BcF!LE zJ@;?`ol~byeMi%@Y1wS{d?AG4gEOLtDT?CBvV1TajlS@~2OsPz{w5rY4H|#_%$e-0 ztFHQUbmGKr8Vv3;+uCk2)9JC(EDLb}H3Lp5v0XQor1ZkvzI~>gPTvEd@1&IUgV$Y$ zi)YQkjqBF~Lf{8IJz9Lzri%iF!q=)CXL18Ts{nYub?8u({$wchbgH7_sm;Io)yDgO z_OmbO%dQ(^p4Sj!3_+hs9spa2xXXEfQQGp^nKQfB9X@OW!0(nU!P=IV;Tg33p@&Kb ze>rQGO7rHVv(zS?o_x#w;u6bj2+*Nt(`D7r!`QZ3)5Cz`l!q{p&~d2Of}JA!>t(M6JS@5(Y#qKrGG` z+qO^7o8~26Yikm~I{@SO+PdWgU<=)E5$~DPkGG^QM1x25zsDn7?0O07lzC~5ljW4|L!oE|Dsb0SR z`p)o07dThD+VZcYpS?0DxQm z^d|tog&Q}@;wxX7XykH>BCb2O3P8}0dHMh^Z5TUp!Qi^?Idk6r$rDdx0pQ*R3m}BR zKl|(%u3he@W7n)%gPAjD=G)ub|6C{(rU016Ij^CVN=2pYgVh@d1fGvXBAbe1Oq(_h z4?q0yu;c&s`R4~L@D*3!p(mdl@aOKlbJw-kU$3jV-09)IzQxg8uBskDd>{stGOk-I zT=(p^X3w7YD)1fv=fC{4?N#r*GrXDq(V1tCuk7w#UeVqCgJvK;%6A02034B|p5E%} z-z2N6pSpF&j$HuoJpjM>D|1To=FMATS=Ki!%en|axXkotB}saxrl#imufF=~j&hLK ztXcDk<1TM%0suVM)`l;wTxqEN{mbX>+obBLwSy_Oo2J@cNqb8E|!gM*ZG-OqleD2_8pXKZ57b)yk~5OW}X08^5-TFuSt97V|kz=KPd zmO_D(Y3KPTyzjpI1|84m^WCvn?Aflau3FFY&JP3vn+PF){@w3>SBjFKd+xbmb=gSm zM?d-z0O0yntMKb5o*1ywix=;#e&daoySuyR$2bp08AHftQj+sX#x&|A4K=Ru zQ^_R;DJ?A;?dUj5Wo&H3PhD^TS%BqLHDOV@GqHK|w(q|Cu3Mg6Je6$Za3Zo{!v<%= zh7ErrguEq5(iT-!A09Po)W*MMd1<(|<>x=|k%ai5BN{!_r|WjXPyhPYsu9PTMGA#6 zBbs?hRYOW9GgIfhIpjN4=0M)pc2xBvSJ(IaJ0T@``qnT$!_YQo&KwXzuxZmKy#4mu zgT6ca?6WIu+pfyz^YK6+pf@%)Ht4#J&d$#ImX?;eO-)UGfj}TRYSgHn_3PJ{JoIwr z6j}LJ*}_42E3&8997*a<#A2Isg+gNnm=N+UbVvwQcHQv`A)}wZ;|^`!_rGtC@^Ahz zfGCY?jx$l`yxLEE!5YZ@7KE<9>qVo7;Kx2styqDTpP&z>PMtc)LA>CC3#8q$x+$gU z+S*!c^mRoKaNDtqAH@YGbOAiL$HG6u_ND(rj)=%vQ0jhak zwJXbwy=&LjKEGi@yPqx}0BFUXcWTnzch{(nQ*AJ&8UD8>0F#hBlca6=(WBdO;J^vj z!cHU-3l}bIAcUNs%jFh%o;O1XQB5fgQc4wF*Qx8eN;;jUl+t>?cT#~wr z01*KA=2>S|PdI#dSxtZcPsecHe40OS8-Sydw3RnC{nJ+tAKr2@7HX&xUbt{!U2ALW zT+6b~<($s~Fqu+XPbq~YNswh3ilPk4331Nhd0we=&IN!j&iNkB`IbN+urV5qzPEe# z?#|+QmMmEULI~D>($bC)$}bxlzE_*g{@a{KUk)G6 zl^7JvX5&PNW(^2v{=ve4%v!FZ^lG}^`w9LG2qA;OS-5Z^X=`h1Xm4-7z_#rbuIqk= z5Mn5b0$takswz}fg`y}zQ4~m$G$|WAt}Dxxd1%Q(~PkWme0EYu<_120RZ!F zy>-wDckeDa)>yV|8EtQGpW55odzs@nD=4Moi>%Q!4Z5z2;(JZgh^A?z$fhDloO9y3 zE^OO|WmzyyQ~2KzN+|)LIgWF>>$*xyOH1;!(@uM~wY7B{0K8Y0M=x)``OR+qO%Y#(|X|UV1HdAp|u|b2MY@3vF#}h1S;AM*!p$MLFR->&J~l zLr5Dj^}7&r{;dumB(=2~^jGpcKgEhOg`z%$^yx zZLb6{UXmoLC<@9t8S=TLdweC0V!$edfFwy!6a}iP!t*>Z#=saOp63bwz3@L1#@LK( zHk*sZVs8o|wicEBg%@6kb?eq0H|JPQ4UC>1a7w{_l|li4bBTMNCd&L63IMXIDpXMn zLXLeS1~fjXuNQ{4i!Z(y7yGLLLI~V{|NUB_P?%@i_A*MTAxw5CU<$ zv7zOPUdF(RD0cym1EsGh0JyGjQz^kuQ0V~xlP6Esg%Ia*&S!X@r|Y_Y92iAFieQwl zhZRMKF;>hbmc*#E>gp%bisKd;=(;WxMS&2)$mjE4v~9Z$z|j+l7_%%0*98@#R9qnd zfKpCn*%D^#0Fj+La7N##b7hfm}N7TVM1_Lw%j30lA#3xQ3g=ta`=lM*DSdE?x8v6 zxMf*q2_c%xMQ0?&l(UdAHb@y4e^bt=@=U-Gph)qCP)aH1yjln`Zs*ROqYoT7u-`Yv z$Cn2lJV?CWUNRIQE`-TA&v2CLDFzrM!eI-#p7jVR0i*(;ltw{FJvf)jCpW|gQgvOg z_dKtWa~>=QW$1s(*Sm@U6nlASQPe|a%6Sk_BQUCXyfK^2PU`RPS4U!y-qAtTR7z2O zfJ#MOj+4!2v)%bzjtydvh(@z;-CmmzX8C_m0Z5(~A*NX$YHA9gzaR7Oy6d=;U3Jw} z;Y1?Qz&Vc%VNQAIaGXdLJ7a9nMGj?GIY32_h6bX(e?%yy@I0@kx3_m3=Ugc|hydVi z*nk`TR7u#jBRXUC8X(iM5d(m~r7FHX6X9?dICHYZ82eQN0gAcf&LXUN;P*BAfv z?4_5MD`-`g<-l+&BqK4W_&OX2BY`xWxRrrbD#D_aDzYr=ilQ9ny#2qGE2VFI?sLtW z=QRdgH=+TQ7xP|}!U4KH!#He5BHkc?TE6+sf{>(+tfuwkWZ5x&Gj9M02oaDR=PWs$ zF6C>#w07-K0LVzJDe97u7&H<{#XcN3Lv>PlxlEBzY?#%S>W@BBWBc|^)fpQd6atE` zfARpgC`~(*wv&YmJ2LCmdB-jLFhxmZVzC2xMd{1>dPoNl7DAT_g|p>+e&VoB7h?`% zEHA`>KRKK@4ab<_EZ0cvDF>^a}YC(Xp2_c^Z ze%{^j6y*R@l$L*c_+j&xwYA5ui)9TXmx)HV6eQ_L$}i8A2MQx4-Ery^&zt(_{P~j~ z{M_dTQMXVi6fDb16;qTW>71eL8A;E4k{%kWzx;ENvh!Jtv2-q%^M+Q58KF?UVVY+L z7#kJx*^?Q_yE~quY;|?Lb;O0kw(4rDzpn0syeuC~$TBj%x%adF&>1^}96frzdf-5) zd;r&VvyS6*`<8Oh9X%DXDhFpMn}&MV!&$bn^QHlG6$*txmG<{8U0SVJ)~t}@Ob#$+ zXnxkzuh`Fdin7^>$4j~H;?}MbKs%m!#<5qg-jz0tz1_iJI!Oq(eQQ<;AmDk^XfpW) z8K@hwYLE^FgY5t^Cu6Zjatwzu=TwE&_GV-f#Y z20)rpkyn%s1Ogu(+P%AdXlAkmP&*-bY1OJ+Z#=#;6^U$45aOhKT@(WlWh@l5?P(;P zUiR>`X`@O@*5CfNt0+pBEXzj+qL$L6#fik~lN9t&MxBgB^DS9hRaMpArn|&#b};y^r|U=mt1L(@E^E;nZnyzA+;Bq)>DIAhcV=R- z*ZLGC)k6q!{*p*c2t+-vS~1N_m7bpYFMa>}Qkj$2Zy3gQN@>TCJ1hJ?=)z7#Q4be( zlz}4{W5V~5xFktQNs?NYEM40A&U^2<0Py&P36aR5L+6KGcVWcyYQq2(e!W2wfGNv6 zy~@hh@&mQ+xNpf4+_z-O$kiQhJonrILCEVz(^XI6A!bQD* z{NsWLr%oM6`p07Vy1Kg8B}v*_&YGbYb|R*f12NRhk0fG4ESjV1`c}g*cK`AhzsM6p zaPw=gNwRHEGJ1QjiMa0B)qW738Q8MGld762$nvKA!iBHzdh$tgxFvG=fd?KKx-23J z^X9dgpO;alPi6*-AS7)rjNF ziZd38_-4HqKtCatsq3#>fx!Dee)Q2i9(@!5aP#Z04`0N2jX+(3`xO)09=x!oplWj_kFx$$H(toaDlY6qN2&@>|7PFtgqF0 zUUh|^Z}0Yt-uq>60b_0JiPji3U0HgDVZY#~I& zkjR^yC{`N^)KJfPs0A#7!x)3As#~Jb=;Mcg4M--P^9^I1eDvt8QPaG%#&MeK07?P$ z`>Vx$nszu9jjm&n$P>5k*io`vOUI5K8K7-@_hQ@Ly_f-@3&8IC?h{S(=jT+@^tj_p zri@h>jFEsJf~bJxaUK(lRXC|sm=D%KWLED{~Oj{_M4RX(`VT@Ikfg{R5AmuC> zPLzf?nMFlU7-OUe4(A+-q8uQa_M|#`^qM=SPdC5O+dD_}WPEDUay*J}H zqh!~uR%|<}`n&&vzNhUmR^u@?0hB7)y?fL14WlDjQ`6C($rzsJohF1Zgb)+}DFRdW zdR)v_&Y%(4Ll|RVoC`w8kx(SEwkj5T;cz5!v}ezrxgwqZTEMbaRy$5pl@KK0Z_Vli z&`D{oKNR{P7YID@!=p!Ed3X124ghm+yAAf@#lx1-eBx%7L}g_=<@}xw%W^y+u9nhi z145wE-^`)_&^)iQFPXd|Ynl@xoWFAAlqqX}HEr5so%{E9=M#yWnCCTlo;N6o?>lv$ zn0YJ@C5kQsV+^XU?+M0Y&$@MWkA062<(Zb2tCVE&im2;OsbnltoPXC={k-g_!TT?u<+-6#?f|mSxCgmTaU1TT#qB z#^87!6jg<07)e=Gx76wS`wJE2z}b=@;#oNHlUG*Uiu+GUybYuaB@ zq0kz3`sq*q=*>5Kis$*^lqtA<*RE6BFZSV%9r$p^4qSfWh1hlA0C4;50?$3y5!|`6 zJD<w3j$DtP~mwEE@Sg#$Eh8|dG5T%#$8%NgRTdIW4Y@F2|$S- z=W))#I0qMEVDp^cy`t_ZmIq1_0;-DoiV94qukT;n*tq^Hl5}`}M@OA(npf+V_4&B# zHrEOv7qfbO0NMd`NK&>t5ZILrh5q}sOD}!w@n@b%0>Dp}EWu~SjKOW2Hhns~o_EZh zYmHyN{6kS+|KnCg`C2XzxWek|t22Ej#r$oN5dbO9Mas6Pr(Jh^p-?C+n>bOo$Bc<| zj2kC?+~1F#ZEa{zB#_Kz;o5e&4_4Ze2|}Q18lu4)&#P8;?fRO2 z^r$CivuXnnjsbGe7l)h=PB(x~P0RO%bC$K3A8^O=~dCKojQ!b;thYnf_$6k_28+0ajft z(t!Yu+BObnGNjwGkg#p!JP$4*aD@Q(7xENJp%a1tA*j$a)CU3>9S&oZs)`ERCZwYS zY9@n#=M6B|j~O%m-mo4@(XZ<*X*R5Ej;L3QpHa~W&Oajmk`!RshLpK z!~NCO>oXM6W{@|1+toADWew%i8<sM}Awhh}~AaIM>Hvf*v{>7_)k!A5w7RAR{2tWCh_F0nv z&_@V*!r^2#7<|o)#nuX4e@~1b--)skn7^ic_>`(KufOujf%4kN9xEL?{gFokWB>Ta z36+Nqon4j9&WoGo%&=vRsj%%>mE)jV2o!hyDLD3=4pF9U#4wW@`p635i;+_-ZU>O0 z6e&fqvx;&!uP8gSs=7HHi@kqz?%W+~AA4-jzKef8?>yWyLb>p#22e?cZ@dxr5A(2) z&#zuRT|07QNxZFXK}|Y6xu#I4t#n-@%()r_q@WNaAVkp{A!9lWEy- z_+weq4!c!V&-GMSPfoh-95t7l7s%x%g$jkbsN)2}j)S1*!6;*uRF-!c792v5mu2J? z#mj42pJf;aEnVN@==%FaRd;&2-f2rx=Ix*U)W#im9H$!omPh6M%@0`m&b8O#uK)bc z;}_^2dMGq@{rcv3TidvBBGDWy6zYSXS7$I*qjFv;F&34C2+Ke~rc|Yb6v@Px=UEJ`hXQ8|z6iekusMueb(5ZAG+jODs1 z5)7t!FxcybLLF{2+L~!-Xn*;>`+8BfC8F4_yKZ1J`$J`0OFxbFcYB7}mMgBv&D*{E zfM!{(RF)M=sYEE1B!DtPC^@!oUNA~IBZPxe&LxSts_I#RfY&!_l!p^+0sXX|I`wyH pPe1+i-{l-nJ@pj+ul)nt{|7R@mQGMjbOrzb002ovPDHLkV1mi&^#A|> literal 0 HcmV?d00001 diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-ldpi/icon.png b/applications/osmo4_android_studio/app/src/main/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a7bbccd4c8ed88d887446cacac19c5e84a20b9c2 GIT binary patch literal 3105 zcmV++4BqpJP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_000ZLNklcy_QRXeVW0(`g$yHX#oH{{*7-aqkHz$N`^7p zkxErKMKOl4F`pocs%4sKi{nPq9Ctn=if45}c*70`kKWhb{vQ5R=&u0#3_u+Kbpg~p{{109?EoDE=pbY19URxUNmUR0;JWK7vN4}uzy7l; zw56;J_rCKER>kA&FHH0EVsG!Gfn;)e5r8}Z1Yj7Tet?YvFadA?6aX3kF8~q15P%N> zyw7nM^Lif=!r|}T{pOpOK9eeYZn*^j@ZI_IrDm6_=>W$WZ;h+)4nRLs6uOt=Xc1#} zInPsp!$Elt2L&7sDiQ>`kuh2U&?ACCuQNtH0R0xALjY})q&FT8h2{dlV~ND4!#q}4 z2ml}=G^^_KhXK2Ld}X3faM6kb=RWId|^d1OV)4Y61X6Hg8tGRbKwx15PLP0dyRo zZGzCbDIPEXSeWKDYXAU`PMLDkvm9si0CWD22*uQ^2s;a6004rCn z%quJ`ycCHD#^u~>{Ekq9LciTko~8yg$(S8g}P^8o)?Rkik@BvC&=M*;ews{Zuh zq9WP+wmU0H~^}y0f^rnBws`O`STG zrca-KV$Pg7IZmhZDxbSW%R9v2Gv zL{SFzjpxbaF>~h3EJ!#nFYoWWyStydc=6(|Q>oPKj*gB!wr#)A($ey9I2^wD)TvV( z09=3l^;g7bXlMWc4Cd!Q(#seE093>H+`m^=<^ce{SyCcxm!$n?0cr!RA1liJpENxH z5Rb=K;3?(W{> zcDoA$fdE%fP=H7zg5u(0Or1Iv#l^*lMx)5j&vyxeaBEvzTYGhNb;;qwhp&jYZQC}a zENf7AI^P!oxQOITUtbgexMWwCK)SB+08+M{866z#pX|JHLNpphI2=YW7=+*Nr$8V;q9}&j+S-0zR#q0B9P{qG??x&X zvvf%s1ptXLK~+^R0C2e;4=+iQn*p#G1Ml%%v8;CQ-i^-A&H`Q6H_Eci6h(oms!UN7 zD2f7EmLW+Jc%FwW%TQGnZnvAcTrTA1=8_-?)4RL7?_0chF<+Ohc>s#8yAEP*E+YUu z5wi_L0st-rAOlzcz!Aah@4u=gxpe8${X~=_NfJqt#2gL>c%BDi3`B%XCIem9k;!Dh z7=s`Pa5|k#mSyI2I$_)PSI(R{6K!p6orswk90Zq6g8{G^BTf_z0N@5~+th7)&>EM{ zrD?v&FgteaP?E{youVj05Cm`>2ae;w7=vxw6EM22!!Qh(rU@bfV+=gcLli|2k(V)6 zH#u(d<(C;hFu(vHO=PB0sfz%>AreWaMX@V&Ik_Z9Ds@Fq@W2BPBuvxv@H`KW<5;#> zT9$=OCWCZ34PDofN~MrWr6!=V1(oAC;&~ne0|Rvc(A?aNt@ZT?_V+v7ra8p~kOXvI z)6N3`_ijmvF~sxl4g&B1oS4acZu_iR;!l?>0RR*f6clIShzLY90h3iH3zJnTolZ|c z5fNjI!Rd5H0buRgwOHTM0>SHz=jeL=7=TfZ8y-@WcL9Jq^wd+C0k`}09*)b%0Nkdz zKusonfBo#U007IfKt!-@8@6r3G|dTR48xe1u8%@xG8ver3CpsGh^}gv<=)=E(TLCw zVA$a}y|JyW2ji_U-YqLTdYeYVl@bKR`0h|Y5Xxh$+M+X2r+uGXR77YIS0)P+zxxfFxC+E!z0l?~2 zt4;wJHcb*i zJw1+Rbp4kFp-}s1GWoZ*ZHoXVmi*+r%6>iqO@?7GNfdW?ef6um_Kb`~{U3h#^mNPe zeE^_cmJbj4{SO`)7|6VE?%ZXdE82C^t)4?Z|D-7pFV0ldlc{pTZ*HH~M_ zzCW2^0%*gA4cOe=Z1`u*`rpjZ&@Dm3aK!**lF3Efz`)e1^77^*$z(D;HdbSqCd&d% zR%enzr0Y6k4#$~Laq-u-^zT3HH#^~Jm``s~s{!Ucg30C=0{(cy9(>Wsx6+l~QkSQ`v^8PD4F! literal 0 HcmV?d00001 diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_audio.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_audio.xml new file mode 100644 index 0000000..a197158 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_audio.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_compressed.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_compressed.xml new file mode 100644 index 0000000..3284644 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_compressed.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_error.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_error.xml new file mode 100644 index 0000000..928cd19 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_error.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_file.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_file.xml new file mode 100644 index 0000000..f91cde0 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_file.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_folder.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_folder.xml new file mode 100644 index 0000000..4e5bb1f --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_folder.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_image.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_image.xml new file mode 100644 index 0000000..1d26130 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_image.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_video.xml b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_video.xml new file mode 100644 index 0000000..b9a56e3 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/ic_video.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/icon.png b/applications/osmo4_android_studio/app/src/main/res/drawable-mdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..883b9dc7332c18b1c8c0b428e6cd4c74171b0147 GIT binary patch literal 4070 zcmV@dnWwY!$qIGL&ucSm;$8J#7wHH=IZTA=8v=*Z%_Sx}Hcf*|ApAwZJOt2>?U z^z-(;_v|0tH+Gul<+!h^{i;sguDxTm0RP8@d>cys*xYPMkB?V`ySio@ zZMK=wp`j`!ofdUwb5S~(j7gFdGrHaWlq`1`-R@4-YVCaJrkjGKrA7T8Bd~4NDqWm4c#}3;@vsgv%pD`C(ZU4-m8Y4SQMHzu&ue zZ|J{`z_wMZbfH6snw8<<9~tBEYl~D>C<2HTfC+#B0H3Fr0!RZ$0*C?#0|)^$NQe^E z>$_E(ZL`?W@cT!0?Hc>9BtTl{%()8v{m+V_&~09TxB)l-=m02LfN=n+EMS^7zyr_& z5VHhX01|*8fMEcG0LBENo4DQ2PhYN)&&Ajdu7>P4iIOy z^EiM2fPMfc0dy0BK|(N22xI^Z028I~P>N}kVkUq}0L1`oS&{(&X8}4uh%{lb>@Y1@ z@Y6NBcl*B;0vqe<9NggGOZIU1`&9trL&l>4fc6tYdt9#cJFyu1=Xjipuq+6}fMJ-7 za*|O`DTS)4P*oLrMZpY0)Rk6idSN7@o2Dpm0wkSvLN7pv1mOsZiywUA%$fF!;bSlK za_jQtZso|4*F6&xD`o*q88Ttg4bVdt%fR6oGkz6cw(N<$fxy|}NMs4ivV>(>f``W5>4pVzC=$0*niQAD~A$F8SrOX`2QXEO_AW_wN0m?ZAP+?Af!A#^dotvMg6| z97i~gn?iyR0)}Bg2!UR&57yMw+`ntruA^TL4z|_bamS8!hA}FUNWCeY=DYyR08v%d zJT^9V>+fLuIW3;WUEm~e){;XcFkFhKZj^n`dJUEV<@|)**T3lTG@~yYtdNkXWZrrk^$G3d> z<9p`Me{z@8Iou0SJAhh%l&8~fsju(%t&0~|U1$`}k>7ee>$U@O2S9@WJp|C#MDgTH z*Iv8mLjCIN>;JL1xLEOey|lEnl=^%=>ht+%X=y3-dcA68W#y4aAAQt%zWxubSaH)Y zJf5>(WbJkUbQ_>xJkG%c%+sDq=zrCxgw|e>V{o#?3+g!1jsT3dt zAYneX(o!PJj#6Ycn_i9!2P-Om_~TDM{qjQK0bu*~ z?W10=_ZJ+;rSd|F+U@o?yp>#y(Ynmzl8KbuU^5I{=-_$cMr(b2zoZOM}I z3lfNZ^2t(LIJ~qRAPj)h07gBYU;n71W9P*TYtq=*_>R?TeVgMr%JV#Uo`)a^r>m-} zezAS~cI8rZ_!cjIt9{n2mpfS&41jWgI3>w5e)Q;*=OwVAxmj-*9{yMgI8lL5OKEyB#IF3_FOG{tav17-nOV!cR(xTECGhX__<2f`8 zzz(1U02d0~vn6jrPZCfD2j^R((W^Yj9KQU7C<%|}g~xX94qvKaO}1>=(qpk$UPvaB zGSBmS%FD|)U#^bdZrvIhsI7gWTc?v{03HA~Npgj{x>gh(wx+*{4sq_>ohMwbuf_ms1>gV}M58Md!y_^in!Q6qOT3hl6o64hu_`9hTknsI1OR{o z0AXODLQEvet;n1t!wi#9Y_>mPaPX3VFI>2=s=vQ~&5$E{WXBBhq#$jFrd zI)Q8mNx@*fsH$cWKny^fWrwQQtm(W2?4-7~_TKL9?%nZt{Aq*1P-VB3xU8XFr6Zce$f;D#HzM~%iaF=US8MoJkS z&o^rC833>tjq{9@GWsk5*zH}{JoQxKLW_0?D3wQt|Pk@MLL==DR%EIu6oK@`gn zjebo);CYLd!^!|8LN4h2p`oGML!r=53*CVPAytqpePCy zMIn($yg`ZIvsR6-Q+2h5CU1w%u|lzpwsDKFc@Gk7$69O)|hZO{6Jk@-F4@) zX?8fEWRoKXfGW$A%P0c?DIl%p{2_H7#OH8 zWOt&o6Fj~y(NJKrdcgpIYO#!@vg`~12*cDAQWT5Dsw7F8neS~NllM|eC&8!FX-JZU zR4O$&3K|KT^`@3)vMdWqsVNqVEiPnN=<5>I@3V;y+6Ao8@ zwr<@yqwv*NU)8FrYAys`o0zgJPw{>#l{$xnq9~JuH9ZW&km2Fs#(bLqU{Td8jL2-V zF@Ori#obc~jEUk`5uQ)QvjhZ1arAufK|{VGx7%HcoJxiUA|HId_j8*z9}1BWMbW!y z(H`2mhyZ|S zhI7H^hfe+oq*5uQ)9ERrpeRayNa_84|CCaX;o!k*ZRxZ_k4!~xf?>vp&31SS0dGUY zXwd2WJOEGyfD<5GD0Ih;l`9>&%F^ldIL$~wuWKzAd_I|c6575%DMdP+ode|&Vjmh>S*)t84ZygfSjOY=fw#lq z1KP(t&pT78)M|!dnA}=Vp~+l`WG+!HoN@?LhGG8gqmMp%PqVis8ok2N*Z0dRN_AlX zCkRm^MMdi$IdEVyy`9Vl^o@-lpR(I~hLKrHO98@6S^?Lts%;V|q1E>n15+LTWvHJ&ldmjXVmX;RT z=kxteRaNz3ai2SRbHV42fJVe>wZ2zTQE?Ukw${`%nEn2LsGyWnktzI+h+>yqSNA*Q z$&|X#mt9@SX>;a`>qkazvnmSj1;9|shhwp8Zl68-;9JAPy^lZs_^HE(58seVrOJsG z_*uz~{oF9iU7-q%7=VfS^XLEI{rBGwY-?)r=sP=KuSh0mx&d+)KsUpr#=YKkf7jlA zPF?Dp!q&=%9_l(ZGE!*_1m;;NC0+oGs*2;G&@C&cP3!pajvZaq)zx2)kB@&>Q5177 zaNz6HW}$gfXvI<#MJg^Xe&+Du!#iJ}JGau%(Xq868eLQlkP!f#0QDCaZ;r27^I}_D z+c{TK=MZRXYf~C;zWKmtB+_IKhf6E~@c>{I#W)d(G%qhHN!&PZ-iL>h$&=x5c&VzY zf<{7H4z=Ymmw=)ug<@Z}+wHG5G&HP#k>{_~ojm!6vRG_kB|t&|x&Yd1vwaqIyVtb5 z`DQF1Ye514@Ws)i(XvI0K8;4B&Bkc7$OsTGK=i6ACMPCtiVh7`U0+r8)-gfY9}0zT zlx10@l#<*LC`2NsQCXJL9*<|k52jCl@wTq62gSa=-&9CaRT)6WkSXDxG?`8$7c98@ zX9o`S7s7d70swIQn{Pf42#2rJ#bS0LLjpwri$r2x((k|fDn%KnTCm`s6ISco z(a}+7I-Ndm2<1L~K40{vxpRO1WGHmn*VD7n6%5{At*S-`K!&qn(`_~%KRsi{_tx** zcfs8JqBk_FZoF|;@#)i>7o9n?pjJ^x?hTC}z_{5g=@&0%dmRpL=ken>+SiBC@$tzy zp^4dO#Ps4~+)`hUs|7)&d-kM_eSMq~&a_!o+`d~-LosRDAr|0_pGpl47-_|YV z03qsWhvUdtMa9pp%a-kIX=%A=z38$DXtM6%hwVcrPCQ=R)3bVdFj!ZSOmcPr-{hWn zkmKYbtMyo*tgKbBTL1WJTU+#U@qFW(`g`uVr-+V@-eUIq@3N1MHWtTXE_*VmH>)ZU zD4irR37!x{387(~E)^2Rp-55DzOd8z2AMmzt+loFvJ1$6F#%1sZQI7~*s;TjV6a|H zB<7Lv@jAUERfs%qV<|OIAQ6j32VpV|Di%w(VluTS%;t{ou3jCy^Ugaj>Av9q<$tsM YCmgQXxMub0=l}o!07*qoM6N<$f>(sn=l}o! literal 0 HcmV?d00001 diff --git a/applications/osmo4_android_studio/app/src/main/res/drawable/ic_back.xml b/applications/osmo4_android_studio/app/src/main/res/drawable/ic_back.xml new file mode 100644 index 0000000..beafea3 --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/drawable/ic_back.xml @@ -0,0 +1,9 @@ + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/layout/about_dialog.xml b/applications/osmo4_android_studio/app/src/main/res/layout/about_dialog.xml new file mode 100644 index 0000000..2518a7b --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/layout/about_dialog.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/osmo4_android_studio/app/src/main/res/layout/activity_config_file_editor.xml b/applications/osmo4_android_studio/app/src/main/res/layout/activity_config_file_editor.xml new file mode 100644 index 0000000..986ddad --- /dev/null +++ b/applications/osmo4_android_studio/app/src/main/res/layout/activity_config_file_editor.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +